sdl_impl.cpp 57 KB

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