sdl_impl.cpp 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657
  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 "common/logging/log.h"
  20. #include "common/math_util.h"
  21. #include "common/param_package.h"
  22. #include "common/settings.h"
  23. #include "common/threadsafe_queue.h"
  24. #include "core/frontend/input.h"
  25. #include "input_common/motion_input.h"
  26. #include "input_common/sdl/sdl_impl.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. EnableMotion();
  55. }
  56. void EnableMotion() {
  57. if (sdl_controller) {
  58. SDL_GameController* controller = sdl_controller.get();
  59. if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) {
  60. SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
  61. has_accel = true;
  62. }
  63. if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) {
  64. SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE);
  65. has_gyro = true;
  66. }
  67. }
  68. }
  69. void SetButton(int button, bool value) {
  70. std::lock_guard lock{mutex};
  71. state.buttons.insert_or_assign(button, value);
  72. }
  73. void PreSetButton(int button) {
  74. if (!state.buttons.contains(button)) {
  75. SetButton(button, false);
  76. }
  77. }
  78. void SetMotion(SDL_ControllerSensorEvent event) {
  79. constexpr float gravity_constant = 9.80665f;
  80. std::lock_guard lock{mutex};
  81. u64 time_difference = event.timestamp - last_motion_update;
  82. last_motion_update = event.timestamp;
  83. switch (event.sensor) {
  84. case SDL_SENSOR_ACCEL: {
  85. const Common::Vec3f acceleration = {-event.data[0], event.data[2], -event.data[1]};
  86. motion.SetAcceleration(acceleration / gravity_constant);
  87. break;
  88. }
  89. case SDL_SENSOR_GYRO: {
  90. const Common::Vec3f gyroscope = {event.data[0], -event.data[2], event.data[1]};
  91. motion.SetGyroscope(gyroscope / (Common::PI * 2));
  92. break;
  93. }
  94. }
  95. // Ignore duplicated timestamps
  96. if (time_difference == 0) {
  97. return;
  98. }
  99. motion.SetGyroThreshold(0.0001f);
  100. motion.UpdateRotation(time_difference * 1000);
  101. motion.UpdateOrientation(time_difference * 1000);
  102. }
  103. bool GetButton(int button) const {
  104. std::lock_guard lock{mutex};
  105. return state.buttons.at(button);
  106. }
  107. bool ToggleButton(int button) {
  108. std::lock_guard lock{mutex};
  109. if (!state.toggle_buttons.contains(button) || !state.lock_buttons.contains(button)) {
  110. state.toggle_buttons.insert_or_assign(button, false);
  111. state.lock_buttons.insert_or_assign(button, false);
  112. }
  113. const bool button_state = state.toggle_buttons.at(button);
  114. const bool button_lock = state.lock_buttons.at(button);
  115. if (button_lock) {
  116. return button_state;
  117. }
  118. state.lock_buttons.insert_or_assign(button, true);
  119. if (button_state) {
  120. state.toggle_buttons.insert_or_assign(button, false);
  121. } else {
  122. state.toggle_buttons.insert_or_assign(button, true);
  123. }
  124. return !button_state;
  125. }
  126. bool UnlockButton(int button) {
  127. std::lock_guard lock{mutex};
  128. if (!state.toggle_buttons.contains(button)) {
  129. return false;
  130. }
  131. state.lock_buttons.insert_or_assign(button, false);
  132. return state.toggle_buttons.at(button);
  133. }
  134. void SetAxis(int axis, Sint16 value) {
  135. std::lock_guard lock{mutex};
  136. state.axes.insert_or_assign(axis, value);
  137. }
  138. void PreSetAxis(int axis) {
  139. if (!state.axes.contains(axis)) {
  140. SetAxis(axis, 0);
  141. }
  142. }
  143. float GetAxis(int axis, float range, float offset) const {
  144. std::lock_guard lock{mutex};
  145. const float value = static_cast<float>(state.axes.at(axis)) / 32767.0f;
  146. return (value + offset) / range;
  147. }
  148. bool RumblePlay(u16 amp_low, u16 amp_high) {
  149. constexpr u32 rumble_max_duration_ms = 1000;
  150. if (sdl_controller) {
  151. return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high,
  152. rumble_max_duration_ms) != -1;
  153. } else if (sdl_joystick) {
  154. return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high,
  155. rumble_max_duration_ms) != -1;
  156. }
  157. return false;
  158. }
  159. std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range, float offset_x,
  160. float offset_y) const {
  161. float x = GetAxis(axis_x, range, offset_x);
  162. float y = GetAxis(axis_y, range, offset_y);
  163. y = -y; // 3DS uses an y-axis inverse from SDL
  164. // Make sure the coordinates are in the unit circle,
  165. // otherwise normalize it.
  166. float r = x * x + y * y;
  167. if (r > 1.0f) {
  168. r = std::sqrt(r);
  169. x /= r;
  170. y /= r;
  171. }
  172. return std::make_tuple(x, y);
  173. }
  174. bool HasGyro() const {
  175. return has_gyro;
  176. }
  177. bool HasAccel() const {
  178. return has_accel;
  179. }
  180. const MotionInput& GetMotion() const {
  181. return motion;
  182. }
  183. void SetHat(int hat, Uint8 direction) {
  184. std::lock_guard lock{mutex};
  185. state.hats.insert_or_assign(hat, direction);
  186. }
  187. bool GetHatDirection(int hat, Uint8 direction) const {
  188. std::lock_guard lock{mutex};
  189. return (state.hats.at(hat) & direction) != 0;
  190. }
  191. /**
  192. * The guid of the joystick
  193. */
  194. const std::string& GetGUID() const {
  195. return guid;
  196. }
  197. /**
  198. * The number of joystick from the same type that were connected before this joystick
  199. */
  200. int GetPort() const {
  201. return port;
  202. }
  203. SDL_Joystick* GetSDLJoystick() const {
  204. return sdl_joystick.get();
  205. }
  206. SDL_GameController* GetSDLGameController() const {
  207. return sdl_controller.get();
  208. }
  209. void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
  210. sdl_joystick.reset(joystick);
  211. sdl_controller.reset(controller);
  212. }
  213. bool IsJoyconLeft() const {
  214. const std::string controller_name = GetControllerName();
  215. if (std::strstr(controller_name.c_str(), "Joy-Con Left") != nullptr) {
  216. return true;
  217. }
  218. if (std::strstr(controller_name.c_str(), "Joy-Con (L)") != nullptr) {
  219. return true;
  220. }
  221. return false;
  222. }
  223. bool IsJoyconRight() const {
  224. const std::string controller_name = GetControllerName();
  225. if (std::strstr(controller_name.c_str(), "Joy-Con Right") != nullptr) {
  226. return true;
  227. }
  228. if (std::strstr(controller_name.c_str(), "Joy-Con (R)") != nullptr) {
  229. return true;
  230. }
  231. return false;
  232. }
  233. std::string GetControllerName() const {
  234. if (sdl_controller) {
  235. switch (SDL_GameControllerGetType(sdl_controller.get())) {
  236. case SDL_CONTROLLER_TYPE_XBOX360:
  237. return "XBox 360 Controller";
  238. case SDL_CONTROLLER_TYPE_XBOXONE:
  239. return "XBox One Controller";
  240. default:
  241. break;
  242. }
  243. const auto name = SDL_GameControllerName(sdl_controller.get());
  244. if (name) {
  245. return name;
  246. }
  247. }
  248. if (sdl_joystick) {
  249. const auto name = SDL_JoystickName(sdl_joystick.get());
  250. if (name) {
  251. return name;
  252. }
  253. }
  254. return "Unknown";
  255. }
  256. private:
  257. struct State {
  258. std::unordered_map<int, bool> buttons;
  259. std::unordered_map<int, bool> toggle_buttons{};
  260. std::unordered_map<int, bool> lock_buttons{};
  261. std::unordered_map<int, Sint16> axes;
  262. std::unordered_map<int, Uint8> hats;
  263. } state;
  264. std::string guid;
  265. int port;
  266. std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
  267. std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
  268. mutable std::mutex mutex;
  269. // Motion is initialized with the PID values
  270. MotionInput motion{0.3f, 0.005f, 0.0f};
  271. u64 last_motion_update{};
  272. bool has_gyro{false};
  273. bool has_accel{false};
  274. };
  275. std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
  276. std::lock_guard lock{joystick_map_mutex};
  277. const auto it = joystick_map.find(guid);
  278. if (it != joystick_map.end()) {
  279. while (it->second.size() <= static_cast<std::size_t>(port)) {
  280. auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
  281. nullptr, nullptr);
  282. it->second.emplace_back(std::move(joystick));
  283. }
  284. return it->second[static_cast<std::size_t>(port)];
  285. }
  286. auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
  287. return joystick_map[guid].emplace_back(std::move(joystick));
  288. }
  289. std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
  290. auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
  291. const std::string guid = GetGUID(sdl_joystick);
  292. std::lock_guard lock{joystick_map_mutex};
  293. const auto map_it = joystick_map.find(guid);
  294. if (map_it == joystick_map.end()) {
  295. return nullptr;
  296. }
  297. const auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(),
  298. [&sdl_joystick](const auto& joystick) {
  299. return joystick->GetSDLJoystick() == sdl_joystick;
  300. });
  301. if (vec_it == map_it->second.end()) {
  302. return nullptr;
  303. }
  304. return *vec_it;
  305. }
  306. void SDLState::InitJoystick(int joystick_index) {
  307. SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
  308. SDL_GameController* sdl_gamecontroller = nullptr;
  309. if (SDL_IsGameController(joystick_index)) {
  310. sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
  311. }
  312. if (!sdl_joystick) {
  313. LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
  314. return;
  315. }
  316. const std::string guid = GetGUID(sdl_joystick);
  317. std::lock_guard lock{joystick_map_mutex};
  318. if (joystick_map.find(guid) == joystick_map.end()) {
  319. auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
  320. joystick_map[guid].emplace_back(std::move(joystick));
  321. return;
  322. }
  323. auto& joystick_guid_list = joystick_map[guid];
  324. const auto joystick_it =
  325. std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
  326. [](const auto& joystick) { return !joystick->GetSDLJoystick(); });
  327. if (joystick_it != joystick_guid_list.end()) {
  328. (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
  329. return;
  330. }
  331. const int port = static_cast<int>(joystick_guid_list.size());
  332. auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
  333. joystick_guid_list.emplace_back(std::move(joystick));
  334. }
  335. void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
  336. const std::string guid = GetGUID(sdl_joystick);
  337. std::lock_guard lock{joystick_map_mutex};
  338. // This call to guid is safe since the joystick is guaranteed to be in the map
  339. const auto& joystick_guid_list = joystick_map[guid];
  340. const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
  341. [&sdl_joystick](const auto& joystick) {
  342. return joystick->GetSDLJoystick() == sdl_joystick;
  343. });
  344. if (joystick_it != joystick_guid_list.end()) {
  345. (*joystick_it)->SetSDLJoystick(nullptr, nullptr);
  346. }
  347. }
  348. void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
  349. switch (event.type) {
  350. case SDL_JOYBUTTONUP: {
  351. if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
  352. joystick->SetButton(event.jbutton.button, false);
  353. }
  354. break;
  355. }
  356. case SDL_JOYBUTTONDOWN: {
  357. if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
  358. joystick->SetButton(event.jbutton.button, true);
  359. }
  360. break;
  361. }
  362. case SDL_JOYHATMOTION: {
  363. if (auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) {
  364. joystick->SetHat(event.jhat.hat, event.jhat.value);
  365. }
  366. break;
  367. }
  368. case SDL_JOYAXISMOTION: {
  369. if (auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) {
  370. joystick->SetAxis(event.jaxis.axis, event.jaxis.value);
  371. }
  372. break;
  373. }
  374. case SDL_CONTROLLERSENSORUPDATE: {
  375. if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) {
  376. joystick->SetMotion(event.csensor);
  377. }
  378. break;
  379. }
  380. case SDL_JOYDEVICEREMOVED:
  381. LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
  382. CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
  383. break;
  384. case SDL_JOYDEVICEADDED:
  385. LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which);
  386. InitJoystick(event.jdevice.which);
  387. break;
  388. }
  389. }
  390. void SDLState::CloseJoysticks() {
  391. std::lock_guard lock{joystick_map_mutex};
  392. joystick_map.clear();
  393. }
  394. class SDLButton final : public Input::ButtonDevice {
  395. public:
  396. explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_, bool toggle_)
  397. : joystick(std::move(joystick_)), button(button_), toggle(toggle_) {}
  398. bool GetStatus() const override {
  399. const bool button_state = joystick->GetButton(button);
  400. if (!toggle) {
  401. return button_state;
  402. }
  403. if (button_state) {
  404. return joystick->ToggleButton(button);
  405. }
  406. return joystick->UnlockButton(button);
  407. }
  408. private:
  409. std::shared_ptr<SDLJoystick> joystick;
  410. int button;
  411. bool toggle;
  412. };
  413. class SDLDirectionButton final : public Input::ButtonDevice {
  414. public:
  415. explicit SDLDirectionButton(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
  416. : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
  417. bool GetStatus() const override {
  418. return joystick->GetHatDirection(hat, direction);
  419. }
  420. private:
  421. std::shared_ptr<SDLJoystick> joystick;
  422. int hat;
  423. Uint8 direction;
  424. };
  425. class SDLAxisButton final : public Input::ButtonDevice {
  426. public:
  427. explicit SDLAxisButton(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
  428. bool trigger_if_greater_)
  429. : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
  430. trigger_if_greater(trigger_if_greater_) {}
  431. bool GetStatus() const override {
  432. const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f);
  433. if (trigger_if_greater) {
  434. return axis_value > threshold;
  435. }
  436. return axis_value < threshold;
  437. }
  438. private:
  439. std::shared_ptr<SDLJoystick> joystick;
  440. int axis;
  441. float threshold;
  442. bool trigger_if_greater;
  443. };
  444. class SDLAnalog final : public Input::AnalogDevice {
  445. public:
  446. explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_,
  447. bool invert_x_, bool invert_y_, float deadzone_, float range_,
  448. float offset_x_, float offset_y_)
  449. : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_),
  450. invert_y(invert_y_), deadzone(deadzone_), range(range_), offset_x(offset_x_),
  451. offset_y(offset_y_) {}
  452. std::tuple<float, float> GetStatus() const override {
  453. auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range, offset_x, offset_y);
  454. const float r = std::sqrt((x * x) + (y * y));
  455. if (invert_x) {
  456. x = -x;
  457. }
  458. if (invert_y) {
  459. y = -y;
  460. }
  461. if (r > deadzone) {
  462. return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone),
  463. y / r * (r - deadzone) / (1 - deadzone));
  464. }
  465. return {};
  466. }
  467. std::tuple<float, float> GetRawStatus() const override {
  468. const float x = joystick->GetAxis(axis_x, range, offset_x);
  469. const float y = joystick->GetAxis(axis_y, range, offset_y);
  470. return {x, -y};
  471. }
  472. Input::AnalogProperties GetAnalogProperties() const override {
  473. return {deadzone, range, 0.5f};
  474. }
  475. bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
  476. const auto [x, y] = GetStatus();
  477. const float directional_deadzone = 0.5f;
  478. switch (direction) {
  479. case Input::AnalogDirection::RIGHT:
  480. return x > directional_deadzone;
  481. case Input::AnalogDirection::LEFT:
  482. return x < -directional_deadzone;
  483. case Input::AnalogDirection::UP:
  484. return y > directional_deadzone;
  485. case Input::AnalogDirection::DOWN:
  486. return y < -directional_deadzone;
  487. }
  488. return false;
  489. }
  490. private:
  491. std::shared_ptr<SDLJoystick> joystick;
  492. const int axis_x;
  493. const int axis_y;
  494. const bool invert_x;
  495. const bool invert_y;
  496. const float deadzone;
  497. const float range;
  498. const float offset_x;
  499. const float offset_y;
  500. };
  501. class SDLVibration final : public Input::VibrationDevice {
  502. public:
  503. explicit SDLVibration(std::shared_ptr<SDLJoystick> joystick_)
  504. : joystick(std::move(joystick_)) {}
  505. u8 GetStatus() const override {
  506. joystick->RumblePlay(1, 1);
  507. return joystick->RumblePlay(0, 0);
  508. }
  509. bool SetRumblePlay(f32 amp_low, [[maybe_unused]] f32 freq_low, f32 amp_high,
  510. [[maybe_unused]] f32 freq_high) const override {
  511. const auto process_amplitude = [](f32 amplitude) {
  512. return static_cast<u16>((amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF);
  513. };
  514. const auto processed_amp_low = process_amplitude(amp_low);
  515. const auto processed_amp_high = process_amplitude(amp_high);
  516. return joystick->RumblePlay(processed_amp_low, processed_amp_high);
  517. }
  518. private:
  519. std::shared_ptr<SDLJoystick> joystick;
  520. };
  521. class SDLMotion final : public Input::MotionDevice {
  522. public:
  523. explicit SDLMotion(std::shared_ptr<SDLJoystick> joystick_) : joystick(std::move(joystick_)) {}
  524. Input::MotionStatus GetStatus() const override {
  525. return joystick->GetMotion().GetMotion();
  526. }
  527. private:
  528. std::shared_ptr<SDLJoystick> joystick;
  529. };
  530. class SDLDirectionMotion final : public Input::MotionDevice {
  531. public:
  532. explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
  533. : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
  534. Input::MotionStatus GetStatus() const override {
  535. if (joystick->GetHatDirection(hat, direction)) {
  536. return joystick->GetMotion().GetRandomMotion(2, 6);
  537. }
  538. return joystick->GetMotion().GetRandomMotion(0, 0);
  539. }
  540. private:
  541. std::shared_ptr<SDLJoystick> joystick;
  542. int hat;
  543. Uint8 direction;
  544. };
  545. class SDLAxisMotion final : public Input::MotionDevice {
  546. public:
  547. explicit SDLAxisMotion(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
  548. bool trigger_if_greater_)
  549. : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
  550. trigger_if_greater(trigger_if_greater_) {}
  551. Input::MotionStatus GetStatus() const override {
  552. const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f);
  553. bool trigger = axis_value < threshold;
  554. if (trigger_if_greater) {
  555. trigger = axis_value > threshold;
  556. }
  557. if (trigger) {
  558. return joystick->GetMotion().GetRandomMotion(2, 6);
  559. }
  560. return joystick->GetMotion().GetRandomMotion(0, 0);
  561. }
  562. private:
  563. std::shared_ptr<SDLJoystick> joystick;
  564. int axis;
  565. float threshold;
  566. bool trigger_if_greater;
  567. };
  568. class SDLButtonMotion final : public Input::MotionDevice {
  569. public:
  570. explicit SDLButtonMotion(std::shared_ptr<SDLJoystick> joystick_, int button_)
  571. : joystick(std::move(joystick_)), button(button_) {}
  572. Input::MotionStatus GetStatus() const override {
  573. if (joystick->GetButton(button)) {
  574. return joystick->GetMotion().GetRandomMotion(2, 6);
  575. }
  576. return joystick->GetMotion().GetRandomMotion(0, 0);
  577. }
  578. private:
  579. std::shared_ptr<SDLJoystick> joystick;
  580. int button;
  581. };
  582. /// A button device factory that creates button devices from SDL joystick
  583. class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
  584. public:
  585. explicit SDLButtonFactory(SDLState& state_) : state(state_) {}
  586. /**
  587. * Creates a button device from a joystick button
  588. * @param params contains parameters for creating the device:
  589. * - "guid": the guid of the joystick to bind
  590. * - "port": the nth joystick of the same type to bind
  591. * - "button"(optional): the index of the button to bind
  592. * - "hat"(optional): the index of the hat to bind as direction buttons
  593. * - "axis"(optional): the index of the axis to bind
  594. * - "direction"(only used for hat): the direction name of the hat to bind. Can be "up",
  595. * "down", "left" or "right"
  596. * - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is
  597. * triggered if the axis value crosses
  598. * - "direction"(only used for axis): "+" means the button is triggered when the axis
  599. * value is greater than the threshold; "-" means the button is triggered when the axis
  600. * value is smaller than the threshold
  601. */
  602. std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override {
  603. const std::string guid = params.Get("guid", "0");
  604. const int port = params.Get("port", 0);
  605. const auto toggle = params.Get("toggle", false);
  606. auto joystick = state.GetSDLJoystickByGUID(guid, port);
  607. if (params.Has("hat")) {
  608. const int hat = params.Get("hat", 0);
  609. const std::string direction_name = params.Get("direction", "");
  610. Uint8 direction;
  611. if (direction_name == "up") {
  612. direction = SDL_HAT_UP;
  613. } else if (direction_name == "down") {
  614. direction = SDL_HAT_DOWN;
  615. } else if (direction_name == "left") {
  616. direction = SDL_HAT_LEFT;
  617. } else if (direction_name == "right") {
  618. direction = SDL_HAT_RIGHT;
  619. } else {
  620. direction = 0;
  621. }
  622. // This is necessary so accessing GetHat with hat won't crash
  623. joystick->SetHat(hat, SDL_HAT_CENTERED);
  624. return std::make_unique<SDLDirectionButton>(joystick, hat, direction);
  625. }
  626. if (params.Has("axis")) {
  627. const int axis = params.Get("axis", 0);
  628. // Convert range from (0.0, 1.0) to (-1.0, 1.0)
  629. const float threshold = (params.Get("threshold", 0.5f) - 0.5f) * 2.0f;
  630. const std::string direction_name = params.Get("direction", "");
  631. bool trigger_if_greater;
  632. if (direction_name == "+") {
  633. trigger_if_greater = true;
  634. } else if (direction_name == "-") {
  635. trigger_if_greater = false;
  636. } else {
  637. trigger_if_greater = true;
  638. LOG_ERROR(Input, "Unknown direction {}", direction_name);
  639. }
  640. // This is necessary so accessing GetAxis with axis won't crash
  641. joystick->PreSetAxis(axis);
  642. return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater);
  643. }
  644. const int button = params.Get("button", 0);
  645. // This is necessary so accessing GetButton with button won't crash
  646. joystick->PreSetButton(button);
  647. return std::make_unique<SDLButton>(joystick, button, toggle);
  648. }
  649. private:
  650. SDLState& state;
  651. };
  652. /// An analog device factory that creates analog devices from SDL joystick
  653. class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> {
  654. public:
  655. explicit SDLAnalogFactory(SDLState& state_) : state(state_) {}
  656. /**
  657. * Creates an analog device from joystick axes
  658. * @param params contains parameters for creating the device:
  659. * - "guid": the guid of the joystick to bind
  660. * - "port": the nth joystick of the same type
  661. * - "axis_x": the index of the axis to be bind as x-axis
  662. * - "axis_y": the index of the axis to be bind as y-axis
  663. */
  664. std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override {
  665. const std::string guid = params.Get("guid", "0");
  666. const int port = params.Get("port", 0);
  667. const int axis_x = params.Get("axis_x", 0);
  668. const int axis_y = params.Get("axis_y", 1);
  669. const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
  670. const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
  671. const std::string invert_x_value = params.Get("invert_x", "+");
  672. const std::string invert_y_value = params.Get("invert_y", "+");
  673. const bool invert_x = invert_x_value == "-";
  674. const bool invert_y = invert_y_value == "-";
  675. const float offset_x = params.Get("offset_x", 0.0f);
  676. const float offset_y = params.Get("offset_y", 0.0f);
  677. auto joystick = state.GetSDLJoystickByGUID(guid, port);
  678. // This is necessary so accessing GetAxis with axis_x and axis_y won't crash
  679. joystick->PreSetAxis(axis_x);
  680. joystick->PreSetAxis(axis_y);
  681. return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, invert_x, invert_y, deadzone,
  682. range, offset_x, offset_y);
  683. }
  684. private:
  685. SDLState& state;
  686. };
  687. /// An vibration device factory that creates vibration devices from SDL joystick
  688. class SDLVibrationFactory final : public Input::Factory<Input::VibrationDevice> {
  689. public:
  690. explicit SDLVibrationFactory(SDLState& state_) : state(state_) {}
  691. /**
  692. * Creates a vibration device from a joystick
  693. * @param params contains parameters for creating the device:
  694. * - "guid": the guid of the joystick to bind
  695. * - "port": the nth joystick of the same type
  696. */
  697. std::unique_ptr<Input::VibrationDevice> Create(const Common::ParamPackage& params) override {
  698. const std::string guid = params.Get("guid", "0");
  699. const int port = params.Get("port", 0);
  700. return std::make_unique<SDLVibration>(state.GetSDLJoystickByGUID(guid, port));
  701. }
  702. private:
  703. SDLState& state;
  704. };
  705. /// A motion device factory that creates motion devices from SDL joystick
  706. class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> {
  707. public:
  708. explicit SDLMotionFactory(SDLState& state_) : state(state_) {}
  709. /**
  710. * Creates motion device from joystick axes
  711. * @param params contains parameters for creating the device:
  712. * - "guid": the guid of the joystick to bind
  713. * - "port": the nth joystick of the same type
  714. */
  715. std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override {
  716. const std::string guid = params.Get("guid", "0");
  717. const int port = params.Get("port", 0);
  718. auto joystick = state.GetSDLJoystickByGUID(guid, port);
  719. if (params.Has("motion")) {
  720. return std::make_unique<SDLMotion>(joystick);
  721. }
  722. if (params.Has("hat")) {
  723. const int hat = params.Get("hat", 0);
  724. const std::string direction_name = params.Get("direction", "");
  725. Uint8 direction;
  726. if (direction_name == "up") {
  727. direction = SDL_HAT_UP;
  728. } else if (direction_name == "down") {
  729. direction = SDL_HAT_DOWN;
  730. } else if (direction_name == "left") {
  731. direction = SDL_HAT_LEFT;
  732. } else if (direction_name == "right") {
  733. direction = SDL_HAT_RIGHT;
  734. } else {
  735. direction = 0;
  736. }
  737. // This is necessary so accessing GetHat with hat won't crash
  738. joystick->SetHat(hat, SDL_HAT_CENTERED);
  739. return std::make_unique<SDLDirectionMotion>(joystick, hat, direction);
  740. }
  741. if (params.Has("axis")) {
  742. const int axis = params.Get("axis", 0);
  743. const float threshold = params.Get("threshold", 0.5f);
  744. const std::string direction_name = params.Get("direction", "");
  745. bool trigger_if_greater;
  746. if (direction_name == "+") {
  747. trigger_if_greater = true;
  748. } else if (direction_name == "-") {
  749. trigger_if_greater = false;
  750. } else {
  751. trigger_if_greater = true;
  752. LOG_ERROR(Input, "Unknown direction {}", direction_name);
  753. }
  754. // This is necessary so accessing GetAxis with axis won't crash
  755. joystick->PreSetAxis(axis);
  756. return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater);
  757. }
  758. const int button = params.Get("button", 0);
  759. // This is necessary so accessing GetButton with button won't crash
  760. joystick->PreSetButton(button);
  761. return std::make_unique<SDLButtonMotion>(joystick, button);
  762. }
  763. private:
  764. SDLState& state;
  765. };
  766. SDLState::SDLState() {
  767. using namespace Input;
  768. button_factory = std::make_shared<SDLButtonFactory>(*this);
  769. analog_factory = std::make_shared<SDLAnalogFactory>(*this);
  770. vibration_factory = std::make_shared<SDLVibrationFactory>(*this);
  771. motion_factory = std::make_shared<SDLMotionFactory>(*this);
  772. RegisterFactory<ButtonDevice>("sdl", button_factory);
  773. RegisterFactory<AnalogDevice>("sdl", analog_factory);
  774. RegisterFactory<VibrationDevice>("sdl", vibration_factory);
  775. RegisterFactory<MotionDevice>("sdl", motion_factory);
  776. if (!Settings::values.enable_raw_input) {
  777. // Disable raw input. When enabled this setting causes SDL to die when a web applet opens
  778. SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
  779. }
  780. // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers
  781. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
  782. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
  783. // Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a
  784. // GameController and not a generic one
  785. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
  786. // Turn off Pro controller home led
  787. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0");
  788. // If the frontend is going to manage the event loop, then we don't start one here
  789. start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0;
  790. if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) {
  791. LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
  792. return;
  793. }
  794. has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0;
  795. if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
  796. LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
  797. }
  798. SDL_AddEventWatch(&SDLEventWatcher, this);
  799. initialized = true;
  800. if (start_thread) {
  801. poll_thread = std::thread([this] {
  802. using namespace std::chrono_literals;
  803. while (initialized) {
  804. SDL_PumpEvents();
  805. std::this_thread::sleep_for(1ms);
  806. }
  807. });
  808. }
  809. // Because the events for joystick connection happens before we have our event watcher added, we
  810. // can just open all the joysticks right here
  811. for (int i = 0; i < SDL_NumJoysticks(); ++i) {
  812. InitJoystick(i);
  813. }
  814. }
  815. SDLState::~SDLState() {
  816. using namespace Input;
  817. UnregisterFactory<ButtonDevice>("sdl");
  818. UnregisterFactory<AnalogDevice>("sdl");
  819. UnregisterFactory<VibrationDevice>("sdl");
  820. UnregisterFactory<MotionDevice>("sdl");
  821. CloseJoysticks();
  822. SDL_DelEventWatch(&SDLEventWatcher, this);
  823. initialized = false;
  824. if (start_thread) {
  825. poll_thread.join();
  826. SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
  827. }
  828. }
  829. std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
  830. std::scoped_lock lock(joystick_map_mutex);
  831. std::vector<Common::ParamPackage> devices;
  832. std::unordered_map<int, std::shared_ptr<SDLJoystick>> joycon_pairs;
  833. for (const auto& [key, value] : joystick_map) {
  834. for (const auto& joystick : value) {
  835. if (!joystick->GetSDLJoystick()) {
  836. continue;
  837. }
  838. std::string name =
  839. fmt::format("{} {}", joystick->GetControllerName(), joystick->GetPort());
  840. devices.emplace_back(Common::ParamPackage{
  841. {"class", "sdl"},
  842. {"display", std::move(name)},
  843. {"guid", joystick->GetGUID()},
  844. {"port", std::to_string(joystick->GetPort())},
  845. });
  846. if (joystick->IsJoyconLeft()) {
  847. joycon_pairs.insert_or_assign(joystick->GetPort(), joystick);
  848. }
  849. }
  850. }
  851. // Add dual controllers
  852. for (const auto& [key, value] : joystick_map) {
  853. for (const auto& joystick : value) {
  854. if (joystick->IsJoyconRight()) {
  855. if (!joycon_pairs.contains(joystick->GetPort())) {
  856. continue;
  857. }
  858. const auto joystick2 = joycon_pairs.at(joystick->GetPort());
  859. std::string name =
  860. fmt::format("{} {}", "Nintendo Dual Joy-Con", joystick->GetPort());
  861. devices.emplace_back(Common::ParamPackage{
  862. {"class", "sdl"},
  863. {"display", std::move(name)},
  864. {"guid", joystick->GetGUID()},
  865. {"guid2", joystick2->GetGUID()},
  866. {"port", std::to_string(joystick->GetPort())},
  867. });
  868. }
  869. }
  870. }
  871. return devices;
  872. }
  873. namespace {
  874. Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis,
  875. float value = 0.1f) {
  876. Common::ParamPackage params({{"engine", "sdl"}});
  877. params.Set("port", port);
  878. params.Set("guid", std::move(guid));
  879. params.Set("axis", axis);
  880. params.Set("threshold", "0.5");
  881. if (value > 0) {
  882. params.Set("direction", "+");
  883. } else {
  884. params.Set("direction", "-");
  885. }
  886. return params;
  887. }
  888. Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, s32 button) {
  889. Common::ParamPackage params({{"engine", "sdl"}});
  890. params.Set("port", port);
  891. params.Set("guid", std::move(guid));
  892. params.Set("button", button);
  893. params.Set("toggle", false);
  894. return params;
  895. }
  896. Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat, s32 value) {
  897. Common::ParamPackage params({{"engine", "sdl"}});
  898. params.Set("port", port);
  899. params.Set("guid", std::move(guid));
  900. params.Set("hat", hat);
  901. switch (value) {
  902. case SDL_HAT_UP:
  903. params.Set("direction", "up");
  904. break;
  905. case SDL_HAT_DOWN:
  906. params.Set("direction", "down");
  907. break;
  908. case SDL_HAT_LEFT:
  909. params.Set("direction", "left");
  910. break;
  911. case SDL_HAT_RIGHT:
  912. params.Set("direction", "right");
  913. break;
  914. default:
  915. return {};
  916. }
  917. return params;
  918. }
  919. Common::ParamPackage BuildMotionParam(int port, std::string guid) {
  920. Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}});
  921. params.Set("port", port);
  922. params.Set("guid", std::move(guid));
  923. return params;
  924. }
  925. Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
  926. switch (event.type) {
  927. case SDL_JOYAXISMOTION: {
  928. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
  929. return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  930. static_cast<s32>(event.jaxis.axis),
  931. event.jaxis.value);
  932. }
  933. break;
  934. }
  935. case SDL_JOYBUTTONUP: {
  936. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) {
  937. return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  938. static_cast<s32>(event.jbutton.button));
  939. }
  940. break;
  941. }
  942. case SDL_JOYHATMOTION: {
  943. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) {
  944. return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  945. static_cast<s32>(event.jhat.hat),
  946. static_cast<s32>(event.jhat.value));
  947. }
  948. break;
  949. }
  950. }
  951. return {};
  952. }
  953. Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) {
  954. switch (event.type) {
  955. case SDL_JOYAXISMOTION: {
  956. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
  957. return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  958. static_cast<s32>(event.jaxis.axis),
  959. event.jaxis.value);
  960. }
  961. break;
  962. }
  963. case SDL_JOYBUTTONUP: {
  964. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) {
  965. return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  966. static_cast<s32>(event.jbutton.button));
  967. }
  968. break;
  969. }
  970. case SDL_JOYHATMOTION: {
  971. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) {
  972. return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  973. static_cast<s32>(event.jhat.hat),
  974. static_cast<s32>(event.jhat.value));
  975. }
  976. break;
  977. }
  978. case SDL_CONTROLLERSENSORUPDATE: {
  979. bool is_motion_shaking = false;
  980. constexpr float gyro_threshold = 5.0f;
  981. constexpr float accel_threshold = 11.0f;
  982. if (event.csensor.sensor == SDL_SENSOR_ACCEL) {
  983. const Common::Vec3f acceleration = {-event.csensor.data[0], event.csensor.data[2],
  984. -event.csensor.data[1]};
  985. if (acceleration.Length() > accel_threshold) {
  986. is_motion_shaking = true;
  987. }
  988. }
  989. if (event.csensor.sensor == SDL_SENSOR_GYRO) {
  990. const Common::Vec3f gyroscope = {event.csensor.data[0], -event.csensor.data[2],
  991. event.csensor.data[1]};
  992. if (gyroscope.Length() > gyro_threshold) {
  993. is_motion_shaking = true;
  994. }
  995. }
  996. if (!is_motion_shaking) {
  997. break;
  998. }
  999. if (const auto joystick = state.GetSDLJoystickBySDLID(event.csensor.which)) {
  1000. return BuildMotionParam(joystick->GetPort(), joystick->GetGUID());
  1001. }
  1002. break;
  1003. }
  1004. }
  1005. return {};
  1006. }
  1007. Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
  1008. const SDL_GameControllerButtonBind& binding) {
  1009. switch (binding.bindType) {
  1010. case SDL_CONTROLLER_BINDTYPE_NONE:
  1011. break;
  1012. case SDL_CONTROLLER_BINDTYPE_AXIS:
  1013. return BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
  1014. case SDL_CONTROLLER_BINDTYPE_BUTTON:
  1015. return BuildButtonParamPackageForButton(port, guid, binding.value.button);
  1016. case SDL_CONTROLLER_BINDTYPE_HAT:
  1017. return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
  1018. binding.value.hat.hat_mask);
  1019. }
  1020. return {};
  1021. }
  1022. Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x,
  1023. int axis_y, float offset_x, float offset_y) {
  1024. Common::ParamPackage params;
  1025. params.Set("engine", "sdl");
  1026. params.Set("port", port);
  1027. params.Set("guid", guid);
  1028. params.Set("axis_x", axis_x);
  1029. params.Set("axis_y", axis_y);
  1030. params.Set("offset_x", offset_x);
  1031. params.Set("offset_y", offset_y);
  1032. params.Set("invert_x", "+");
  1033. params.Set("invert_y", "+");
  1034. return params;
  1035. }
  1036. } // Anonymous namespace
  1037. ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) {
  1038. if (!params.Has("guid") || !params.Has("port")) {
  1039. return {};
  1040. }
  1041. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  1042. auto* controller = joystick->GetSDLGameController();
  1043. if (controller == nullptr) {
  1044. return {};
  1045. }
  1046. // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
  1047. // We will add those afterwards
  1048. // This list also excludes Screenshot since theres not really a mapping for that
  1049. ButtonBindings switch_to_sdl_button;
  1050. if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) {
  1051. switch_to_sdl_button = GetNintendoButtonBinding(joystick);
  1052. } else {
  1053. switch_to_sdl_button = GetDefaultButtonBinding();
  1054. }
  1055. // Add the missing bindings for ZL/ZR
  1056. static constexpr ZButtonBindings switch_to_sdl_axis{{
  1057. {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
  1058. {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
  1059. }};
  1060. // Parameters contain two joysticks return dual
  1061. if (params.Has("guid2")) {
  1062. const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
  1063. if (joystick2->GetSDLGameController() != nullptr) {
  1064. return GetDualControllerMapping(joystick, joystick2, switch_to_sdl_button,
  1065. switch_to_sdl_axis);
  1066. }
  1067. }
  1068. return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis);
  1069. }
  1070. ButtonBindings SDLState::GetDefaultButtonBinding() const {
  1071. return {
  1072. std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
  1073. {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
  1074. {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
  1075. {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
  1076. {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
  1077. {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
  1078. {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  1079. {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  1080. {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
  1081. {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
  1082. {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
  1083. {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
  1084. {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
  1085. {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
  1086. {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  1087. {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  1088. {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
  1089. };
  1090. }
  1091. ButtonBindings SDLState::GetNintendoButtonBinding(
  1092. const std::shared_ptr<SDLJoystick>& joystick) const {
  1093. // Default SL/SR mapping for pro controllers
  1094. auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
  1095. auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
  1096. if (joystick->IsJoyconLeft()) {
  1097. sl_button = SDL_CONTROLLER_BUTTON_PADDLE2;
  1098. sr_button = SDL_CONTROLLER_BUTTON_PADDLE4;
  1099. }
  1100. if (joystick->IsJoyconRight()) {
  1101. sl_button = SDL_CONTROLLER_BUTTON_PADDLE3;
  1102. sr_button = SDL_CONTROLLER_BUTTON_PADDLE1;
  1103. }
  1104. return {
  1105. std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_A},
  1106. {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_B},
  1107. {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_X},
  1108. {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_Y},
  1109. {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
  1110. {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
  1111. {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  1112. {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  1113. {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
  1114. {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
  1115. {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
  1116. {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
  1117. {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
  1118. {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
  1119. {Settings::NativeButton::SL, sl_button},
  1120. {Settings::NativeButton::SR, sr_button},
  1121. {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
  1122. };
  1123. }
  1124. ButtonMapping SDLState::GetSingleControllerMapping(
  1125. const std::shared_ptr<SDLJoystick>& joystick, const ButtonBindings& switch_to_sdl_button,
  1126. const ZButtonBindings& switch_to_sdl_axis) const {
  1127. ButtonMapping mapping;
  1128. mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
  1129. auto* controller = joystick->GetSDLGameController();
  1130. for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
  1131. const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
  1132. mapping.insert_or_assign(
  1133. switch_button,
  1134. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  1135. }
  1136. for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
  1137. const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
  1138. mapping.insert_or_assign(
  1139. switch_button,
  1140. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  1141. }
  1142. return mapping;
  1143. }
  1144. ButtonMapping SDLState::GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
  1145. const std::shared_ptr<SDLJoystick>& joystick2,
  1146. const ButtonBindings& switch_to_sdl_button,
  1147. const ZButtonBindings& switch_to_sdl_axis) const {
  1148. ButtonMapping mapping;
  1149. mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
  1150. auto* controller = joystick->GetSDLGameController();
  1151. auto* controller2 = joystick2->GetSDLGameController();
  1152. for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
  1153. if (IsButtonOnLeftSide(switch_button)) {
  1154. const auto& binding = SDL_GameControllerGetBindForButton(controller2, sdl_button);
  1155. mapping.insert_or_assign(
  1156. switch_button,
  1157. BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
  1158. continue;
  1159. }
  1160. const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
  1161. mapping.insert_or_assign(
  1162. switch_button,
  1163. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  1164. }
  1165. for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
  1166. if (IsButtonOnLeftSide(switch_button)) {
  1167. const auto& binding = SDL_GameControllerGetBindForAxis(controller2, sdl_axis);
  1168. mapping.insert_or_assign(
  1169. switch_button,
  1170. BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
  1171. continue;
  1172. }
  1173. const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
  1174. mapping.insert_or_assign(
  1175. switch_button,
  1176. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  1177. }
  1178. return mapping;
  1179. }
  1180. bool SDLState::IsButtonOnLeftSide(Settings::NativeButton::Values button) const {
  1181. switch (button) {
  1182. case Settings::NativeButton::DDown:
  1183. case Settings::NativeButton::DLeft:
  1184. case Settings::NativeButton::DRight:
  1185. case Settings::NativeButton::DUp:
  1186. case Settings::NativeButton::L:
  1187. case Settings::NativeButton::LStick:
  1188. case Settings::NativeButton::Minus:
  1189. case Settings::NativeButton::Screenshot:
  1190. case Settings::NativeButton::ZL:
  1191. return true;
  1192. default:
  1193. return false;
  1194. }
  1195. }
  1196. AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
  1197. if (!params.Has("guid") || !params.Has("port")) {
  1198. return {};
  1199. }
  1200. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  1201. const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
  1202. auto* controller = joystick->GetSDLGameController();
  1203. if (controller == nullptr) {
  1204. return {};
  1205. }
  1206. AnalogMapping mapping = {};
  1207. const auto& binding_left_x =
  1208. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
  1209. const auto& binding_left_y =
  1210. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
  1211. if (params.Has("guid2")) {
  1212. joystick2->PreSetAxis(binding_left_x.value.axis);
  1213. joystick2->PreSetAxis(binding_left_y.value.axis);
  1214. const auto left_offset_x = -joystick2->GetAxis(binding_left_x.value.axis, 1.0f, 0);
  1215. const auto left_offset_y = -joystick2->GetAxis(binding_left_y.value.axis, 1.0f, 0);
  1216. mapping.insert_or_assign(
  1217. Settings::NativeAnalog::LStick,
  1218. BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(),
  1219. binding_left_x.value.axis, binding_left_y.value.axis,
  1220. left_offset_x, left_offset_y));
  1221. } else {
  1222. joystick->PreSetAxis(binding_left_x.value.axis);
  1223. joystick->PreSetAxis(binding_left_y.value.axis);
  1224. const auto left_offset_x = -joystick->GetAxis(binding_left_x.value.axis, 1.0f, 0);
  1225. const auto left_offset_y = -joystick->GetAxis(binding_left_y.value.axis, 1.0f, 0);
  1226. mapping.insert_or_assign(
  1227. Settings::NativeAnalog::LStick,
  1228. BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
  1229. binding_left_x.value.axis, binding_left_y.value.axis,
  1230. left_offset_x, left_offset_y));
  1231. }
  1232. const auto& binding_right_x =
  1233. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
  1234. const auto& binding_right_y =
  1235. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
  1236. joystick->PreSetAxis(binding_right_x.value.axis);
  1237. joystick->PreSetAxis(binding_right_y.value.axis);
  1238. const auto right_offset_x = -joystick->GetAxis(binding_right_x.value.axis, 1.0f, 0);
  1239. const auto right_offset_y = -joystick->GetAxis(binding_right_y.value.axis, 1.0f, 0);
  1240. mapping.insert_or_assign(Settings::NativeAnalog::RStick,
  1241. BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
  1242. binding_right_x.value.axis,
  1243. binding_right_y.value.axis, right_offset_x,
  1244. right_offset_y));
  1245. return mapping;
  1246. }
  1247. MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& params) {
  1248. if (!params.Has("guid") || !params.Has("port")) {
  1249. return {};
  1250. }
  1251. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  1252. const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
  1253. auto* controller = joystick->GetSDLGameController();
  1254. if (controller == nullptr) {
  1255. return {};
  1256. }
  1257. MotionMapping mapping = {};
  1258. joystick->EnableMotion();
  1259. if (joystick->HasGyro() || joystick->HasAccel()) {
  1260. mapping.insert_or_assign(Settings::NativeMotion::MotionRight,
  1261. BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
  1262. }
  1263. if (params.Has("guid2")) {
  1264. joystick2->EnableMotion();
  1265. if (joystick2->HasGyro() || joystick2->HasAccel()) {
  1266. mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
  1267. BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID()));
  1268. }
  1269. } else {
  1270. if (joystick->HasGyro() || joystick->HasAccel()) {
  1271. mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
  1272. BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
  1273. }
  1274. }
  1275. return mapping;
  1276. }
  1277. namespace Polling {
  1278. class SDLPoller : public InputCommon::Polling::DevicePoller {
  1279. public:
  1280. explicit SDLPoller(SDLState& state_) : state(state_) {}
  1281. void Start([[maybe_unused]] const std::string& device_id) override {
  1282. state.event_queue.Clear();
  1283. state.polling = true;
  1284. }
  1285. void Stop() override {
  1286. state.polling = false;
  1287. }
  1288. protected:
  1289. SDLState& state;
  1290. };
  1291. class SDLButtonPoller final : public SDLPoller {
  1292. public:
  1293. explicit SDLButtonPoller(SDLState& state_) : SDLPoller(state_) {}
  1294. Common::ParamPackage GetNextInput() override {
  1295. SDL_Event event;
  1296. while (state.event_queue.Pop(event)) {
  1297. const auto package = FromEvent(event);
  1298. if (package) {
  1299. return *package;
  1300. }
  1301. }
  1302. return {};
  1303. }
  1304. [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(SDL_Event& event) {
  1305. switch (event.type) {
  1306. case SDL_JOYAXISMOTION:
  1307. if (!axis_memory.count(event.jaxis.which) ||
  1308. !axis_memory[event.jaxis.which].count(event.jaxis.axis)) {
  1309. axis_memory[event.jaxis.which][event.jaxis.axis] = event.jaxis.value;
  1310. axis_event_count[event.jaxis.which][event.jaxis.axis] = 1;
  1311. break;
  1312. } else {
  1313. axis_event_count[event.jaxis.which][event.jaxis.axis]++;
  1314. // The joystick and axis exist in our map if we take this branch, so no checks
  1315. // needed
  1316. if (std::abs(
  1317. (event.jaxis.value - axis_memory[event.jaxis.which][event.jaxis.axis]) /
  1318. 32767.0) < 0.5) {
  1319. break;
  1320. } else {
  1321. if (axis_event_count[event.jaxis.which][event.jaxis.axis] == 2 &&
  1322. IsAxisAtPole(event.jaxis.value) &&
  1323. IsAxisAtPole(axis_memory[event.jaxis.which][event.jaxis.axis])) {
  1324. // If we have exactly two events and both are near a pole, this is
  1325. // likely a digital input masquerading as an analog axis; Instead of
  1326. // trying to look at the direction the axis travelled, assume the first
  1327. // event was press and the second was release; This should handle most
  1328. // digital axes while deferring to the direction of travel for analog
  1329. // axes
  1330. event.jaxis.value = static_cast<Sint16>(
  1331. std::copysign(32767, axis_memory[event.jaxis.which][event.jaxis.axis]));
  1332. } else {
  1333. // There are more than two events, so this is likely a true analog axis,
  1334. // check the direction it travelled
  1335. event.jaxis.value = static_cast<Sint16>(std::copysign(
  1336. 32767,
  1337. event.jaxis.value - axis_memory[event.jaxis.which][event.jaxis.axis]));
  1338. }
  1339. axis_memory.clear();
  1340. axis_event_count.clear();
  1341. }
  1342. }
  1343. [[fallthrough]];
  1344. case SDL_JOYBUTTONUP:
  1345. case SDL_JOYHATMOTION:
  1346. return {SDLEventToButtonParamPackage(state, event)};
  1347. }
  1348. return std::nullopt;
  1349. }
  1350. private:
  1351. // Determine whether an axis value is close to an extreme or center
  1352. // Some controllers have a digital D-Pad as a pair of analog sticks, with 3 possible values per
  1353. // axis, which is why the center must be considered a pole
  1354. bool IsAxisAtPole(int16_t value) const {
  1355. return std::abs(value) >= 32767 || std::abs(value) < 327;
  1356. }
  1357. std::unordered_map<SDL_JoystickID, std::unordered_map<uint8_t, int16_t>> axis_memory;
  1358. std::unordered_map<SDL_JoystickID, std::unordered_map<uint8_t, uint32_t>> axis_event_count;
  1359. };
  1360. class SDLMotionPoller final : public SDLPoller {
  1361. public:
  1362. explicit SDLMotionPoller(SDLState& state_) : SDLPoller(state_) {}
  1363. Common::ParamPackage GetNextInput() override {
  1364. SDL_Event event;
  1365. while (state.event_queue.Pop(event)) {
  1366. const auto package = FromEvent(event);
  1367. if (package) {
  1368. return *package;
  1369. }
  1370. }
  1371. return {};
  1372. }
  1373. [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
  1374. switch (event.type) {
  1375. case SDL_JOYAXISMOTION:
  1376. if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
  1377. break;
  1378. }
  1379. [[fallthrough]];
  1380. case SDL_JOYBUTTONUP:
  1381. case SDL_JOYHATMOTION:
  1382. case SDL_CONTROLLERSENSORUPDATE:
  1383. return {SDLEventToMotionParamPackage(state, event)};
  1384. }
  1385. return std::nullopt;
  1386. }
  1387. };
  1388. /**
  1389. * Attempts to match the press to a controller joy axis (left/right stick) and if a match
  1390. * isn't found, checks if the event matches anything from SDLButtonPoller and uses that
  1391. * instead
  1392. */
  1393. class SDLAnalogPreferredPoller final : public SDLPoller {
  1394. public:
  1395. explicit SDLAnalogPreferredPoller(SDLState& state_)
  1396. : SDLPoller(state_), button_poller(state_) {}
  1397. void Start(const std::string& device_id) override {
  1398. SDLPoller::Start(device_id);
  1399. // Reset stored axes
  1400. first_axis = -1;
  1401. }
  1402. Common::ParamPackage GetNextInput() override {
  1403. SDL_Event event;
  1404. while (state.event_queue.Pop(event)) {
  1405. if (event.type != SDL_JOYAXISMOTION) {
  1406. // Check for a button press
  1407. auto button_press = button_poller.FromEvent(event);
  1408. if (button_press) {
  1409. return *button_press;
  1410. }
  1411. continue;
  1412. }
  1413. const auto axis = event.jaxis.axis;
  1414. // Filter out axis events that are below a threshold
  1415. if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
  1416. continue;
  1417. }
  1418. // Filter out axis events that are the same
  1419. if (first_axis == axis) {
  1420. continue;
  1421. }
  1422. // In order to return a complete analog param, we need inputs for both axes.
  1423. // If the first axis isn't set we set the value then wait till next event
  1424. if (first_axis == -1) {
  1425. first_axis = axis;
  1426. continue;
  1427. }
  1428. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
  1429. // Set offset to zero since the joystick is not on center
  1430. auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
  1431. first_axis, axis, 0, 0);
  1432. first_axis = -1;
  1433. return params;
  1434. }
  1435. }
  1436. return {};
  1437. }
  1438. private:
  1439. int first_axis = -1;
  1440. SDLButtonPoller button_poller;
  1441. };
  1442. } // namespace Polling
  1443. SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
  1444. Pollers pollers;
  1445. switch (type) {
  1446. case InputCommon::Polling::DeviceType::AnalogPreferred:
  1447. pollers.emplace_back(std::make_unique<Polling::SDLAnalogPreferredPoller>(*this));
  1448. break;
  1449. case InputCommon::Polling::DeviceType::Button:
  1450. pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
  1451. break;
  1452. case InputCommon::Polling::DeviceType::Motion:
  1453. pollers.emplace_back(std::make_unique<Polling::SDLMotionPoller>(*this));
  1454. break;
  1455. }
  1456. return pollers;
  1457. }
  1458. } // namespace InputCommon::SDL