sdl_impl.cpp 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  1. // Copyright 2018 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <array>
  6. #include <atomic>
  7. #include <chrono>
  8. #include <cmath>
  9. #include <functional>
  10. #include <mutex>
  11. #include <optional>
  12. #include <sstream>
  13. #include <string>
  14. #include <thread>
  15. #include <tuple>
  16. #include <unordered_map>
  17. #include <utility>
  18. #include <vector>
  19. #include <SDL.h>
  20. #include "common/logging/log.h"
  21. #include "common/param_package.h"
  22. #include "common/threadsafe_queue.h"
  23. #include "core/frontend/input.h"
  24. #include "input_common/motion_input.h"
  25. #include "input_common/sdl/sdl_impl.h"
  26. #include "input_common/settings.h"
  27. namespace InputCommon::SDL {
  28. namespace {
  29. std::string GetGUID(SDL_Joystick* joystick) {
  30. const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  31. char guid_str[33];
  32. SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
  33. return guid_str;
  34. }
  35. /// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice
  36. Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
  37. } // Anonymous namespace
  38. static int SDLEventWatcher(void* user_data, SDL_Event* event) {
  39. auto* const sdl_state = static_cast<SDLState*>(user_data);
  40. // Don't handle the event if we are configuring
  41. if (sdl_state->polling) {
  42. sdl_state->event_queue.Push(*event);
  43. } else {
  44. sdl_state->HandleGameControllerEvent(*event);
  45. }
  46. return 0;
  47. }
  48. class SDLJoystick {
  49. public:
  50. SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
  51. SDL_GameController* game_controller)
  52. : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
  53. sdl_controller{game_controller, &SDL_GameControllerClose} {}
  54. void SetButton(int button, bool value) {
  55. std::lock_guard lock{mutex};
  56. state.buttons.insert_or_assign(button, value);
  57. }
  58. bool GetButton(int button) const {
  59. std::lock_guard lock{mutex};
  60. return state.buttons.at(button);
  61. }
  62. void SetAxis(int axis, Sint16 value) {
  63. std::lock_guard lock{mutex};
  64. state.axes.insert_or_assign(axis, value);
  65. }
  66. float GetAxis(int axis, float range) const {
  67. std::lock_guard lock{mutex};
  68. return static_cast<float>(state.axes.at(axis)) / (32767.0f * range);
  69. }
  70. bool RumblePlay(u16 amp_low, u16 amp_high) {
  71. if (sdl_controller) {
  72. return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, 0) == 0;
  73. } else if (sdl_joystick) {
  74. return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, 0) == 0;
  75. }
  76. return false;
  77. }
  78. std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const {
  79. float x = GetAxis(axis_x, range);
  80. float y = GetAxis(axis_y, range);
  81. y = -y; // 3DS uses an y-axis inverse from SDL
  82. // Make sure the coordinates are in the unit circle,
  83. // otherwise normalize it.
  84. float r = x * x + y * y;
  85. if (r > 1.0f) {
  86. r = std::sqrt(r);
  87. x /= r;
  88. y /= r;
  89. }
  90. return std::make_tuple(x, y);
  91. }
  92. const MotionInput& GetMotion() const {
  93. return motion;
  94. }
  95. void SetHat(int hat, Uint8 direction) {
  96. std::lock_guard lock{mutex};
  97. state.hats.insert_or_assign(hat, direction);
  98. }
  99. bool GetHatDirection(int hat, Uint8 direction) const {
  100. std::lock_guard lock{mutex};
  101. return (state.hats.at(hat) & direction) != 0;
  102. }
  103. /**
  104. * The guid of the joystick
  105. */
  106. const std::string& GetGUID() const {
  107. return guid;
  108. }
  109. /**
  110. * The number of joystick from the same type that were connected before this joystick
  111. */
  112. int GetPort() const {
  113. return port;
  114. }
  115. SDL_Joystick* GetSDLJoystick() const {
  116. return sdl_joystick.get();
  117. }
  118. SDL_GameController* GetSDLGameController() const {
  119. return sdl_controller.get();
  120. }
  121. void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
  122. sdl_joystick.reset(joystick);
  123. sdl_controller.reset(controller);
  124. }
  125. private:
  126. struct State {
  127. std::unordered_map<int, bool> buttons;
  128. std::unordered_map<int, Sint16> axes;
  129. std::unordered_map<int, Uint8> hats;
  130. } state;
  131. std::string guid;
  132. int port;
  133. std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
  134. std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
  135. mutable std::mutex mutex;
  136. // Motion is initialized without PID values as motion input is not aviable for SDL2
  137. MotionInput motion{0.0f, 0.0f, 0.0f};
  138. };
  139. std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
  140. std::lock_guard lock{joystick_map_mutex};
  141. const auto it = joystick_map.find(guid);
  142. if (it != joystick_map.end()) {
  143. while (it->second.size() <= static_cast<std::size_t>(port)) {
  144. auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
  145. nullptr, nullptr);
  146. it->second.emplace_back(std::move(joystick));
  147. }
  148. return it->second[static_cast<std::size_t>(port)];
  149. }
  150. auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
  151. return joystick_map[guid].emplace_back(std::move(joystick));
  152. }
  153. std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
  154. auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
  155. const std::string guid = GetGUID(sdl_joystick);
  156. std::lock_guard lock{joystick_map_mutex};
  157. const auto map_it = joystick_map.find(guid);
  158. if (map_it == joystick_map.end()) {
  159. return nullptr;
  160. }
  161. const auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(),
  162. [&sdl_joystick](const auto& joystick) {
  163. return joystick->GetSDLJoystick() == sdl_joystick;
  164. });
  165. if (vec_it == map_it->second.end()) {
  166. return nullptr;
  167. }
  168. return *vec_it;
  169. }
  170. void SDLState::InitJoystick(int joystick_index) {
  171. SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
  172. SDL_GameController* sdl_gamecontroller = nullptr;
  173. if (SDL_IsGameController(joystick_index)) {
  174. sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
  175. }
  176. if (!sdl_joystick) {
  177. LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
  178. return;
  179. }
  180. const std::string guid = GetGUID(sdl_joystick);
  181. std::lock_guard lock{joystick_map_mutex};
  182. if (joystick_map.find(guid) == joystick_map.end()) {
  183. auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
  184. joystick_map[guid].emplace_back(std::move(joystick));
  185. return;
  186. }
  187. auto& joystick_guid_list = joystick_map[guid];
  188. const auto joystick_it =
  189. std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
  190. [](const auto& joystick) { return !joystick->GetSDLJoystick(); });
  191. if (joystick_it != joystick_guid_list.end()) {
  192. (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
  193. return;
  194. }
  195. const int port = static_cast<int>(joystick_guid_list.size());
  196. auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
  197. joystick_guid_list.emplace_back(std::move(joystick));
  198. }
  199. void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
  200. const std::string guid = GetGUID(sdl_joystick);
  201. std::lock_guard lock{joystick_map_mutex};
  202. // This call to guid is safe since the joystick is guaranteed to be in the map
  203. const auto& joystick_guid_list = joystick_map[guid];
  204. const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
  205. [&sdl_joystick](const auto& joystick) {
  206. return joystick->GetSDLJoystick() == sdl_joystick;
  207. });
  208. (*joystick_it)->SetSDLJoystick(nullptr, nullptr);
  209. }
  210. void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
  211. switch (event.type) {
  212. case SDL_JOYBUTTONUP: {
  213. if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
  214. joystick->SetButton(event.jbutton.button, false);
  215. }
  216. break;
  217. }
  218. case SDL_JOYBUTTONDOWN: {
  219. if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
  220. joystick->SetButton(event.jbutton.button, true);
  221. }
  222. break;
  223. }
  224. case SDL_JOYHATMOTION: {
  225. if (auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) {
  226. joystick->SetHat(event.jhat.hat, event.jhat.value);
  227. }
  228. break;
  229. }
  230. case SDL_JOYAXISMOTION: {
  231. if (auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) {
  232. joystick->SetAxis(event.jaxis.axis, event.jaxis.value);
  233. }
  234. break;
  235. }
  236. case SDL_JOYDEVICEREMOVED:
  237. LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
  238. CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
  239. break;
  240. case SDL_JOYDEVICEADDED:
  241. LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which);
  242. InitJoystick(event.jdevice.which);
  243. break;
  244. }
  245. }
  246. void SDLState::CloseJoysticks() {
  247. std::lock_guard lock{joystick_map_mutex};
  248. joystick_map.clear();
  249. }
  250. class SDLButton final : public Input::ButtonDevice {
  251. public:
  252. explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_)
  253. : joystick(std::move(joystick_)), button(button_) {}
  254. bool GetStatus() const override {
  255. return joystick->GetButton(button);
  256. }
  257. private:
  258. std::shared_ptr<SDLJoystick> joystick;
  259. int button;
  260. };
  261. class SDLDirectionButton final : public Input::ButtonDevice {
  262. public:
  263. explicit SDLDirectionButton(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
  264. : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
  265. bool GetStatus() const override {
  266. return joystick->GetHatDirection(hat, direction);
  267. }
  268. private:
  269. std::shared_ptr<SDLJoystick> joystick;
  270. int hat;
  271. Uint8 direction;
  272. };
  273. class SDLAxisButton final : public Input::ButtonDevice {
  274. public:
  275. explicit SDLAxisButton(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
  276. bool trigger_if_greater_)
  277. : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
  278. trigger_if_greater(trigger_if_greater_) {}
  279. bool GetStatus() const override {
  280. const float axis_value = joystick->GetAxis(axis, 1.0f);
  281. if (trigger_if_greater) {
  282. return axis_value > threshold;
  283. }
  284. return axis_value < threshold;
  285. }
  286. private:
  287. std::shared_ptr<SDLJoystick> joystick;
  288. int axis;
  289. float threshold;
  290. bool trigger_if_greater;
  291. };
  292. class SDLAnalog final : public Input::AnalogDevice {
  293. public:
  294. explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_,
  295. bool invert_x_, bool invert_y_, float deadzone_, float range_)
  296. : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_),
  297. invert_y(invert_y_), deadzone(deadzone_), range(range_) {}
  298. std::tuple<float, float> GetStatus() const override {
  299. auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range);
  300. const float r = std::sqrt((x * x) + (y * y));
  301. if (invert_x) {
  302. x = -x;
  303. }
  304. if (invert_y) {
  305. y = -y;
  306. }
  307. if (r > deadzone) {
  308. return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone),
  309. y / r * (r - deadzone) / (1 - deadzone));
  310. }
  311. return {};
  312. }
  313. bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
  314. const auto [x, y] = GetStatus();
  315. const float directional_deadzone = 0.5f;
  316. switch (direction) {
  317. case Input::AnalogDirection::RIGHT:
  318. return x > directional_deadzone;
  319. case Input::AnalogDirection::LEFT:
  320. return x < -directional_deadzone;
  321. case Input::AnalogDirection::UP:
  322. return y > directional_deadzone;
  323. case Input::AnalogDirection::DOWN:
  324. return y < -directional_deadzone;
  325. }
  326. return false;
  327. }
  328. private:
  329. std::shared_ptr<SDLJoystick> joystick;
  330. const int axis_x;
  331. const int axis_y;
  332. const bool invert_x;
  333. const bool invert_y;
  334. const float deadzone;
  335. const float range;
  336. };
  337. class SDLVibration final : public Input::VibrationDevice {
  338. public:
  339. explicit SDLVibration(std::shared_ptr<SDLJoystick> joystick_)
  340. : joystick(std::move(joystick_)) {}
  341. u8 GetStatus() const override {
  342. joystick->RumblePlay(1, 1);
  343. return joystick->RumblePlay(0, 0);
  344. }
  345. bool SetRumblePlay(f32 amp_low, [[maybe_unused]] f32 freq_low, f32 amp_high,
  346. [[maybe_unused]] f32 freq_high) const override {
  347. const auto process_amplitude = [](f32 amplitude) {
  348. return static_cast<u16>((amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF);
  349. };
  350. const auto processed_amp_low = process_amplitude(amp_low);
  351. const auto processed_amp_high = process_amplitude(amp_high);
  352. return joystick->RumblePlay(processed_amp_low, processed_amp_high);
  353. }
  354. private:
  355. std::shared_ptr<SDLJoystick> joystick;
  356. };
  357. class SDLDirectionMotion final : public Input::MotionDevice {
  358. public:
  359. explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
  360. : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
  361. Input::MotionStatus GetStatus() const override {
  362. if (joystick->GetHatDirection(hat, direction)) {
  363. return joystick->GetMotion().GetRandomMotion(2, 6);
  364. }
  365. return joystick->GetMotion().GetRandomMotion(0, 0);
  366. }
  367. private:
  368. std::shared_ptr<SDLJoystick> joystick;
  369. int hat;
  370. Uint8 direction;
  371. };
  372. class SDLAxisMotion final : public Input::MotionDevice {
  373. public:
  374. explicit SDLAxisMotion(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
  375. bool trigger_if_greater_)
  376. : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
  377. trigger_if_greater(trigger_if_greater_) {}
  378. Input::MotionStatus GetStatus() const override {
  379. const float axis_value = joystick->GetAxis(axis, 1.0f);
  380. bool trigger = axis_value < threshold;
  381. if (trigger_if_greater) {
  382. trigger = axis_value > threshold;
  383. }
  384. if (trigger) {
  385. return joystick->GetMotion().GetRandomMotion(2, 6);
  386. }
  387. return joystick->GetMotion().GetRandomMotion(0, 0);
  388. }
  389. private:
  390. std::shared_ptr<SDLJoystick> joystick;
  391. int axis;
  392. float threshold;
  393. bool trigger_if_greater;
  394. };
  395. class SDLButtonMotion final : public Input::MotionDevice {
  396. public:
  397. explicit SDLButtonMotion(std::shared_ptr<SDLJoystick> joystick_, int button_)
  398. : joystick(std::move(joystick_)), button(button_) {}
  399. Input::MotionStatus GetStatus() const override {
  400. if (joystick->GetButton(button)) {
  401. return joystick->GetMotion().GetRandomMotion(2, 6);
  402. }
  403. return joystick->GetMotion().GetRandomMotion(0, 0);
  404. }
  405. private:
  406. std::shared_ptr<SDLJoystick> joystick;
  407. int button;
  408. };
  409. /// A button device factory that creates button devices from SDL joystick
  410. class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
  411. public:
  412. explicit SDLButtonFactory(SDLState& state_) : state(state_) {}
  413. /**
  414. * Creates a button device from a joystick button
  415. * @param params contains parameters for creating the device:
  416. * - "guid": the guid of the joystick to bind
  417. * - "port": the nth joystick of the same type to bind
  418. * - "button"(optional): the index of the button to bind
  419. * - "hat"(optional): the index of the hat to bind as direction buttons
  420. * - "axis"(optional): the index of the axis to bind
  421. * - "direction"(only used for hat): the direction name of the hat to bind. Can be "up",
  422. * "down", "left" or "right"
  423. * - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is
  424. * triggered if the axis value crosses
  425. * - "direction"(only used for axis): "+" means the button is triggered when the axis
  426. * value is greater than the threshold; "-" means the button is triggered when the axis
  427. * value is smaller than the threshold
  428. */
  429. std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override {
  430. const std::string guid = params.Get("guid", "0");
  431. const int port = params.Get("port", 0);
  432. auto joystick = state.GetSDLJoystickByGUID(guid, port);
  433. if (params.Has("hat")) {
  434. const int hat = params.Get("hat", 0);
  435. const std::string direction_name = params.Get("direction", "");
  436. Uint8 direction;
  437. if (direction_name == "up") {
  438. direction = SDL_HAT_UP;
  439. } else if (direction_name == "down") {
  440. direction = SDL_HAT_DOWN;
  441. } else if (direction_name == "left") {
  442. direction = SDL_HAT_LEFT;
  443. } else if (direction_name == "right") {
  444. direction = SDL_HAT_RIGHT;
  445. } else {
  446. direction = 0;
  447. }
  448. // This is necessary so accessing GetHat with hat won't crash
  449. joystick->SetHat(hat, SDL_HAT_CENTERED);
  450. return std::make_unique<SDLDirectionButton>(joystick, hat, direction);
  451. }
  452. if (params.Has("axis")) {
  453. const int axis = params.Get("axis", 0);
  454. const float threshold = params.Get("threshold", 0.5f);
  455. const std::string direction_name = params.Get("direction", "");
  456. bool trigger_if_greater;
  457. if (direction_name == "+") {
  458. trigger_if_greater = true;
  459. } else if (direction_name == "-") {
  460. trigger_if_greater = false;
  461. } else {
  462. trigger_if_greater = true;
  463. LOG_ERROR(Input, "Unknown direction {}", direction_name);
  464. }
  465. // This is necessary so accessing GetAxis with axis won't crash
  466. joystick->SetAxis(axis, 0);
  467. return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater);
  468. }
  469. const int button = params.Get("button", 0);
  470. // This is necessary so accessing GetButton with button won't crash
  471. joystick->SetButton(button, false);
  472. return std::make_unique<SDLButton>(joystick, button);
  473. }
  474. private:
  475. SDLState& state;
  476. };
  477. /// An analog device factory that creates analog devices from SDL joystick
  478. class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> {
  479. public:
  480. explicit SDLAnalogFactory(SDLState& state_) : state(state_) {}
  481. /**
  482. * Creates an analog device from joystick axes
  483. * @param params contains parameters for creating the device:
  484. * - "guid": the guid of the joystick to bind
  485. * - "port": the nth joystick of the same type
  486. * - "axis_x": the index of the axis to be bind as x-axis
  487. * - "axis_y": the index of the axis to be bind as y-axis
  488. */
  489. std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override {
  490. const std::string guid = params.Get("guid", "0");
  491. const int port = params.Get("port", 0);
  492. const int axis_x = params.Get("axis_x", 0);
  493. const int axis_y = params.Get("axis_y", 1);
  494. const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
  495. const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
  496. const std::string invert_x_value = params.Get("invert_x", "+");
  497. const std::string invert_y_value = params.Get("invert_y", "+");
  498. const bool invert_x = invert_x_value == "-";
  499. const bool invert_y = invert_y_value == "-";
  500. auto joystick = state.GetSDLJoystickByGUID(guid, port);
  501. // This is necessary so accessing GetAxis with axis_x and axis_y won't crash
  502. joystick->SetAxis(axis_x, 0);
  503. joystick->SetAxis(axis_y, 0);
  504. return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, invert_x, invert_y, deadzone,
  505. range);
  506. }
  507. private:
  508. SDLState& state;
  509. };
  510. /// An vibration device factory that creates vibration devices from SDL joystick
  511. class SDLVibrationFactory final : public Input::Factory<Input::VibrationDevice> {
  512. public:
  513. explicit SDLVibrationFactory(SDLState& state_) : state(state_) {}
  514. /**
  515. * Creates a vibration device from a joystick
  516. * @param params contains parameters for creating the device:
  517. * - "guid": the guid of the joystick to bind
  518. * - "port": the nth joystick of the same type
  519. */
  520. std::unique_ptr<Input::VibrationDevice> Create(const Common::ParamPackage& params) override {
  521. const std::string guid = params.Get("guid", "0");
  522. const int port = params.Get("port", 0);
  523. return std::make_unique<SDLVibration>(state.GetSDLJoystickByGUID(guid, port));
  524. }
  525. private:
  526. SDLState& state;
  527. };
  528. /// A motion device factory that creates motion devices from SDL joystick
  529. class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> {
  530. public:
  531. explicit SDLMotionFactory(SDLState& state_) : state(state_) {}
  532. /**
  533. * Creates motion device from joystick axes
  534. * @param params contains parameters for creating the device:
  535. * - "guid": the guid of the joystick to bind
  536. * - "port": the nth joystick of the same type
  537. */
  538. std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override {
  539. const std::string guid = params.Get("guid", "0");
  540. const int port = params.Get("port", 0);
  541. auto joystick = state.GetSDLJoystickByGUID(guid, port);
  542. if (params.Has("hat")) {
  543. const int hat = params.Get("hat", 0);
  544. const std::string direction_name = params.Get("direction", "");
  545. Uint8 direction;
  546. if (direction_name == "up") {
  547. direction = SDL_HAT_UP;
  548. } else if (direction_name == "down") {
  549. direction = SDL_HAT_DOWN;
  550. } else if (direction_name == "left") {
  551. direction = SDL_HAT_LEFT;
  552. } else if (direction_name == "right") {
  553. direction = SDL_HAT_RIGHT;
  554. } else {
  555. direction = 0;
  556. }
  557. // This is necessary so accessing GetHat with hat won't crash
  558. joystick->SetHat(hat, SDL_HAT_CENTERED);
  559. return std::make_unique<SDLDirectionMotion>(joystick, hat, direction);
  560. }
  561. if (params.Has("axis")) {
  562. const int axis = params.Get("axis", 0);
  563. const float threshold = params.Get("threshold", 0.5f);
  564. const std::string direction_name = params.Get("direction", "");
  565. bool trigger_if_greater;
  566. if (direction_name == "+") {
  567. trigger_if_greater = true;
  568. } else if (direction_name == "-") {
  569. trigger_if_greater = false;
  570. } else {
  571. trigger_if_greater = true;
  572. LOG_ERROR(Input, "Unknown direction {}", direction_name);
  573. }
  574. // This is necessary so accessing GetAxis with axis won't crash
  575. joystick->SetAxis(axis, 0);
  576. return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater);
  577. }
  578. const int button = params.Get("button", 0);
  579. // This is necessary so accessing GetButton with button won't crash
  580. joystick->SetButton(button, false);
  581. return std::make_unique<SDLButtonMotion>(joystick, button);
  582. }
  583. private:
  584. SDLState& state;
  585. };
  586. SDLState::SDLState() {
  587. using namespace Input;
  588. button_factory = std::make_shared<SDLButtonFactory>(*this);
  589. analog_factory = std::make_shared<SDLAnalogFactory>(*this);
  590. vibration_factory = std::make_shared<SDLVibrationFactory>(*this);
  591. motion_factory = std::make_shared<SDLMotionFactory>(*this);
  592. RegisterFactory<ButtonDevice>("sdl", button_factory);
  593. RegisterFactory<AnalogDevice>("sdl", analog_factory);
  594. RegisterFactory<VibrationDevice>("sdl", vibration_factory);
  595. RegisterFactory<MotionDevice>("sdl", motion_factory);
  596. // If the frontend is going to manage the event loop, then we don't start one here
  597. start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0;
  598. if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) {
  599. LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
  600. return;
  601. }
  602. has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0;
  603. if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
  604. LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
  605. }
  606. SDL_AddEventWatch(&SDLEventWatcher, this);
  607. initialized = true;
  608. if (start_thread) {
  609. poll_thread = std::thread([this] {
  610. using namespace std::chrono_literals;
  611. while (initialized) {
  612. SDL_PumpEvents();
  613. std::this_thread::sleep_for(1ms);
  614. }
  615. });
  616. }
  617. // Because the events for joystick connection happens before we have our event watcher added, we
  618. // can just open all the joysticks right here
  619. for (int i = 0; i < SDL_NumJoysticks(); ++i) {
  620. InitJoystick(i);
  621. }
  622. }
  623. SDLState::~SDLState() {
  624. using namespace Input;
  625. UnregisterFactory<ButtonDevice>("sdl");
  626. UnregisterFactory<AnalogDevice>("sdl");
  627. UnregisterFactory<VibrationDevice>("sdl");
  628. UnregisterFactory<MotionDevice>("sdl");
  629. CloseJoysticks();
  630. SDL_DelEventWatch(&SDLEventWatcher, this);
  631. initialized = false;
  632. if (start_thread) {
  633. poll_thread.join();
  634. SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
  635. }
  636. }
  637. std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
  638. std::scoped_lock lock(joystick_map_mutex);
  639. std::vector<Common::ParamPackage> devices;
  640. for (const auto& [key, value] : joystick_map) {
  641. for (const auto& joystick : value) {
  642. if (auto* const controller = joystick->GetSDLGameController()) {
  643. std::string name =
  644. fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
  645. devices.emplace_back(Common::ParamPackage{
  646. {"class", "sdl"},
  647. {"display", std::move(name)},
  648. {"guid", joystick->GetGUID()},
  649. {"port", std::to_string(joystick->GetPort())},
  650. });
  651. } else if (auto* const joy = joystick->GetSDLJoystick()) {
  652. std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort());
  653. devices.emplace_back(Common::ParamPackage{
  654. {"class", "sdl"},
  655. {"display", std::move(name)},
  656. {"guid", joystick->GetGUID()},
  657. {"port", std::to_string(joystick->GetPort())},
  658. });
  659. }
  660. }
  661. }
  662. return devices;
  663. }
  664. namespace {
  665. Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis,
  666. float value = 0.1f) {
  667. Common::ParamPackage params({{"engine", "sdl"}});
  668. params.Set("port", port);
  669. params.Set("guid", std::move(guid));
  670. params.Set("axis", axis);
  671. if (value > 0) {
  672. params.Set("direction", "+");
  673. params.Set("threshold", "0.5");
  674. } else {
  675. params.Set("direction", "-");
  676. params.Set("threshold", "-0.5");
  677. }
  678. return params;
  679. }
  680. Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, s32 button) {
  681. Common::ParamPackage params({{"engine", "sdl"}});
  682. params.Set("port", port);
  683. params.Set("guid", std::move(guid));
  684. params.Set("button", button);
  685. return params;
  686. }
  687. Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat, s32 value) {
  688. Common::ParamPackage params({{"engine", "sdl"}});
  689. params.Set("port", port);
  690. params.Set("guid", std::move(guid));
  691. params.Set("hat", hat);
  692. switch (value) {
  693. case SDL_HAT_UP:
  694. params.Set("direction", "up");
  695. break;
  696. case SDL_HAT_DOWN:
  697. params.Set("direction", "down");
  698. break;
  699. case SDL_HAT_LEFT:
  700. params.Set("direction", "left");
  701. break;
  702. case SDL_HAT_RIGHT:
  703. params.Set("direction", "right");
  704. break;
  705. default:
  706. return {};
  707. }
  708. return params;
  709. }
  710. Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
  711. switch (event.type) {
  712. case SDL_JOYAXISMOTION: {
  713. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
  714. return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  715. static_cast<s32>(event.jaxis.axis),
  716. event.jaxis.value);
  717. }
  718. break;
  719. }
  720. case SDL_JOYBUTTONUP: {
  721. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) {
  722. return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  723. static_cast<s32>(event.jbutton.button));
  724. }
  725. break;
  726. }
  727. case SDL_JOYHATMOTION: {
  728. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) {
  729. return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  730. static_cast<s32>(event.jhat.hat),
  731. static_cast<s32>(event.jhat.value));
  732. }
  733. break;
  734. }
  735. }
  736. return {};
  737. }
  738. Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) {
  739. switch (event.type) {
  740. case SDL_JOYAXISMOTION: {
  741. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
  742. return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  743. static_cast<s32>(event.jaxis.axis),
  744. event.jaxis.value);
  745. }
  746. break;
  747. }
  748. case SDL_JOYBUTTONUP: {
  749. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) {
  750. return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  751. static_cast<s32>(event.jbutton.button));
  752. }
  753. break;
  754. }
  755. case SDL_JOYHATMOTION: {
  756. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) {
  757. return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  758. static_cast<s32>(event.jhat.hat),
  759. static_cast<s32>(event.jhat.value));
  760. }
  761. break;
  762. }
  763. }
  764. return {};
  765. }
  766. Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
  767. const SDL_GameControllerButtonBind& binding) {
  768. switch (binding.bindType) {
  769. case SDL_CONTROLLER_BINDTYPE_NONE:
  770. break;
  771. case SDL_CONTROLLER_BINDTYPE_AXIS:
  772. return BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
  773. case SDL_CONTROLLER_BINDTYPE_BUTTON:
  774. return BuildButtonParamPackageForButton(port, guid, binding.value.button);
  775. case SDL_CONTROLLER_BINDTYPE_HAT:
  776. return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
  777. binding.value.hat.hat_mask);
  778. }
  779. return {};
  780. }
  781. Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x,
  782. int axis_y) {
  783. Common::ParamPackage params;
  784. params.Set("engine", "sdl");
  785. params.Set("port", port);
  786. params.Set("guid", guid);
  787. params.Set("axis_x", axis_x);
  788. params.Set("axis_y", axis_y);
  789. params.Set("invert_x", "+");
  790. params.Set("invert_y", "+");
  791. return params;
  792. }
  793. } // Anonymous namespace
  794. ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) {
  795. if (!params.Has("guid") || !params.Has("port")) {
  796. return {};
  797. }
  798. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  799. auto* controller = joystick->GetSDLGameController();
  800. if (controller == nullptr) {
  801. return {};
  802. }
  803. // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
  804. // We will add those afterwards
  805. // This list also excludes Screenshot since theres not really a mapping for that
  806. using ButtonBindings =
  807. std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
  808. static constexpr ButtonBindings switch_to_sdl_button{{
  809. {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
  810. {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
  811. {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
  812. {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
  813. {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
  814. {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
  815. {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  816. {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  817. {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
  818. {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
  819. {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
  820. {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
  821. {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
  822. {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
  823. {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  824. {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  825. {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
  826. }};
  827. // Add the missing bindings for ZL/ZR
  828. using ZBindings =
  829. std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
  830. static constexpr ZBindings switch_to_sdl_axis{{
  831. {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
  832. {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
  833. }};
  834. ButtonMapping mapping;
  835. mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
  836. for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
  837. const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
  838. mapping.insert_or_assign(
  839. switch_button,
  840. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  841. }
  842. for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
  843. const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
  844. mapping.insert_or_assign(
  845. switch_button,
  846. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  847. }
  848. return mapping;
  849. }
  850. AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
  851. if (!params.Has("guid") || !params.Has("port")) {
  852. return {};
  853. }
  854. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  855. auto* controller = joystick->GetSDLGameController();
  856. if (controller == nullptr) {
  857. return {};
  858. }
  859. AnalogMapping mapping = {};
  860. const auto& binding_left_x =
  861. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
  862. const auto& binding_left_y =
  863. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
  864. mapping.insert_or_assign(Settings::NativeAnalog::LStick,
  865. BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
  866. binding_left_x.value.axis,
  867. binding_left_y.value.axis));
  868. const auto& binding_right_x =
  869. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
  870. const auto& binding_right_y =
  871. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
  872. mapping.insert_or_assign(Settings::NativeAnalog::RStick,
  873. BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
  874. binding_right_x.value.axis,
  875. binding_right_y.value.axis));
  876. return mapping;
  877. }
  878. namespace Polling {
  879. class SDLPoller : public InputCommon::Polling::DevicePoller {
  880. public:
  881. explicit SDLPoller(SDLState& state_) : state(state_) {}
  882. void Start([[maybe_unused]] const std::string& device_id) override {
  883. state.event_queue.Clear();
  884. state.polling = true;
  885. }
  886. void Stop() override {
  887. state.polling = false;
  888. }
  889. protected:
  890. SDLState& state;
  891. };
  892. class SDLButtonPoller final : public SDLPoller {
  893. public:
  894. explicit SDLButtonPoller(SDLState& state_) : SDLPoller(state_) {}
  895. Common::ParamPackage GetNextInput() override {
  896. SDL_Event event;
  897. while (state.event_queue.Pop(event)) {
  898. const auto package = FromEvent(event);
  899. if (package) {
  900. return *package;
  901. }
  902. }
  903. return {};
  904. }
  905. [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
  906. switch (event.type) {
  907. case SDL_JOYAXISMOTION:
  908. if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
  909. break;
  910. }
  911. [[fallthrough]];
  912. case SDL_JOYBUTTONUP:
  913. case SDL_JOYHATMOTION:
  914. return {SDLEventToButtonParamPackage(state, event)};
  915. }
  916. return std::nullopt;
  917. }
  918. };
  919. class SDLMotionPoller final : public SDLPoller {
  920. public:
  921. explicit SDLMotionPoller(SDLState& state_) : SDLPoller(state_) {}
  922. Common::ParamPackage GetNextInput() override {
  923. SDL_Event event;
  924. while (state.event_queue.Pop(event)) {
  925. const auto package = FromEvent(event);
  926. if (package) {
  927. return *package;
  928. }
  929. }
  930. return {};
  931. }
  932. [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
  933. switch (event.type) {
  934. case SDL_JOYAXISMOTION:
  935. if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
  936. break;
  937. }
  938. [[fallthrough]];
  939. case SDL_JOYBUTTONUP:
  940. case SDL_JOYHATMOTION:
  941. return {SDLEventToMotionParamPackage(state, event)};
  942. }
  943. return std::nullopt;
  944. }
  945. };
  946. /**
  947. * Attempts to match the press to a controller joy axis (left/right stick) and if a match
  948. * isn't found, checks if the event matches anything from SDLButtonPoller and uses that
  949. * instead
  950. */
  951. class SDLAnalogPreferredPoller final : public SDLPoller {
  952. public:
  953. explicit SDLAnalogPreferredPoller(SDLState& state_)
  954. : SDLPoller(state_), button_poller(state_) {}
  955. void Start(const std::string& device_id) override {
  956. SDLPoller::Start(device_id);
  957. // Reset stored axes
  958. analog_x_axis = -1;
  959. analog_y_axis = -1;
  960. }
  961. Common::ParamPackage GetNextInput() override {
  962. SDL_Event event;
  963. while (state.event_queue.Pop(event)) {
  964. // Filter out axis events that are below a threshold
  965. if (event.type == SDL_JOYAXISMOTION && std::abs(event.jaxis.value / 32767.0) < 0.5) {
  966. continue;
  967. }
  968. if (event.type == SDL_JOYAXISMOTION) {
  969. const auto axis = event.jaxis.axis;
  970. // In order to return a complete analog param, we need inputs for both axes.
  971. // First we take the x-axis (horizontal) input, then the y-axis (vertical) input.
  972. if (analog_x_axis == -1) {
  973. analog_x_axis = axis;
  974. } else if (analog_y_axis == -1 && analog_x_axis != axis) {
  975. analog_y_axis = axis;
  976. }
  977. } else {
  978. // If the press wasn't accepted as a joy axis, check for a button press
  979. auto button_press = button_poller.FromEvent(event);
  980. if (button_press) {
  981. return *button_press;
  982. }
  983. }
  984. }
  985. if (analog_x_axis != -1 && analog_y_axis != -1) {
  986. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
  987. auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
  988. analog_x_axis, analog_y_axis);
  989. analog_x_axis = -1;
  990. analog_y_axis = -1;
  991. return params;
  992. }
  993. }
  994. return {};
  995. }
  996. private:
  997. int analog_x_axis = -1;
  998. int analog_y_axis = -1;
  999. SDLButtonPoller button_poller;
  1000. };
  1001. } // namespace Polling
  1002. SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
  1003. Pollers pollers;
  1004. switch (type) {
  1005. case InputCommon::Polling::DeviceType::AnalogPreferred:
  1006. pollers.emplace_back(std::make_unique<Polling::SDLAnalogPreferredPoller>(*this));
  1007. break;
  1008. case InputCommon::Polling::DeviceType::Button:
  1009. pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
  1010. break;
  1011. case InputCommon::Polling::DeviceType::Motion:
  1012. pollers.emplace_back(std::make_unique<Polling::SDLMotionPoller>(*this));
  1013. break;
  1014. }
  1015. return pollers;
  1016. }
  1017. } // namespace InputCommon::SDL