sdl_driver.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  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. std::scoped_lock lock{joystick_map_mutex};
  287. if (joystick_map.find(guid) == joystick_map.end()) {
  288. auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
  289. PreSetController(joystick->GetPadIdentifier());
  290. SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
  291. joystick->EnableMotion();
  292. joystick_map[guid].emplace_back(std::move(joystick));
  293. return;
  294. }
  295. auto& joystick_guid_list = joystick_map[guid];
  296. const auto joystick_it =
  297. std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
  298. [](const auto& joystick) { return !joystick->GetSDLJoystick(); });
  299. if (joystick_it != joystick_guid_list.end()) {
  300. (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
  301. (*joystick_it)->EnableMotion();
  302. return;
  303. }
  304. const int port = static_cast<int>(joystick_guid_list.size());
  305. auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
  306. PreSetController(joystick->GetPadIdentifier());
  307. SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
  308. joystick->EnableMotion();
  309. joystick_guid_list.emplace_back(std::move(joystick));
  310. }
  311. void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) {
  312. const auto guid = GetGUID(sdl_joystick);
  313. std::scoped_lock lock{joystick_map_mutex};
  314. // This call to guid is safe since the joystick is guaranteed to be in the map
  315. const auto& joystick_guid_list = joystick_map[guid];
  316. const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
  317. [&sdl_joystick](const auto& joystick) {
  318. return joystick->GetSDLJoystick() == sdl_joystick;
  319. });
  320. if (joystick_it != joystick_guid_list.end()) {
  321. (*joystick_it)->SetSDLJoystick(nullptr, nullptr);
  322. }
  323. }
  324. void SDLDriver::PumpEvents() const {
  325. if (initialized) {
  326. SDL_PumpEvents();
  327. }
  328. }
  329. void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
  330. switch (event.type) {
  331. case SDL_JOYBUTTONUP: {
  332. if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
  333. const PadIdentifier identifier = joystick->GetPadIdentifier();
  334. SetButton(identifier, event.jbutton.button, false);
  335. }
  336. break;
  337. }
  338. case SDL_JOYBUTTONDOWN: {
  339. if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
  340. const PadIdentifier identifier = joystick->GetPadIdentifier();
  341. SetButton(identifier, event.jbutton.button, true);
  342. // Battery doesn't trigger an event so just update every button press
  343. SetBattery(identifier, joystick->GetBatteryLevel());
  344. }
  345. break;
  346. }
  347. case SDL_JOYHATMOTION: {
  348. if (const auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) {
  349. const PadIdentifier identifier = joystick->GetPadIdentifier();
  350. SetHatButton(identifier, event.jhat.hat, event.jhat.value);
  351. }
  352. break;
  353. }
  354. case SDL_JOYAXISMOTION: {
  355. if (const auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) {
  356. const PadIdentifier identifier = joystick->GetPadIdentifier();
  357. SetAxis(identifier, event.jaxis.axis, event.jaxis.value / 32767.0f);
  358. }
  359. break;
  360. }
  361. case SDL_CONTROLLERSENSORUPDATE: {
  362. if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) {
  363. if (joystick->UpdateMotion(event.csensor)) {
  364. const PadIdentifier identifier = joystick->GetPadIdentifier();
  365. SetMotion(identifier, 0, joystick->GetMotion());
  366. }
  367. }
  368. break;
  369. }
  370. case SDL_JOYDEVICEREMOVED:
  371. LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
  372. CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
  373. break;
  374. case SDL_JOYDEVICEADDED:
  375. LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which);
  376. InitJoystick(event.jdevice.which);
  377. break;
  378. }
  379. }
  380. void SDLDriver::CloseJoysticks() {
  381. std::scoped_lock lock{joystick_map_mutex};
  382. joystick_map.clear();
  383. }
  384. SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
  385. if (!Settings::values.enable_raw_input) {
  386. // Disable raw input. When enabled this setting causes SDL to die when a web applet opens
  387. SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
  388. }
  389. // Prevent SDL from adding undesired axis
  390. SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
  391. // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers
  392. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
  393. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
  394. SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
  395. // Use hidapi driver for joycons. This will allow joycons to be detected as a GameController and
  396. // not a generic one
  397. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
  398. // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native
  399. // driver on Linux.
  400. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0");
  401. // If the frontend is going to manage the event loop, then we don't start one here
  402. start_thread = SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == 0;
  403. if (start_thread && SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) {
  404. LOG_CRITICAL(Input, "SDL_Init failed with: {}", SDL_GetError());
  405. return;
  406. }
  407. SDL_AddEventWatch(&SDLEventWatcher, this);
  408. initialized = true;
  409. if (start_thread) {
  410. vibration_thread = std::thread([this] {
  411. Common::SetCurrentThreadName("SDL_Vibration");
  412. using namespace std::chrono_literals;
  413. while (initialized) {
  414. SendVibrations();
  415. std::this_thread::sleep_for(10ms);
  416. }
  417. });
  418. }
  419. // Because the events for joystick connection happens before we have our event watcher added, we
  420. // can just open all the joysticks right here
  421. for (int i = 0; i < SDL_NumJoysticks(); ++i) {
  422. InitJoystick(i);
  423. }
  424. }
  425. SDLDriver::~SDLDriver() {
  426. CloseJoysticks();
  427. SDL_DelEventWatch(&SDLEventWatcher, this);
  428. initialized = false;
  429. if (start_thread) {
  430. vibration_thread.join();
  431. SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
  432. }
  433. }
  434. std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
  435. std::vector<Common::ParamPackage> devices;
  436. std::unordered_map<int, std::shared_ptr<SDLJoystick>> joycon_pairs;
  437. for (const auto& [key, value] : joystick_map) {
  438. for (const auto& joystick : value) {
  439. if (!joystick->GetSDLJoystick()) {
  440. continue;
  441. }
  442. const std::string name =
  443. fmt::format("{} {}", joystick->GetControllerName(), joystick->GetPort());
  444. devices.emplace_back(Common::ParamPackage{
  445. {"engine", GetEngineName()},
  446. {"display", std::move(name)},
  447. {"guid", joystick->GetGUID().RawString()},
  448. {"port", std::to_string(joystick->GetPort())},
  449. });
  450. if (joystick->IsJoyconLeft()) {
  451. joycon_pairs.insert_or_assign(joystick->GetPort(), joystick);
  452. }
  453. }
  454. }
  455. // Add dual controllers
  456. for (const auto& [key, value] : joystick_map) {
  457. for (const auto& joystick : value) {
  458. if (joystick->IsJoyconRight()) {
  459. if (!joycon_pairs.contains(joystick->GetPort())) {
  460. continue;
  461. }
  462. const auto joystick2 = joycon_pairs.at(joystick->GetPort());
  463. const std::string name =
  464. fmt::format("{} {}", "Nintendo Dual Joy-Con", joystick->GetPort());
  465. devices.emplace_back(Common::ParamPackage{
  466. {"engine", GetEngineName()},
  467. {"display", std::move(name)},
  468. {"guid", joystick->GetGUID().RawString()},
  469. {"guid2", joystick2->GetGUID().RawString()},
  470. {"port", std::to_string(joystick->GetPort())},
  471. });
  472. }
  473. }
  474. }
  475. return devices;
  476. }
  477. Common::Input::VibrationError SDLDriver::SetVibration(
  478. const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
  479. const auto joystick =
  480. GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port));
  481. const auto process_amplitude_exp = [](f32 amplitude, f32 factor) {
  482. return (amplitude + std::pow(amplitude, factor)) * 0.5f * 0xFFFF;
  483. };
  484. // Default exponential curve for rumble
  485. f32 factor = 0.35f;
  486. // If vibration is set as a linear output use a flatter value
  487. if (vibration.type == Common::Input::VibrationAmplificationType::Linear) {
  488. factor = 0.5f;
  489. }
  490. // Amplitude for HD rumble needs no modification
  491. if (joystick->HasHDRumble()) {
  492. factor = 1.0f;
  493. }
  494. const Common::Input::VibrationStatus new_vibration{
  495. .low_amplitude = process_amplitude_exp(vibration.low_amplitude, factor),
  496. .low_frequency = vibration.low_frequency,
  497. .high_amplitude = process_amplitude_exp(vibration.high_amplitude, factor),
  498. .high_frequency = vibration.high_frequency,
  499. .type = Common::Input::VibrationAmplificationType::Exponential,
  500. };
  501. vibration_queue.Push(VibrationRequest{
  502. .identifier = identifier,
  503. .vibration = new_vibration,
  504. });
  505. return Common::Input::VibrationError::None;
  506. }
  507. bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) {
  508. const auto joystick =
  509. GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port));
  510. constexpr Common::Input::VibrationStatus test_vibration{
  511. .low_amplitude = 1,
  512. .low_frequency = 160.0f,
  513. .high_amplitude = 1,
  514. .high_frequency = 320.0f,
  515. .type = Common::Input::VibrationAmplificationType::Exponential,
  516. };
  517. constexpr Common::Input::VibrationStatus zero_vibration{
  518. .low_amplitude = 0,
  519. .low_frequency = 160.0f,
  520. .high_amplitude = 0,
  521. .high_frequency = 320.0f,
  522. .type = Common::Input::VibrationAmplificationType::Exponential,
  523. };
  524. if (joystick->IsVibrationTested()) {
  525. return joystick->HasVibration();
  526. }
  527. // First vibration might fail
  528. joystick->RumblePlay(test_vibration);
  529. // Wait for about 15ms to ensure the controller is ready for the stop command
  530. std::this_thread::sleep_for(std::chrono::milliseconds(15));
  531. if (!joystick->RumblePlay(zero_vibration)) {
  532. joystick->EnableVibration(false);
  533. return false;
  534. }
  535. joystick->EnableVibration(true);
  536. return true;
  537. }
  538. void SDLDriver::SendVibrations() {
  539. while (!vibration_queue.Empty()) {
  540. VibrationRequest request;
  541. vibration_queue.Pop(request);
  542. const auto joystick = GetSDLJoystickByGUID(request.identifier.guid.RawString(),
  543. static_cast<int>(request.identifier.port));
  544. joystick->RumblePlay(request.vibration);
  545. }
  546. }
  547. Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, const Common::UUID& guid,
  548. s32 axis, float value) const {
  549. Common::ParamPackage params{};
  550. params.Set("engine", GetEngineName());
  551. params.Set("port", port);
  552. params.Set("guid", guid.RawString());
  553. params.Set("axis", axis);
  554. params.Set("threshold", "0.5");
  555. params.Set("invert", value < 0 ? "-" : "+");
  556. return params;
  557. }
  558. Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, const Common::UUID& guid,
  559. s32 button) const {
  560. Common::ParamPackage params{};
  561. params.Set("engine", GetEngineName());
  562. params.Set("port", port);
  563. params.Set("guid", guid.RawString());
  564. params.Set("button", button);
  565. return params;
  566. }
  567. Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, const Common::UUID& guid,
  568. s32 hat, u8 value) const {
  569. Common::ParamPackage params{};
  570. params.Set("engine", GetEngineName());
  571. params.Set("port", port);
  572. params.Set("guid", guid.RawString());
  573. params.Set("hat", hat);
  574. params.Set("direction", GetHatButtonName(value));
  575. return params;
  576. }
  577. Common::ParamPackage SDLDriver::BuildMotionParam(int port, const Common::UUID& guid) const {
  578. Common::ParamPackage params{};
  579. params.Set("engine", GetEngineName());
  580. params.Set("motion", 0);
  581. params.Set("port", port);
  582. params.Set("guid", guid.RawString());
  583. return params;
  584. }
  585. Common::ParamPackage SDLDriver::BuildParamPackageForBinding(
  586. int port, const Common::UUID& guid, const SDL_GameControllerButtonBind& binding) const {
  587. switch (binding.bindType) {
  588. case SDL_CONTROLLER_BINDTYPE_NONE:
  589. break;
  590. case SDL_CONTROLLER_BINDTYPE_AXIS:
  591. return BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
  592. case SDL_CONTROLLER_BINDTYPE_BUTTON:
  593. return BuildButtonParamPackageForButton(port, guid, binding.value.button);
  594. case SDL_CONTROLLER_BINDTYPE_HAT:
  595. return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
  596. static_cast<u8>(binding.value.hat.hat_mask));
  597. }
  598. return {};
  599. }
  600. Common::ParamPackage SDLDriver::BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x,
  601. int axis_y, float offset_x,
  602. float offset_y) const {
  603. Common::ParamPackage params;
  604. params.Set("engine", GetEngineName());
  605. params.Set("port", static_cast<int>(identifier.port));
  606. params.Set("guid", identifier.guid.RawString());
  607. params.Set("axis_x", axis_x);
  608. params.Set("axis_y", axis_y);
  609. params.Set("offset_x", offset_x);
  610. params.Set("offset_y", offset_y);
  611. params.Set("invert_x", "+");
  612. params.Set("invert_y", "+");
  613. return params;
  614. }
  615. ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& params) {
  616. if (!params.Has("guid") || !params.Has("port")) {
  617. return {};
  618. }
  619. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  620. auto* controller = joystick->GetSDLGameController();
  621. if (controller == nullptr) {
  622. return {};
  623. }
  624. // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
  625. // We will add those afterwards
  626. // This list also excludes Screenshot since theres not really a mapping for that
  627. ButtonBindings switch_to_sdl_button;
  628. if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) {
  629. switch_to_sdl_button = GetNintendoButtonBinding(joystick);
  630. } else {
  631. switch_to_sdl_button = GetDefaultButtonBinding();
  632. }
  633. // Add the missing bindings for ZL/ZR
  634. static constexpr ZButtonBindings switch_to_sdl_axis{{
  635. {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
  636. {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
  637. }};
  638. // Parameters contain two joysticks return dual
  639. if (params.Has("guid2")) {
  640. const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
  641. if (joystick2->GetSDLGameController() != nullptr) {
  642. return GetDualControllerMapping(joystick, joystick2, switch_to_sdl_button,
  643. switch_to_sdl_axis);
  644. }
  645. }
  646. return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis);
  647. }
  648. ButtonBindings SDLDriver::GetDefaultButtonBinding() const {
  649. return {
  650. std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
  651. {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
  652. {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
  653. {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
  654. {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
  655. {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
  656. {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  657. {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  658. {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
  659. {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
  660. {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
  661. {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
  662. {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
  663. {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
  664. {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  665. {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  666. {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
  667. {Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1},
  668. };
  669. }
  670. ButtonBindings SDLDriver::GetNintendoButtonBinding(
  671. const std::shared_ptr<SDLJoystick>& joystick) const {
  672. // Default SL/SR mapping for pro controllers
  673. auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
  674. auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
  675. if (joystick->IsJoyconLeft()) {
  676. sl_button = SDL_CONTROLLER_BUTTON_PADDLE2;
  677. sr_button = SDL_CONTROLLER_BUTTON_PADDLE4;
  678. }
  679. if (joystick->IsJoyconRight()) {
  680. sl_button = SDL_CONTROLLER_BUTTON_PADDLE3;
  681. sr_button = SDL_CONTROLLER_BUTTON_PADDLE1;
  682. }
  683. return {
  684. std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_A},
  685. {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_B},
  686. {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_X},
  687. {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_Y},
  688. {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
  689. {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
  690. {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  691. {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  692. {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
  693. {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
  694. {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
  695. {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
  696. {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
  697. {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
  698. {Settings::NativeButton::SL, sl_button},
  699. {Settings::NativeButton::SR, sr_button},
  700. {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
  701. {Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1},
  702. };
  703. }
  704. ButtonMapping SDLDriver::GetSingleControllerMapping(
  705. const std::shared_ptr<SDLJoystick>& joystick, const ButtonBindings& switch_to_sdl_button,
  706. const ZButtonBindings& switch_to_sdl_axis) const {
  707. ButtonMapping mapping;
  708. mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
  709. auto* controller = joystick->GetSDLGameController();
  710. for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
  711. const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
  712. mapping.insert_or_assign(
  713. switch_button,
  714. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  715. }
  716. for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
  717. const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
  718. mapping.insert_or_assign(
  719. switch_button,
  720. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  721. }
  722. return mapping;
  723. }
  724. ButtonMapping SDLDriver::GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
  725. const std::shared_ptr<SDLJoystick>& joystick2,
  726. const ButtonBindings& switch_to_sdl_button,
  727. const ZButtonBindings& switch_to_sdl_axis) const {
  728. ButtonMapping mapping;
  729. mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
  730. auto* controller = joystick->GetSDLGameController();
  731. auto* controller2 = joystick2->GetSDLGameController();
  732. for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
  733. if (IsButtonOnLeftSide(switch_button)) {
  734. const auto& binding = SDL_GameControllerGetBindForButton(controller2, sdl_button);
  735. mapping.insert_or_assign(
  736. switch_button,
  737. BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
  738. continue;
  739. }
  740. const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
  741. mapping.insert_or_assign(
  742. switch_button,
  743. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  744. }
  745. for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
  746. if (IsButtonOnLeftSide(switch_button)) {
  747. const auto& binding = SDL_GameControllerGetBindForAxis(controller2, sdl_axis);
  748. mapping.insert_or_assign(
  749. switch_button,
  750. BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
  751. continue;
  752. }
  753. const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
  754. mapping.insert_or_assign(
  755. switch_button,
  756. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  757. }
  758. return mapping;
  759. }
  760. bool SDLDriver::IsButtonOnLeftSide(Settings::NativeButton::Values button) const {
  761. switch (button) {
  762. case Settings::NativeButton::DDown:
  763. case Settings::NativeButton::DLeft:
  764. case Settings::NativeButton::DRight:
  765. case Settings::NativeButton::DUp:
  766. case Settings::NativeButton::L:
  767. case Settings::NativeButton::LStick:
  768. case Settings::NativeButton::Minus:
  769. case Settings::NativeButton::Screenshot:
  770. case Settings::NativeButton::ZL:
  771. return true;
  772. default:
  773. return false;
  774. }
  775. }
  776. AnalogMapping SDLDriver::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
  777. if (!params.Has("guid") || !params.Has("port")) {
  778. return {};
  779. }
  780. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  781. const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
  782. auto* controller = joystick->GetSDLGameController();
  783. if (controller == nullptr) {
  784. return {};
  785. }
  786. AnalogMapping mapping = {};
  787. const auto& binding_left_x =
  788. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
  789. const auto& binding_left_y =
  790. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
  791. if (params.Has("guid2")) {
  792. const auto identifier = joystick2->GetPadIdentifier();
  793. PreSetController(identifier);
  794. PreSetAxis(identifier, binding_left_x.value.axis);
  795. PreSetAxis(identifier, binding_left_y.value.axis);
  796. const auto left_offset_x = -GetAxis(identifier, binding_left_x.value.axis);
  797. const auto left_offset_y = GetAxis(identifier, binding_left_y.value.axis);
  798. mapping.insert_or_assign(Settings::NativeAnalog::LStick,
  799. BuildParamPackageForAnalog(identifier, binding_left_x.value.axis,
  800. binding_left_y.value.axis,
  801. left_offset_x, left_offset_y));
  802. } else {
  803. const auto identifier = joystick->GetPadIdentifier();
  804. PreSetController(identifier);
  805. PreSetAxis(identifier, binding_left_x.value.axis);
  806. PreSetAxis(identifier, binding_left_y.value.axis);
  807. const auto left_offset_x = -GetAxis(identifier, binding_left_x.value.axis);
  808. const auto left_offset_y = GetAxis(identifier, binding_left_y.value.axis);
  809. mapping.insert_or_assign(Settings::NativeAnalog::LStick,
  810. BuildParamPackageForAnalog(identifier, binding_left_x.value.axis,
  811. binding_left_y.value.axis,
  812. left_offset_x, left_offset_y));
  813. }
  814. const auto& binding_right_x =
  815. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
  816. const auto& binding_right_y =
  817. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
  818. const auto identifier = joystick->GetPadIdentifier();
  819. PreSetController(identifier);
  820. PreSetAxis(identifier, binding_right_x.value.axis);
  821. PreSetAxis(identifier, binding_right_y.value.axis);
  822. const auto right_offset_x = -GetAxis(identifier, binding_right_x.value.axis);
  823. const auto right_offset_y = GetAxis(identifier, binding_right_y.value.axis);
  824. mapping.insert_or_assign(Settings::NativeAnalog::RStick,
  825. BuildParamPackageForAnalog(identifier, binding_right_x.value.axis,
  826. binding_right_y.value.axis, right_offset_x,
  827. right_offset_y));
  828. return mapping;
  829. }
  830. MotionMapping SDLDriver::GetMotionMappingForDevice(const Common::ParamPackage& params) {
  831. if (!params.Has("guid") || !params.Has("port")) {
  832. return {};
  833. }
  834. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  835. const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
  836. auto* controller = joystick->GetSDLGameController();
  837. if (controller == nullptr) {
  838. return {};
  839. }
  840. MotionMapping mapping = {};
  841. joystick->EnableMotion();
  842. if (joystick->HasMotion()) {
  843. mapping.insert_or_assign(Settings::NativeMotion::MotionRight,
  844. BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
  845. }
  846. if (params.Has("guid2")) {
  847. joystick2->EnableMotion();
  848. if (joystick2->HasMotion()) {
  849. mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
  850. BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID()));
  851. }
  852. } else {
  853. if (joystick->HasMotion()) {
  854. mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
  855. BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
  856. }
  857. }
  858. return mapping;
  859. }
  860. Common::Input::ButtonNames SDLDriver::GetUIName(const Common::ParamPackage& params) const {
  861. if (params.Has("button")) {
  862. // TODO(German77): Find how to substitue the values for real button names
  863. return Common::Input::ButtonNames::Value;
  864. }
  865. if (params.Has("hat")) {
  866. return Common::Input::ButtonNames::Value;
  867. }
  868. if (params.Has("axis")) {
  869. return Common::Input::ButtonNames::Value;
  870. }
  871. if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) {
  872. return Common::Input::ButtonNames::Value;
  873. }
  874. if (params.Has("motion")) {
  875. return Common::Input::ButtonNames::Engine;
  876. }
  877. return Common::Input::ButtonNames::Invalid;
  878. }
  879. std::string SDLDriver::GetHatButtonName(u8 direction_value) const {
  880. switch (direction_value) {
  881. case SDL_HAT_UP:
  882. return "up";
  883. case SDL_HAT_DOWN:
  884. return "down";
  885. case SDL_HAT_LEFT:
  886. return "left";
  887. case SDL_HAT_RIGHT:
  888. return "right";
  889. default:
  890. return {};
  891. }
  892. }
  893. u8 SDLDriver::GetHatButtonId(const std::string& direction_name) const {
  894. Uint8 direction;
  895. if (direction_name == "up") {
  896. direction = SDL_HAT_UP;
  897. } else if (direction_name == "down") {
  898. direction = SDL_HAT_DOWN;
  899. } else if (direction_name == "left") {
  900. direction = SDL_HAT_LEFT;
  901. } else if (direction_name == "right") {
  902. direction = SDL_HAT_RIGHT;
  903. } else {
  904. direction = 0;
  905. }
  906. return direction;
  907. }
  908. bool SDLDriver::IsStickInverted(const Common::ParamPackage& params) {
  909. if (!params.Has("guid") || !params.Has("port")) {
  910. return false;
  911. }
  912. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  913. if (joystick == nullptr) {
  914. return false;
  915. }
  916. auto* controller = joystick->GetSDLGameController();
  917. if (controller == nullptr) {
  918. return false;
  919. }
  920. const auto& axis_x = params.Get("axis_x", 0);
  921. const auto& axis_y = params.Get("axis_y", 0);
  922. const auto& binding_left_x =
  923. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
  924. const auto& binding_right_x =
  925. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
  926. const auto& binding_left_y =
  927. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
  928. const auto& binding_right_y =
  929. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
  930. if (axis_x != binding_left_y.value.axis && axis_x != binding_right_y.value.axis) {
  931. return false;
  932. }
  933. if (axis_y != binding_left_x.value.axis && axis_y != binding_right_x.value.axis) {
  934. return false;
  935. }
  936. return true;
  937. }
  938. } // namespace InputCommon