sdl_driver.cpp 43 KB

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