sdl_driver.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093
  1. // SPDX-FileCopyrightText: 2018 Citra Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/logging/log.h"
  4. #include "common/math_util.h"
  5. #include "common/param_package.h"
  6. #include "common/settings.h"
  7. #include "common/thread.h"
  8. #include "common/vector_math.h"
  9. #include "input_common/drivers/sdl_driver.h"
  10. namespace InputCommon {
  11. namespace {
  12. Common::UUID GetGUID(SDL_Joystick* joystick) {
  13. const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  14. std::array<u8, 16> data{};
  15. std::memcpy(data.data(), guid.data, sizeof(data));
  16. // Clear controller name crc
  17. std::memset(data.data() + 2, 0, sizeof(u16));
  18. return Common::UUID{data};
  19. }
  20. } // Anonymous namespace
  21. static int SDLEventWatcher(void* user_data, SDL_Event* event) {
  22. auto* const sdl_state = static_cast<SDLDriver*>(user_data);
  23. sdl_state->HandleGameControllerEvent(*event);
  24. return 0;
  25. }
  26. class SDLJoystick {
  27. public:
  28. SDLJoystick(Common::UUID guid_, int port_, SDL_Joystick* joystick,
  29. SDL_GameController* game_controller)
  30. : guid{guid_}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
  31. sdl_controller{game_controller, &SDL_GameControllerClose} {
  32. EnableMotion();
  33. }
  34. void EnableMotion() {
  35. if (!sdl_controller) {
  36. return;
  37. }
  38. SDL_GameController* controller = sdl_controller.get();
  39. if (HasMotion()) {
  40. SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_FALSE);
  41. SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_FALSE);
  42. }
  43. has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) == SDL_TRUE;
  44. has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) == SDL_TRUE;
  45. if (has_accel) {
  46. SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
  47. }
  48. if (has_gyro) {
  49. SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE);
  50. }
  51. }
  52. bool HasMotion() const {
  53. return has_gyro || has_accel;
  54. }
  55. bool UpdateMotion(SDL_ControllerSensorEvent event) {
  56. constexpr float gravity_constant = 9.80665f;
  57. std::scoped_lock lock{mutex};
  58. const u64 time_difference = event.timestamp - last_motion_update;
  59. last_motion_update = event.timestamp;
  60. switch (event.sensor) {
  61. case SDL_SENSOR_ACCEL: {
  62. motion.accel_x = -event.data[0] / gravity_constant;
  63. motion.accel_y = event.data[2] / gravity_constant;
  64. motion.accel_z = -event.data[1] / gravity_constant;
  65. break;
  66. }
  67. case SDL_SENSOR_GYRO: {
  68. motion.gyro_x = event.data[0] / (Common::PI * 2);
  69. motion.gyro_y = -event.data[2] / (Common::PI * 2);
  70. motion.gyro_z = event.data[1] / (Common::PI * 2);
  71. break;
  72. }
  73. }
  74. // Ignore duplicated timestamps
  75. if (time_difference == 0) {
  76. return false;
  77. }
  78. // Motion data is invalid
  79. if (motion.accel_x == 0 && motion.gyro_x == 0 && motion.accel_y == 0 &&
  80. motion.gyro_y == 0 && motion.accel_z == 0 && motion.gyro_z == 0) {
  81. if (motion_error_count++ < 200) {
  82. return false;
  83. }
  84. // Try restarting the sensor
  85. motion_error_count = 0;
  86. EnableMotion();
  87. return false;
  88. }
  89. motion_error_count = 0;
  90. motion.delta_timestamp = time_difference * 1000;
  91. return true;
  92. }
  93. const BasicMotion& GetMotion() const {
  94. return motion;
  95. }
  96. bool RumblePlay(const Common::Input::VibrationStatus vibration) {
  97. constexpr u32 rumble_max_duration_ms = 1000;
  98. if (sdl_controller) {
  99. return SDL_GameControllerRumble(
  100. sdl_controller.get(), static_cast<u16>(vibration.low_amplitude),
  101. static_cast<u16>(vibration.high_amplitude), rumble_max_duration_ms) != -1;
  102. } else if (sdl_joystick) {
  103. return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(vibration.low_amplitude),
  104. static_cast<u16>(vibration.high_amplitude),
  105. rumble_max_duration_ms) != -1;
  106. }
  107. return false;
  108. }
  109. bool HasHDRumble() const {
  110. if (sdl_controller) {
  111. const auto type = SDL_GameControllerGetType(sdl_controller.get());
  112. return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ||
  113. (type == SDL_CONTROLLER_TYPE_PS5);
  114. }
  115. return false;
  116. }
  117. void EnableVibration(bool is_enabled) {
  118. has_vibration = is_enabled;
  119. is_vibration_tested = true;
  120. }
  121. bool HasVibration() const {
  122. return has_vibration;
  123. }
  124. bool IsVibrationTested() const {
  125. return is_vibration_tested;
  126. }
  127. /**
  128. * The Pad identifier of the joystick
  129. */
  130. const PadIdentifier GetPadIdentifier() const {
  131. return {
  132. .guid = guid,
  133. .port = static_cast<std::size_t>(port),
  134. .pad = 0,
  135. };
  136. }
  137. /**
  138. * The guid of the joystick
  139. */
  140. const Common::UUID& GetGUID() const {
  141. return guid;
  142. }
  143. /**
  144. * The number of joystick from the same type that were connected before this joystick
  145. */
  146. int GetPort() const {
  147. return port;
  148. }
  149. SDL_Joystick* GetSDLJoystick() const {
  150. return sdl_joystick.get();
  151. }
  152. SDL_GameController* GetSDLGameController() const {
  153. return sdl_controller.get();
  154. }
  155. void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
  156. sdl_joystick.reset(joystick);
  157. sdl_controller.reset(controller);
  158. }
  159. bool IsJoyconLeft() const {
  160. const std::string controller_name = GetControllerName();
  161. if (std::strstr(controller_name.c_str(), "Joy-Con Left") != nullptr) {
  162. return true;
  163. }
  164. if (std::strstr(controller_name.c_str(), "Joy-Con (L)") != nullptr) {
  165. return true;
  166. }
  167. return false;
  168. }
  169. bool IsJoyconRight() const {
  170. const std::string controller_name = GetControllerName();
  171. if (std::strstr(controller_name.c_str(), "Joy-Con Right") != nullptr) {
  172. return true;
  173. }
  174. if (std::strstr(controller_name.c_str(), "Joy-Con (R)") != nullptr) {
  175. return true;
  176. }
  177. return false;
  178. }
  179. Common::Input::BatteryLevel GetBatteryLevel() {
  180. const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get());
  181. switch (level) {
  182. case SDL_JOYSTICK_POWER_EMPTY:
  183. return Common::Input::BatteryLevel::Empty;
  184. case SDL_JOYSTICK_POWER_LOW:
  185. return Common::Input::BatteryLevel::Low;
  186. case SDL_JOYSTICK_POWER_MEDIUM:
  187. return Common::Input::BatteryLevel::Medium;
  188. case SDL_JOYSTICK_POWER_FULL:
  189. case SDL_JOYSTICK_POWER_MAX:
  190. return Common::Input::BatteryLevel::Full;
  191. case SDL_JOYSTICK_POWER_WIRED:
  192. return Common::Input::BatteryLevel::Charging;
  193. case SDL_JOYSTICK_POWER_UNKNOWN:
  194. default:
  195. return Common::Input::BatteryLevel::None;
  196. }
  197. }
  198. std::string GetControllerName() const {
  199. if (sdl_controller) {
  200. switch (SDL_GameControllerGetType(sdl_controller.get())) {
  201. case SDL_CONTROLLER_TYPE_XBOX360:
  202. return "Xbox 360 Controller";
  203. case SDL_CONTROLLER_TYPE_XBOXONE:
  204. return "Xbox One Controller";
  205. case SDL_CONTROLLER_TYPE_PS3:
  206. return "DualShock 3 Controller";
  207. case SDL_CONTROLLER_TYPE_PS4:
  208. return "DualShock 4 Controller";
  209. case SDL_CONTROLLER_TYPE_PS5:
  210. return "DualSense Controller";
  211. default:
  212. break;
  213. }
  214. const auto name = SDL_GameControllerName(sdl_controller.get());
  215. if (name) {
  216. return name;
  217. }
  218. }
  219. if (sdl_joystick) {
  220. const auto name = SDL_JoystickName(sdl_joystick.get());
  221. if (name) {
  222. return name;
  223. }
  224. }
  225. return "Unknown";
  226. }
  227. private:
  228. Common::UUID guid;
  229. int port;
  230. std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
  231. std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
  232. mutable std::mutex mutex;
  233. u64 last_motion_update{};
  234. std::size_t motion_error_count{};
  235. bool has_gyro{false};
  236. bool has_accel{false};
  237. bool has_vibration{false};
  238. bool is_vibration_tested{false};
  239. BasicMotion motion;
  240. };
  241. std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const Common::UUID& guid, int port) {
  242. std::scoped_lock lock{joystick_map_mutex};
  243. const auto it = joystick_map.find(guid);
  244. if (it != joystick_map.end()) {
  245. while (it->second.size() <= static_cast<std::size_t>(port)) {
  246. auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
  247. nullptr, nullptr);
  248. it->second.emplace_back(std::move(joystick));
  249. }
  250. return it->second[static_cast<std::size_t>(port)];
  251. }
  252. auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
  253. return joystick_map[guid].emplace_back(std::move(joystick));
  254. }
  255. std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) {
  256. return GetSDLJoystickByGUID(Common::UUID{guid}, port);
  257. }
  258. std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
  259. auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
  260. const auto guid = GetGUID(sdl_joystick);
  261. std::scoped_lock lock{joystick_map_mutex};
  262. const auto map_it = joystick_map.find(guid);
  263. if (map_it == joystick_map.end()) {
  264. return nullptr;
  265. }
  266. const auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(),
  267. [&sdl_joystick](const auto& joystick) {
  268. return joystick->GetSDLJoystick() == sdl_joystick;
  269. });
  270. if (vec_it == map_it->second.end()) {
  271. return nullptr;
  272. }
  273. return *vec_it;
  274. }
  275. void SDLDriver::InitJoystick(int joystick_index) {
  276. SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
  277. SDL_GameController* sdl_gamecontroller = nullptr;
  278. if (SDL_IsGameController(joystick_index)) {
  279. sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
  280. }
  281. if (!sdl_joystick) {
  282. LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
  283. return;
  284. }
  285. const auto guid = GetGUID(sdl_joystick);
  286. if (Settings::values.enable_joycon_driver) {
  287. if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e &&
  288. (guid.uuid[8] == 0x06 || guid.uuid[8] == 0x07)) {
  289. LOG_WARNING(Input, "Preferring joycon driver for device index {}", joystick_index);
  290. SDL_JoystickClose(sdl_joystick);
  291. return;
  292. }
  293. }
  294. if (Settings::values.enable_procon_driver) {
  295. if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e && guid.uuid[8] == 0x09) {
  296. LOG_WARNING(Input, "Preferring joycon driver for device index {}", joystick_index);
  297. SDL_JoystickClose(sdl_joystick);
  298. return;
  299. }
  300. }
  301. std::scoped_lock lock{joystick_map_mutex};
  302. if (joystick_map.find(guid) == joystick_map.end()) {
  303. auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
  304. PreSetController(joystick->GetPadIdentifier());
  305. SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
  306. joystick->EnableMotion();
  307. joystick_map[guid].emplace_back(std::move(joystick));
  308. return;
  309. }
  310. auto& joystick_guid_list = joystick_map[guid];
  311. const auto joystick_it =
  312. std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
  313. [](const auto& joystick) { return !joystick->GetSDLJoystick(); });
  314. if (joystick_it != joystick_guid_list.end()) {
  315. (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
  316. (*joystick_it)->EnableMotion();
  317. return;
  318. }
  319. const int port = static_cast<int>(joystick_guid_list.size());
  320. auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
  321. PreSetController(joystick->GetPadIdentifier());
  322. SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
  323. joystick->EnableMotion();
  324. joystick_guid_list.emplace_back(std::move(joystick));
  325. }
  326. void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) {
  327. const auto guid = GetGUID(sdl_joystick);
  328. std::scoped_lock lock{joystick_map_mutex};
  329. // This call to guid is safe since the joystick is guaranteed to be in the map
  330. const auto& joystick_guid_list = joystick_map[guid];
  331. const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
  332. [&sdl_joystick](const auto& joystick) {
  333. return joystick->GetSDLJoystick() == sdl_joystick;
  334. });
  335. if (joystick_it != joystick_guid_list.end()) {
  336. (*joystick_it)->SetSDLJoystick(nullptr, nullptr);
  337. }
  338. }
  339. void SDLDriver::PumpEvents() const {
  340. if (initialized) {
  341. SDL_PumpEvents();
  342. }
  343. }
  344. void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
  345. switch (event.type) {
  346. case SDL_JOYBUTTONUP: {
  347. if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
  348. const PadIdentifier identifier = joystick->GetPadIdentifier();
  349. SetButton(identifier, event.jbutton.button, false);
  350. }
  351. break;
  352. }
  353. case SDL_JOYBUTTONDOWN: {
  354. if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
  355. const PadIdentifier identifier = joystick->GetPadIdentifier();
  356. SetButton(identifier, event.jbutton.button, true);
  357. // Battery doesn't trigger an event so just update every button press
  358. SetBattery(identifier, joystick->GetBatteryLevel());
  359. }
  360. break;
  361. }
  362. case SDL_JOYHATMOTION: {
  363. if (const auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) {
  364. const PadIdentifier identifier = joystick->GetPadIdentifier();
  365. SetHatButton(identifier, event.jhat.hat, event.jhat.value);
  366. }
  367. break;
  368. }
  369. case SDL_JOYAXISMOTION: {
  370. if (const auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) {
  371. const PadIdentifier identifier = joystick->GetPadIdentifier();
  372. SetAxis(identifier, event.jaxis.axis, event.jaxis.value / 32767.0f);
  373. }
  374. break;
  375. }
  376. case SDL_CONTROLLERSENSORUPDATE: {
  377. if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) {
  378. if (joystick->UpdateMotion(event.csensor)) {
  379. const PadIdentifier identifier = joystick->GetPadIdentifier();
  380. SetMotion(identifier, 0, joystick->GetMotion());
  381. }
  382. }
  383. break;
  384. }
  385. case SDL_JOYDEVICEREMOVED:
  386. LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
  387. CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
  388. break;
  389. case SDL_JOYDEVICEADDED:
  390. LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which);
  391. InitJoystick(event.jdevice.which);
  392. break;
  393. }
  394. }
  395. void SDLDriver::CloseJoysticks() {
  396. std::scoped_lock lock{joystick_map_mutex};
  397. joystick_map.clear();
  398. }
  399. SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
  400. if (!Settings::values.enable_raw_input) {
  401. // Disable raw input. When enabled this setting causes SDL to die when a web applet opens
  402. SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
  403. }
  404. // Prevent SDL from adding undesired axis
  405. SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
  406. // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers
  407. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
  408. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
  409. SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
  410. // Disable hidapi drivers for joycon controllers when the custom joycon driver is enabled
  411. if (Settings::values.enable_joycon_driver) {
  412. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0");
  413. } else {
  414. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
  415. }
  416. // Disable hidapi drivers for pro controllers when the custom joycon driver is enabled
  417. if (Settings::values.enable_procon_driver) {
  418. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0");
  419. } else {
  420. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1");
  421. }
  422. // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native
  423. // driver on Linux.
  424. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0");
  425. // If the frontend is going to manage the event loop, then we don't start one here
  426. start_thread = SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == 0;
  427. if (start_thread && SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) {
  428. LOG_CRITICAL(Input, "SDL_Init failed with: {}", SDL_GetError());
  429. return;
  430. }
  431. SDL_AddEventWatch(&SDLEventWatcher, this);
  432. initialized = true;
  433. if (start_thread) {
  434. vibration_thread = std::thread([this] {
  435. Common::SetCurrentThreadName("SDL_Vibration");
  436. using namespace std::chrono_literals;
  437. while (initialized) {
  438. SendVibrations();
  439. std::this_thread::sleep_for(10ms);
  440. }
  441. });
  442. }
  443. // Because the events for joystick connection happens before we have our event watcher added, we
  444. // can just open all the joysticks right here
  445. for (int i = 0; i < SDL_NumJoysticks(); ++i) {
  446. InitJoystick(i);
  447. }
  448. }
  449. SDLDriver::~SDLDriver() {
  450. CloseJoysticks();
  451. SDL_DelEventWatch(&SDLEventWatcher, this);
  452. initialized = false;
  453. if (start_thread) {
  454. vibration_thread.join();
  455. SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
  456. }
  457. }
  458. std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
  459. std::vector<Common::ParamPackage> devices;
  460. std::unordered_map<int, std::shared_ptr<SDLJoystick>> joycon_pairs;
  461. for (const auto& [key, value] : joystick_map) {
  462. for (const auto& joystick : value) {
  463. if (!joystick->GetSDLJoystick()) {
  464. continue;
  465. }
  466. const std::string name =
  467. fmt::format("{} {}", joystick->GetControllerName(), joystick->GetPort());
  468. devices.emplace_back(Common::ParamPackage{
  469. {"engine", GetEngineName()},
  470. {"display", std::move(name)},
  471. {"guid", joystick->GetGUID().RawString()},
  472. {"port", std::to_string(joystick->GetPort())},
  473. });
  474. if (joystick->IsJoyconLeft()) {
  475. joycon_pairs.insert_or_assign(joystick->GetPort(), joystick);
  476. }
  477. }
  478. }
  479. // Add dual controllers
  480. for (const auto& [key, value] : joystick_map) {
  481. for (const auto& joystick : value) {
  482. if (joystick->IsJoyconRight()) {
  483. if (!joycon_pairs.contains(joystick->GetPort())) {
  484. continue;
  485. }
  486. const auto joystick2 = joycon_pairs.at(joystick->GetPort());
  487. const std::string name =
  488. fmt::format("{} {}", "Nintendo Dual Joy-Con", joystick->GetPort());
  489. devices.emplace_back(Common::ParamPackage{
  490. {"engine", GetEngineName()},
  491. {"display", std::move(name)},
  492. {"guid", joystick->GetGUID().RawString()},
  493. {"guid2", joystick2->GetGUID().RawString()},
  494. {"port", std::to_string(joystick->GetPort())},
  495. });
  496. }
  497. }
  498. }
  499. return devices;
  500. }
  501. Common::Input::DriverResult SDLDriver::SetVibration(
  502. const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
  503. const auto joystick =
  504. GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port));
  505. const auto process_amplitude_exp = [](f32 amplitude, f32 factor) {
  506. return (amplitude + std::pow(amplitude, factor)) * 0.5f * 0xFFFF;
  507. };
  508. // Default exponential curve for rumble
  509. f32 factor = 0.35f;
  510. // If vibration is set as a linear output use a flatter value
  511. if (vibration.type == Common::Input::VibrationAmplificationType::Linear) {
  512. factor = 0.5f;
  513. }
  514. // Amplitude for HD rumble needs no modification
  515. if (joystick->HasHDRumble()) {
  516. factor = 1.0f;
  517. }
  518. const Common::Input::VibrationStatus new_vibration{
  519. .low_amplitude = process_amplitude_exp(vibration.low_amplitude, factor),
  520. .low_frequency = vibration.low_frequency,
  521. .high_amplitude = process_amplitude_exp(vibration.high_amplitude, factor),
  522. .high_frequency = vibration.high_frequency,
  523. .type = Common::Input::VibrationAmplificationType::Exponential,
  524. };
  525. vibration_queue.Push(VibrationRequest{
  526. .identifier = identifier,
  527. .vibration = new_vibration,
  528. });
  529. return Common::Input::DriverResult::Success;
  530. }
  531. bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) {
  532. const auto joystick =
  533. GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port));
  534. constexpr Common::Input::VibrationStatus test_vibration{
  535. .low_amplitude = 1,
  536. .low_frequency = 160.0f,
  537. .high_amplitude = 1,
  538. .high_frequency = 320.0f,
  539. .type = Common::Input::VibrationAmplificationType::Exponential,
  540. };
  541. constexpr Common::Input::VibrationStatus zero_vibration{
  542. .low_amplitude = 0,
  543. .low_frequency = 160.0f,
  544. .high_amplitude = 0,
  545. .high_frequency = 320.0f,
  546. .type = Common::Input::VibrationAmplificationType::Exponential,
  547. };
  548. if (joystick->IsVibrationTested()) {
  549. return joystick->HasVibration();
  550. }
  551. // First vibration might fail
  552. joystick->RumblePlay(test_vibration);
  553. // Wait for about 15ms to ensure the controller is ready for the stop command
  554. std::this_thread::sleep_for(std::chrono::milliseconds(15));
  555. if (!joystick->RumblePlay(zero_vibration)) {
  556. joystick->EnableVibration(false);
  557. return false;
  558. }
  559. joystick->EnableVibration(true);
  560. return true;
  561. }
  562. void SDLDriver::SendVibrations() {
  563. while (!vibration_queue.Empty()) {
  564. VibrationRequest request;
  565. vibration_queue.Pop(request);
  566. const auto joystick = GetSDLJoystickByGUID(request.identifier.guid.RawString(),
  567. static_cast<int>(request.identifier.port));
  568. joystick->RumblePlay(request.vibration);
  569. }
  570. }
  571. Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, const Common::UUID& guid,
  572. s32 axis, float value) const {
  573. Common::ParamPackage params{};
  574. params.Set("engine", GetEngineName());
  575. params.Set("port", port);
  576. params.Set("guid", guid.RawString());
  577. params.Set("axis", axis);
  578. params.Set("threshold", "0.5");
  579. params.Set("invert", value < 0 ? "-" : "+");
  580. return params;
  581. }
  582. Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, const Common::UUID& guid,
  583. s32 button) const {
  584. Common::ParamPackage params{};
  585. params.Set("engine", GetEngineName());
  586. params.Set("port", port);
  587. params.Set("guid", guid.RawString());
  588. params.Set("button", button);
  589. return params;
  590. }
  591. Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, const Common::UUID& guid,
  592. s32 hat, u8 value) const {
  593. Common::ParamPackage params{};
  594. params.Set("engine", GetEngineName());
  595. params.Set("port", port);
  596. params.Set("guid", guid.RawString());
  597. params.Set("hat", hat);
  598. params.Set("direction", GetHatButtonName(value));
  599. return params;
  600. }
  601. Common::ParamPackage SDLDriver::BuildMotionParam(int port, const Common::UUID& guid) const {
  602. Common::ParamPackage params{};
  603. params.Set("engine", GetEngineName());
  604. params.Set("motion", 0);
  605. params.Set("port", port);
  606. params.Set("guid", guid.RawString());
  607. return params;
  608. }
  609. Common::ParamPackage SDLDriver::BuildParamPackageForBinding(
  610. int port, const Common::UUID& guid, const SDL_GameControllerButtonBind& binding) const {
  611. switch (binding.bindType) {
  612. case SDL_CONTROLLER_BINDTYPE_NONE:
  613. break;
  614. case SDL_CONTROLLER_BINDTYPE_AXIS:
  615. return BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
  616. case SDL_CONTROLLER_BINDTYPE_BUTTON:
  617. return BuildButtonParamPackageForButton(port, guid, binding.value.button);
  618. case SDL_CONTROLLER_BINDTYPE_HAT:
  619. return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
  620. static_cast<u8>(binding.value.hat.hat_mask));
  621. }
  622. return {};
  623. }
  624. Common::ParamPackage SDLDriver::BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x,
  625. int axis_y, float offset_x,
  626. float offset_y) const {
  627. Common::ParamPackage params;
  628. params.Set("engine", GetEngineName());
  629. params.Set("port", static_cast<int>(identifier.port));
  630. params.Set("guid", identifier.guid.RawString());
  631. params.Set("axis_x", axis_x);
  632. params.Set("axis_y", axis_y);
  633. params.Set("offset_x", offset_x);
  634. params.Set("offset_y", offset_y);
  635. params.Set("invert_x", "+");
  636. params.Set("invert_y", "+");
  637. return params;
  638. }
  639. ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& params) {
  640. if (!params.Has("guid") || !params.Has("port")) {
  641. return {};
  642. }
  643. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  644. auto* controller = joystick->GetSDLGameController();
  645. if (controller == nullptr) {
  646. return {};
  647. }
  648. // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
  649. // We will add those afterwards
  650. // This list also excludes Screenshot since theres not really a mapping for that
  651. ButtonBindings switch_to_sdl_button;
  652. if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) {
  653. switch_to_sdl_button = GetNintendoButtonBinding(joystick);
  654. } else {
  655. switch_to_sdl_button = GetDefaultButtonBinding();
  656. }
  657. // Add the missing bindings for ZL/ZR
  658. static constexpr ZButtonBindings switch_to_sdl_axis{{
  659. {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
  660. {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
  661. }};
  662. // Parameters contain two joysticks return dual
  663. if (params.Has("guid2")) {
  664. const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
  665. if (joystick2->GetSDLGameController() != nullptr) {
  666. return GetDualControllerMapping(joystick, joystick2, switch_to_sdl_button,
  667. switch_to_sdl_axis);
  668. }
  669. }
  670. return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis);
  671. }
  672. ButtonBindings SDLDriver::GetDefaultButtonBinding() const {
  673. return {
  674. std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
  675. {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
  676. {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
  677. {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
  678. {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
  679. {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
  680. {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  681. {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  682. {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
  683. {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
  684. {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
  685. {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
  686. {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
  687. {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
  688. {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  689. {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  690. {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
  691. {Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1},
  692. };
  693. }
  694. ButtonBindings SDLDriver::GetNintendoButtonBinding(
  695. const std::shared_ptr<SDLJoystick>& joystick) const {
  696. // Default SL/SR mapping for pro controllers
  697. auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
  698. auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
  699. if (joystick->IsJoyconLeft()) {
  700. sl_button = SDL_CONTROLLER_BUTTON_PADDLE2;
  701. sr_button = SDL_CONTROLLER_BUTTON_PADDLE4;
  702. }
  703. if (joystick->IsJoyconRight()) {
  704. sl_button = SDL_CONTROLLER_BUTTON_PADDLE3;
  705. sr_button = SDL_CONTROLLER_BUTTON_PADDLE1;
  706. }
  707. return {
  708. std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_A},
  709. {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_B},
  710. {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_X},
  711. {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_Y},
  712. {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
  713. {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
  714. {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  715. {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  716. {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
  717. {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
  718. {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
  719. {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
  720. {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
  721. {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
  722. {Settings::NativeButton::SL, sl_button},
  723. {Settings::NativeButton::SR, sr_button},
  724. {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
  725. {Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1},
  726. };
  727. }
  728. ButtonMapping SDLDriver::GetSingleControllerMapping(
  729. const std::shared_ptr<SDLJoystick>& joystick, const ButtonBindings& switch_to_sdl_button,
  730. const ZButtonBindings& switch_to_sdl_axis) const {
  731. ButtonMapping mapping;
  732. mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
  733. auto* controller = joystick->GetSDLGameController();
  734. for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
  735. const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
  736. mapping.insert_or_assign(
  737. switch_button,
  738. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  739. }
  740. for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
  741. const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
  742. mapping.insert_or_assign(
  743. switch_button,
  744. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  745. }
  746. return mapping;
  747. }
  748. ButtonMapping SDLDriver::GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
  749. const std::shared_ptr<SDLJoystick>& joystick2,
  750. const ButtonBindings& switch_to_sdl_button,
  751. const ZButtonBindings& switch_to_sdl_axis) const {
  752. ButtonMapping mapping;
  753. mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
  754. auto* controller = joystick->GetSDLGameController();
  755. auto* controller2 = joystick2->GetSDLGameController();
  756. for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
  757. if (IsButtonOnLeftSide(switch_button)) {
  758. const auto& binding = SDL_GameControllerGetBindForButton(controller2, sdl_button);
  759. mapping.insert_or_assign(
  760. switch_button,
  761. BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
  762. continue;
  763. }
  764. const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
  765. mapping.insert_or_assign(
  766. switch_button,
  767. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  768. }
  769. for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
  770. if (IsButtonOnLeftSide(switch_button)) {
  771. const auto& binding = SDL_GameControllerGetBindForAxis(controller2, sdl_axis);
  772. mapping.insert_or_assign(
  773. switch_button,
  774. BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
  775. continue;
  776. }
  777. const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
  778. mapping.insert_or_assign(
  779. switch_button,
  780. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  781. }
  782. return mapping;
  783. }
  784. bool SDLDriver::IsButtonOnLeftSide(Settings::NativeButton::Values button) const {
  785. switch (button) {
  786. case Settings::NativeButton::DDown:
  787. case Settings::NativeButton::DLeft:
  788. case Settings::NativeButton::DRight:
  789. case Settings::NativeButton::DUp:
  790. case Settings::NativeButton::L:
  791. case Settings::NativeButton::LStick:
  792. case Settings::NativeButton::Minus:
  793. case Settings::NativeButton::Screenshot:
  794. case Settings::NativeButton::ZL:
  795. return true;
  796. default:
  797. return false;
  798. }
  799. }
  800. AnalogMapping SDLDriver::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
  801. if (!params.Has("guid") || !params.Has("port")) {
  802. return {};
  803. }
  804. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  805. const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
  806. auto* controller = joystick->GetSDLGameController();
  807. if (controller == nullptr) {
  808. return {};
  809. }
  810. AnalogMapping mapping = {};
  811. const auto& binding_left_x =
  812. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
  813. const auto& binding_left_y =
  814. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
  815. if (params.Has("guid2")) {
  816. const auto identifier = joystick2->GetPadIdentifier();
  817. PreSetController(identifier);
  818. PreSetAxis(identifier, binding_left_x.value.axis);
  819. PreSetAxis(identifier, binding_left_y.value.axis);
  820. const auto left_offset_x = -GetAxis(identifier, binding_left_x.value.axis);
  821. const auto left_offset_y = GetAxis(identifier, binding_left_y.value.axis);
  822. mapping.insert_or_assign(Settings::NativeAnalog::LStick,
  823. BuildParamPackageForAnalog(identifier, binding_left_x.value.axis,
  824. binding_left_y.value.axis,
  825. left_offset_x, left_offset_y));
  826. } else {
  827. const auto identifier = joystick->GetPadIdentifier();
  828. PreSetController(identifier);
  829. PreSetAxis(identifier, binding_left_x.value.axis);
  830. PreSetAxis(identifier, binding_left_y.value.axis);
  831. const auto left_offset_x = -GetAxis(identifier, binding_left_x.value.axis);
  832. const auto left_offset_y = GetAxis(identifier, binding_left_y.value.axis);
  833. mapping.insert_or_assign(Settings::NativeAnalog::LStick,
  834. BuildParamPackageForAnalog(identifier, binding_left_x.value.axis,
  835. binding_left_y.value.axis,
  836. left_offset_x, left_offset_y));
  837. }
  838. const auto& binding_right_x =
  839. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
  840. const auto& binding_right_y =
  841. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
  842. const auto identifier = joystick->GetPadIdentifier();
  843. PreSetController(identifier);
  844. PreSetAxis(identifier, binding_right_x.value.axis);
  845. PreSetAxis(identifier, binding_right_y.value.axis);
  846. const auto right_offset_x = -GetAxis(identifier, binding_right_x.value.axis);
  847. const auto right_offset_y = GetAxis(identifier, binding_right_y.value.axis);
  848. mapping.insert_or_assign(Settings::NativeAnalog::RStick,
  849. BuildParamPackageForAnalog(identifier, binding_right_x.value.axis,
  850. binding_right_y.value.axis, right_offset_x,
  851. right_offset_y));
  852. return mapping;
  853. }
  854. MotionMapping SDLDriver::GetMotionMappingForDevice(const Common::ParamPackage& params) {
  855. if (!params.Has("guid") || !params.Has("port")) {
  856. return {};
  857. }
  858. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  859. const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
  860. auto* controller = joystick->GetSDLGameController();
  861. if (controller == nullptr) {
  862. return {};
  863. }
  864. MotionMapping mapping = {};
  865. joystick->EnableMotion();
  866. if (joystick->HasMotion()) {
  867. mapping.insert_or_assign(Settings::NativeMotion::MotionRight,
  868. BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
  869. }
  870. if (params.Has("guid2")) {
  871. joystick2->EnableMotion();
  872. if (joystick2->HasMotion()) {
  873. mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
  874. BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID()));
  875. }
  876. } else {
  877. if (joystick->HasMotion()) {
  878. mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
  879. BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
  880. }
  881. }
  882. return mapping;
  883. }
  884. Common::Input::ButtonNames SDLDriver::GetUIName(const Common::ParamPackage& params) const {
  885. if (params.Has("button")) {
  886. // TODO(German77): Find how to substitue the values for real button names
  887. return Common::Input::ButtonNames::Value;
  888. }
  889. if (params.Has("hat")) {
  890. return Common::Input::ButtonNames::Value;
  891. }
  892. if (params.Has("axis")) {
  893. return Common::Input::ButtonNames::Value;
  894. }
  895. if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) {
  896. return Common::Input::ButtonNames::Value;
  897. }
  898. if (params.Has("motion")) {
  899. return Common::Input::ButtonNames::Engine;
  900. }
  901. return Common::Input::ButtonNames::Invalid;
  902. }
  903. std::string SDLDriver::GetHatButtonName(u8 direction_value) const {
  904. switch (direction_value) {
  905. case SDL_HAT_UP:
  906. return "up";
  907. case SDL_HAT_DOWN:
  908. return "down";
  909. case SDL_HAT_LEFT:
  910. return "left";
  911. case SDL_HAT_RIGHT:
  912. return "right";
  913. default:
  914. return {};
  915. }
  916. }
  917. u8 SDLDriver::GetHatButtonId(const std::string& direction_name) const {
  918. Uint8 direction;
  919. if (direction_name == "up") {
  920. direction = SDL_HAT_UP;
  921. } else if (direction_name == "down") {
  922. direction = SDL_HAT_DOWN;
  923. } else if (direction_name == "left") {
  924. direction = SDL_HAT_LEFT;
  925. } else if (direction_name == "right") {
  926. direction = SDL_HAT_RIGHT;
  927. } else {
  928. direction = 0;
  929. }
  930. return direction;
  931. }
  932. bool SDLDriver::IsStickInverted(const Common::ParamPackage& params) {
  933. if (!params.Has("guid") || !params.Has("port")) {
  934. return false;
  935. }
  936. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  937. if (joystick == nullptr) {
  938. return false;
  939. }
  940. auto* controller = joystick->GetSDLGameController();
  941. if (controller == nullptr) {
  942. return false;
  943. }
  944. const auto& axis_x = params.Get("axis_x", 0);
  945. const auto& axis_y = params.Get("axis_y", 0);
  946. const auto& binding_left_x =
  947. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
  948. const auto& binding_right_x =
  949. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
  950. const auto& binding_left_y =
  951. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
  952. const auto& binding_right_y =
  953. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
  954. if (axis_x != binding_left_y.value.axis && axis_x != binding_right_y.value.axis) {
  955. return false;
  956. }
  957. if (axis_y != binding_left_x.value.axis && axis_y != binding_right_x.value.axis) {
  958. return false;
  959. }
  960. return true;
  961. }
  962. } // namespace InputCommon