sdl_impl.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141
  1. // Copyright 2018 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <array>
  6. #include <atomic>
  7. #include <chrono>
  8. #include <cmath>
  9. #include <functional>
  10. #include <mutex>
  11. #include <optional>
  12. #include <sstream>
  13. #include <string>
  14. #include <thread>
  15. #include <tuple>
  16. #include <unordered_map>
  17. #include <utility>
  18. #include <vector>
  19. #include <SDL.h>
  20. #include "common/logging/log.h"
  21. #include "common/param_package.h"
  22. #include "common/threadsafe_queue.h"
  23. #include "core/frontend/input.h"
  24. #include "input_common/motion_input.h"
  25. #include "input_common/sdl/sdl_impl.h"
  26. #include "input_common/settings.h"
  27. namespace InputCommon::SDL {
  28. namespace {
  29. std::string GetGUID(SDL_Joystick* joystick) {
  30. const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  31. char guid_str[33];
  32. SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
  33. return guid_str;
  34. }
  35. /// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice
  36. Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
  37. } // Anonymous namespace
  38. static int SDLEventWatcher(void* user_data, SDL_Event* event) {
  39. auto* const sdl_state = static_cast<SDLState*>(user_data);
  40. // Don't handle the event if we are configuring
  41. if (sdl_state->polling) {
  42. sdl_state->event_queue.Push(*event);
  43. } else {
  44. sdl_state->HandleGameControllerEvent(*event);
  45. }
  46. return 0;
  47. }
  48. class SDLJoystick {
  49. public:
  50. SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
  51. SDL_GameController* game_controller)
  52. : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
  53. sdl_controller{game_controller, &SDL_GameControllerClose} {}
  54. void SetButton(int button, bool value) {
  55. std::lock_guard lock{mutex};
  56. state.buttons.insert_or_assign(button, value);
  57. }
  58. bool GetButton(int button) const {
  59. std::lock_guard lock{mutex};
  60. return state.buttons.at(button);
  61. }
  62. void SetAxis(int axis, Sint16 value) {
  63. std::lock_guard lock{mutex};
  64. state.axes.insert_or_assign(axis, value);
  65. }
  66. float GetAxis(int axis, float range) const {
  67. std::lock_guard lock{mutex};
  68. return static_cast<float>(state.axes.at(axis)) / (32767.0f * range);
  69. }
  70. bool RumblePlay(u16 amp_low, u16 amp_high) {
  71. if (sdl_controller) {
  72. return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, 0) == 0;
  73. } else if (sdl_joystick) {
  74. return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, 0) == 0;
  75. }
  76. return false;
  77. }
  78. std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const {
  79. float x = GetAxis(axis_x, range);
  80. float y = GetAxis(axis_y, range);
  81. y = -y; // 3DS uses an y-axis inverse from SDL
  82. // Make sure the coordinates are in the unit circle,
  83. // otherwise normalize it.
  84. float r = x * x + y * y;
  85. if (r > 1.0f) {
  86. r = std::sqrt(r);
  87. x /= r;
  88. y /= r;
  89. }
  90. return std::make_tuple(x, y);
  91. }
  92. const MotionInput& GetMotion() const {
  93. return motion;
  94. }
  95. void SetHat(int hat, Uint8 direction) {
  96. std::lock_guard lock{mutex};
  97. state.hats.insert_or_assign(hat, direction);
  98. }
  99. bool GetHatDirection(int hat, Uint8 direction) const {
  100. std::lock_guard lock{mutex};
  101. return (state.hats.at(hat) & direction) != 0;
  102. }
  103. /**
  104. * The guid of the joystick
  105. */
  106. const std::string& GetGUID() const {
  107. return guid;
  108. }
  109. /**
  110. * The number of joystick from the same type that were connected before this joystick
  111. */
  112. int GetPort() const {
  113. return port;
  114. }
  115. SDL_Joystick* GetSDLJoystick() const {
  116. return sdl_joystick.get();
  117. }
  118. SDL_GameController* GetSDLGameController() const {
  119. return sdl_controller.get();
  120. }
  121. void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
  122. sdl_joystick.reset(joystick);
  123. sdl_controller.reset(controller);
  124. }
  125. private:
  126. struct State {
  127. std::unordered_map<int, bool> buttons;
  128. std::unordered_map<int, Sint16> axes;
  129. std::unordered_map<int, Uint8> hats;
  130. } state;
  131. std::string guid;
  132. int port;
  133. std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
  134. std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
  135. mutable std::mutex mutex;
  136. // Motion is initialized without PID values as motion input is not aviable for SDL2
  137. MotionInput motion{0.0f, 0.0f, 0.0f};
  138. };
  139. std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
  140. std::lock_guard lock{joystick_map_mutex};
  141. const auto it = joystick_map.find(guid);
  142. if (it != joystick_map.end()) {
  143. while (it->second.size() <= static_cast<std::size_t>(port)) {
  144. auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
  145. nullptr, nullptr);
  146. it->second.emplace_back(std::move(joystick));
  147. }
  148. return it->second[static_cast<std::size_t>(port)];
  149. }
  150. auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
  151. return joystick_map[guid].emplace_back(std::move(joystick));
  152. }
  153. std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
  154. auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
  155. const std::string guid = GetGUID(sdl_joystick);
  156. std::lock_guard lock{joystick_map_mutex};
  157. const auto map_it = joystick_map.find(guid);
  158. if (map_it == joystick_map.end()) {
  159. return nullptr;
  160. }
  161. const auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(),
  162. [&sdl_joystick](const auto& joystick) {
  163. return joystick->GetSDLJoystick() == sdl_joystick;
  164. });
  165. if (vec_it == map_it->second.end()) {
  166. return nullptr;
  167. }
  168. return *vec_it;
  169. }
  170. void SDLState::InitJoystick(int joystick_index) {
  171. SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
  172. SDL_GameController* sdl_gamecontroller = nullptr;
  173. if (SDL_IsGameController(joystick_index)) {
  174. sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
  175. }
  176. if (!sdl_joystick) {
  177. LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
  178. return;
  179. }
  180. const std::string guid = GetGUID(sdl_joystick);
  181. std::lock_guard lock{joystick_map_mutex};
  182. if (joystick_map.find(guid) == joystick_map.end()) {
  183. auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
  184. joystick_map[guid].emplace_back(std::move(joystick));
  185. return;
  186. }
  187. auto& joystick_guid_list = joystick_map[guid];
  188. const auto joystick_it =
  189. std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
  190. [](const auto& joystick) { return !joystick->GetSDLJoystick(); });
  191. if (joystick_it != joystick_guid_list.end()) {
  192. (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
  193. return;
  194. }
  195. const int port = static_cast<int>(joystick_guid_list.size());
  196. auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
  197. joystick_guid_list.emplace_back(std::move(joystick));
  198. }
  199. void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
  200. const std::string guid = GetGUID(sdl_joystick);
  201. std::lock_guard lock{joystick_map_mutex};
  202. // This call to guid is safe since the joystick is guaranteed to be in the map
  203. const auto& joystick_guid_list = joystick_map[guid];
  204. const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
  205. [&sdl_joystick](const auto& joystick) {
  206. return joystick->GetSDLJoystick() == sdl_joystick;
  207. });
  208. (*joystick_it)->SetSDLJoystick(nullptr, nullptr);
  209. }
  210. void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
  211. switch (event.type) {
  212. case SDL_JOYBUTTONUP: {
  213. if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
  214. joystick->SetButton(event.jbutton.button, false);
  215. }
  216. break;
  217. }
  218. case SDL_JOYBUTTONDOWN: {
  219. if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
  220. joystick->SetButton(event.jbutton.button, true);
  221. }
  222. break;
  223. }
  224. case SDL_JOYHATMOTION: {
  225. if (auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) {
  226. joystick->SetHat(event.jhat.hat, event.jhat.value);
  227. }
  228. break;
  229. }
  230. case SDL_JOYAXISMOTION: {
  231. if (auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) {
  232. joystick->SetAxis(event.jaxis.axis, event.jaxis.value);
  233. }
  234. break;
  235. }
  236. case SDL_JOYDEVICEREMOVED:
  237. LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
  238. CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
  239. break;
  240. case SDL_JOYDEVICEADDED:
  241. LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which);
  242. InitJoystick(event.jdevice.which);
  243. break;
  244. }
  245. }
  246. void SDLState::CloseJoysticks() {
  247. std::lock_guard lock{joystick_map_mutex};
  248. joystick_map.clear();
  249. }
  250. class SDLButton final : public Input::ButtonDevice {
  251. public:
  252. explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_)
  253. : joystick(std::move(joystick_)), button(button_) {}
  254. bool GetStatus() const override {
  255. return joystick->GetButton(button);
  256. }
  257. private:
  258. std::shared_ptr<SDLJoystick> joystick;
  259. int button;
  260. };
  261. class SDLDirectionButton final : public Input::ButtonDevice {
  262. public:
  263. explicit SDLDirectionButton(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
  264. : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
  265. bool GetStatus() const override {
  266. return joystick->GetHatDirection(hat, direction);
  267. }
  268. private:
  269. std::shared_ptr<SDLJoystick> joystick;
  270. int hat;
  271. Uint8 direction;
  272. };
  273. class SDLAxisButton final : public Input::ButtonDevice {
  274. public:
  275. explicit SDLAxisButton(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
  276. bool trigger_if_greater_)
  277. : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
  278. trigger_if_greater(trigger_if_greater_) {}
  279. bool GetStatus() const override {
  280. const float axis_value = joystick->GetAxis(axis, 1.0f);
  281. if (trigger_if_greater) {
  282. return axis_value > threshold;
  283. }
  284. return axis_value < threshold;
  285. }
  286. private:
  287. std::shared_ptr<SDLJoystick> joystick;
  288. int axis;
  289. float threshold;
  290. bool trigger_if_greater;
  291. };
  292. class SDLAnalog final : public Input::AnalogDevice {
  293. public:
  294. explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_,
  295. float deadzone_, float range_)
  296. : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_),
  297. range(range_) {}
  298. std::tuple<float, float> GetStatus() const override {
  299. const auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range);
  300. const float r = std::sqrt((x * x) + (y * y));
  301. if (r > deadzone) {
  302. return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone),
  303. y / r * (r - deadzone) / (1 - deadzone));
  304. }
  305. return {};
  306. }
  307. bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
  308. const auto [x, y] = GetStatus();
  309. const float directional_deadzone = 0.5f;
  310. switch (direction) {
  311. case Input::AnalogDirection::RIGHT:
  312. return x > directional_deadzone;
  313. case Input::AnalogDirection::LEFT:
  314. return x < -directional_deadzone;
  315. case Input::AnalogDirection::UP:
  316. return y > directional_deadzone;
  317. case Input::AnalogDirection::DOWN:
  318. return y < -directional_deadzone;
  319. }
  320. return false;
  321. }
  322. private:
  323. std::shared_ptr<SDLJoystick> joystick;
  324. const int axis_x;
  325. const int axis_y;
  326. const float deadzone;
  327. const float range;
  328. };
  329. class SDLVibration final : public Input::VibrationDevice {
  330. public:
  331. explicit SDLVibration(std::shared_ptr<SDLJoystick> joystick_)
  332. : joystick(std::move(joystick_)) {}
  333. u8 GetStatus() const override {
  334. joystick->RumblePlay(1, 1);
  335. return joystick->RumblePlay(0, 0);
  336. }
  337. bool SetRumblePlay(f32 amp_low, [[maybe_unused]] f32 freq_low, f32 amp_high,
  338. [[maybe_unused]] f32 freq_high) const override {
  339. const auto process_amplitude = [](f32 amplitude) {
  340. return static_cast<u16>((amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF);
  341. };
  342. const auto processed_amp_low = process_amplitude(amp_low);
  343. const auto processed_amp_high = process_amplitude(amp_high);
  344. return joystick->RumblePlay(processed_amp_low, processed_amp_high);
  345. }
  346. private:
  347. std::shared_ptr<SDLJoystick> joystick;
  348. };
  349. class SDLDirectionMotion final : public Input::MotionDevice {
  350. public:
  351. explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
  352. : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
  353. Input::MotionStatus GetStatus() const override {
  354. if (joystick->GetHatDirection(hat, direction)) {
  355. return joystick->GetMotion().GetRandomMotion(2, 6);
  356. }
  357. return joystick->GetMotion().GetRandomMotion(0, 0);
  358. }
  359. private:
  360. std::shared_ptr<SDLJoystick> joystick;
  361. int hat;
  362. Uint8 direction;
  363. };
  364. class SDLAxisMotion final : public Input::MotionDevice {
  365. public:
  366. explicit SDLAxisMotion(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
  367. bool trigger_if_greater_)
  368. : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
  369. trigger_if_greater(trigger_if_greater_) {}
  370. Input::MotionStatus GetStatus() const override {
  371. const float axis_value = joystick->GetAxis(axis, 1.0f);
  372. bool trigger = axis_value < threshold;
  373. if (trigger_if_greater) {
  374. trigger = axis_value > threshold;
  375. }
  376. if (trigger) {
  377. return joystick->GetMotion().GetRandomMotion(2, 6);
  378. }
  379. return joystick->GetMotion().GetRandomMotion(0, 0);
  380. }
  381. private:
  382. std::shared_ptr<SDLJoystick> joystick;
  383. int axis;
  384. float threshold;
  385. bool trigger_if_greater;
  386. };
  387. class SDLButtonMotion final : public Input::MotionDevice {
  388. public:
  389. explicit SDLButtonMotion(std::shared_ptr<SDLJoystick> joystick_, int button_)
  390. : joystick(std::move(joystick_)), button(button_) {}
  391. Input::MotionStatus GetStatus() const override {
  392. if (joystick->GetButton(button)) {
  393. return joystick->GetMotion().GetRandomMotion(2, 6);
  394. }
  395. return joystick->GetMotion().GetRandomMotion(0, 0);
  396. }
  397. private:
  398. std::shared_ptr<SDLJoystick> joystick;
  399. int button;
  400. };
  401. /// A button device factory that creates button devices from SDL joystick
  402. class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
  403. public:
  404. explicit SDLButtonFactory(SDLState& state_) : state(state_) {}
  405. /**
  406. * Creates a button device from a joystick button
  407. * @param params contains parameters for creating the device:
  408. * - "guid": the guid of the joystick to bind
  409. * - "port": the nth joystick of the same type to bind
  410. * - "button"(optional): the index of the button to bind
  411. * - "hat"(optional): the index of the hat to bind as direction buttons
  412. * - "axis"(optional): the index of the axis to bind
  413. * - "direction"(only used for hat): the direction name of the hat to bind. Can be "up",
  414. * "down", "left" or "right"
  415. * - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is
  416. * triggered if the axis value crosses
  417. * - "direction"(only used for axis): "+" means the button is triggered when the axis
  418. * value is greater than the threshold; "-" means the button is triggered when the axis
  419. * value is smaller than the threshold
  420. */
  421. std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override {
  422. const std::string guid = params.Get("guid", "0");
  423. const int port = params.Get("port", 0);
  424. auto joystick = state.GetSDLJoystickByGUID(guid, port);
  425. if (params.Has("hat")) {
  426. const int hat = params.Get("hat", 0);
  427. const std::string direction_name = params.Get("direction", "");
  428. Uint8 direction;
  429. if (direction_name == "up") {
  430. direction = SDL_HAT_UP;
  431. } else if (direction_name == "down") {
  432. direction = SDL_HAT_DOWN;
  433. } else if (direction_name == "left") {
  434. direction = SDL_HAT_LEFT;
  435. } else if (direction_name == "right") {
  436. direction = SDL_HAT_RIGHT;
  437. } else {
  438. direction = 0;
  439. }
  440. // This is necessary so accessing GetHat with hat won't crash
  441. joystick->SetHat(hat, SDL_HAT_CENTERED);
  442. return std::make_unique<SDLDirectionButton>(joystick, hat, direction);
  443. }
  444. if (params.Has("axis")) {
  445. const int axis = params.Get("axis", 0);
  446. const float threshold = params.Get("threshold", 0.5f);
  447. const std::string direction_name = params.Get("direction", "");
  448. bool trigger_if_greater;
  449. if (direction_name == "+") {
  450. trigger_if_greater = true;
  451. } else if (direction_name == "-") {
  452. trigger_if_greater = false;
  453. } else {
  454. trigger_if_greater = true;
  455. LOG_ERROR(Input, "Unknown direction {}", direction_name);
  456. }
  457. // This is necessary so accessing GetAxis with axis won't crash
  458. joystick->SetAxis(axis, 0);
  459. return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater);
  460. }
  461. const int button = params.Get("button", 0);
  462. // This is necessary so accessing GetButton with button won't crash
  463. joystick->SetButton(button, false);
  464. return std::make_unique<SDLButton>(joystick, button);
  465. }
  466. private:
  467. SDLState& state;
  468. };
  469. /// An analog device factory that creates analog devices from SDL joystick
  470. class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> {
  471. public:
  472. explicit SDLAnalogFactory(SDLState& state_) : state(state_) {}
  473. /**
  474. * Creates an analog device from joystick axes
  475. * @param params contains parameters for creating the device:
  476. * - "guid": the guid of the joystick to bind
  477. * - "port": the nth joystick of the same type
  478. * - "axis_x": the index of the axis to be bind as x-axis
  479. * - "axis_y": the index of the axis to be bind as y-axis
  480. */
  481. std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override {
  482. const std::string guid = params.Get("guid", "0");
  483. const int port = params.Get("port", 0);
  484. const int axis_x = params.Get("axis_x", 0);
  485. const int axis_y = params.Get("axis_y", 1);
  486. const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
  487. const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
  488. auto joystick = state.GetSDLJoystickByGUID(guid, port);
  489. // This is necessary so accessing GetAxis with axis_x and axis_y won't crash
  490. joystick->SetAxis(axis_x, 0);
  491. joystick->SetAxis(axis_y, 0);
  492. return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone, range);
  493. }
  494. private:
  495. SDLState& state;
  496. };
  497. /// An vibration device factory that creates vibration devices from SDL joystick
  498. class SDLVibrationFactory final : public Input::Factory<Input::VibrationDevice> {
  499. public:
  500. explicit SDLVibrationFactory(SDLState& state_) : state(state_) {}
  501. /**
  502. * Creates a vibration device from a joystick
  503. * @param params contains parameters for creating the device:
  504. * - "guid": the guid of the joystick to bind
  505. * - "port": the nth joystick of the same type
  506. */
  507. std::unique_ptr<Input::VibrationDevice> Create(const Common::ParamPackage& params) override {
  508. const std::string guid = params.Get("guid", "0");
  509. const int port = params.Get("port", 0);
  510. return std::make_unique<SDLVibration>(state.GetSDLJoystickByGUID(guid, port));
  511. }
  512. private:
  513. SDLState& state;
  514. };
  515. /// A motion device factory that creates motion devices from SDL joystick
  516. class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> {
  517. public:
  518. explicit SDLMotionFactory(SDLState& state_) : state(state_) {}
  519. /**
  520. * Creates motion device from joystick axes
  521. * @param params contains parameters for creating the device:
  522. * - "guid": the guid of the joystick to bind
  523. * - "port": the nth joystick of the same type
  524. */
  525. std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override {
  526. const std::string guid = params.Get("guid", "0");
  527. const int port = params.Get("port", 0);
  528. auto joystick = state.GetSDLJoystickByGUID(guid, port);
  529. if (params.Has("hat")) {
  530. const int hat = params.Get("hat", 0);
  531. const std::string direction_name = params.Get("direction", "");
  532. Uint8 direction;
  533. if (direction_name == "up") {
  534. direction = SDL_HAT_UP;
  535. } else if (direction_name == "down") {
  536. direction = SDL_HAT_DOWN;
  537. } else if (direction_name == "left") {
  538. direction = SDL_HAT_LEFT;
  539. } else if (direction_name == "right") {
  540. direction = SDL_HAT_RIGHT;
  541. } else {
  542. direction = 0;
  543. }
  544. // This is necessary so accessing GetHat with hat won't crash
  545. joystick->SetHat(hat, SDL_HAT_CENTERED);
  546. return std::make_unique<SDLDirectionMotion>(joystick, hat, direction);
  547. }
  548. if (params.Has("axis")) {
  549. const int axis = params.Get("axis", 0);
  550. const float threshold = params.Get("threshold", 0.5f);
  551. const std::string direction_name = params.Get("direction", "");
  552. bool trigger_if_greater;
  553. if (direction_name == "+") {
  554. trigger_if_greater = true;
  555. } else if (direction_name == "-") {
  556. trigger_if_greater = false;
  557. } else {
  558. trigger_if_greater = true;
  559. LOG_ERROR(Input, "Unknown direction {}", direction_name);
  560. }
  561. // This is necessary so accessing GetAxis with axis won't crash
  562. joystick->SetAxis(axis, 0);
  563. return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater);
  564. }
  565. const int button = params.Get("button", 0);
  566. // This is necessary so accessing GetButton with button won't crash
  567. joystick->SetButton(button, false);
  568. return std::make_unique<SDLButtonMotion>(joystick, button);
  569. }
  570. private:
  571. SDLState& state;
  572. };
  573. SDLState::SDLState() {
  574. using namespace Input;
  575. button_factory = std::make_shared<SDLButtonFactory>(*this);
  576. analog_factory = std::make_shared<SDLAnalogFactory>(*this);
  577. vibration_factory = std::make_shared<SDLVibrationFactory>(*this);
  578. motion_factory = std::make_shared<SDLMotionFactory>(*this);
  579. RegisterFactory<ButtonDevice>("sdl", button_factory);
  580. RegisterFactory<AnalogDevice>("sdl", analog_factory);
  581. RegisterFactory<VibrationDevice>("sdl", vibration_factory);
  582. RegisterFactory<MotionDevice>("sdl", motion_factory);
  583. // If the frontend is going to manage the event loop, then we don't start one here
  584. start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0;
  585. if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) {
  586. LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
  587. return;
  588. }
  589. has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0;
  590. if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
  591. LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
  592. }
  593. SDL_AddEventWatch(&SDLEventWatcher, this);
  594. initialized = true;
  595. if (start_thread) {
  596. poll_thread = std::thread([this] {
  597. using namespace std::chrono_literals;
  598. while (initialized) {
  599. SDL_PumpEvents();
  600. std::this_thread::sleep_for(1ms);
  601. }
  602. });
  603. }
  604. // Because the events for joystick connection happens before we have our event watcher added, we
  605. // can just open all the joysticks right here
  606. for (int i = 0; i < SDL_NumJoysticks(); ++i) {
  607. InitJoystick(i);
  608. }
  609. }
  610. SDLState::~SDLState() {
  611. using namespace Input;
  612. UnregisterFactory<ButtonDevice>("sdl");
  613. UnregisterFactory<AnalogDevice>("sdl");
  614. UnregisterFactory<VibrationDevice>("sdl");
  615. UnregisterFactory<MotionDevice>("sdl");
  616. CloseJoysticks();
  617. SDL_DelEventWatch(&SDLEventWatcher, this);
  618. initialized = false;
  619. if (start_thread) {
  620. poll_thread.join();
  621. SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
  622. }
  623. }
  624. std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
  625. std::scoped_lock lock(joystick_map_mutex);
  626. std::vector<Common::ParamPackage> devices;
  627. for (const auto& [key, value] : joystick_map) {
  628. for (const auto& joystick : value) {
  629. if (auto* const controller = joystick->GetSDLGameController()) {
  630. std::string name =
  631. fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
  632. devices.emplace_back(Common::ParamPackage{
  633. {"class", "sdl"},
  634. {"display", std::move(name)},
  635. {"guid", joystick->GetGUID()},
  636. {"port", std::to_string(joystick->GetPort())},
  637. });
  638. } else if (auto* const joy = joystick->GetSDLJoystick()) {
  639. std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort());
  640. devices.emplace_back(Common::ParamPackage{
  641. {"class", "sdl"},
  642. {"display", std::move(name)},
  643. {"guid", joystick->GetGUID()},
  644. {"port", std::to_string(joystick->GetPort())},
  645. });
  646. }
  647. }
  648. }
  649. return devices;
  650. }
  651. namespace {
  652. Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis,
  653. float value = 0.1f) {
  654. Common::ParamPackage params({{"engine", "sdl"}});
  655. params.Set("port", port);
  656. params.Set("guid", std::move(guid));
  657. params.Set("axis", axis);
  658. if (value > 0) {
  659. params.Set("direction", "+");
  660. params.Set("threshold", "0.5");
  661. } else {
  662. params.Set("direction", "-");
  663. params.Set("threshold", "-0.5");
  664. }
  665. return params;
  666. }
  667. Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, s32 button) {
  668. Common::ParamPackage params({{"engine", "sdl"}});
  669. params.Set("port", port);
  670. params.Set("guid", std::move(guid));
  671. params.Set("button", button);
  672. return params;
  673. }
  674. Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat, s32 value) {
  675. Common::ParamPackage params({{"engine", "sdl"}});
  676. params.Set("port", port);
  677. params.Set("guid", std::move(guid));
  678. params.Set("hat", hat);
  679. switch (value) {
  680. case SDL_HAT_UP:
  681. params.Set("direction", "up");
  682. break;
  683. case SDL_HAT_DOWN:
  684. params.Set("direction", "down");
  685. break;
  686. case SDL_HAT_LEFT:
  687. params.Set("direction", "left");
  688. break;
  689. case SDL_HAT_RIGHT:
  690. params.Set("direction", "right");
  691. break;
  692. default:
  693. return {};
  694. }
  695. return params;
  696. }
  697. Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
  698. switch (event.type) {
  699. case SDL_JOYAXISMOTION: {
  700. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
  701. return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  702. static_cast<s32>(event.jaxis.axis),
  703. event.jaxis.value);
  704. }
  705. break;
  706. }
  707. case SDL_JOYBUTTONUP: {
  708. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) {
  709. return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  710. static_cast<s32>(event.jbutton.button));
  711. }
  712. break;
  713. }
  714. case SDL_JOYHATMOTION: {
  715. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) {
  716. return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  717. static_cast<s32>(event.jhat.hat),
  718. static_cast<s32>(event.jhat.value));
  719. }
  720. break;
  721. }
  722. }
  723. return {};
  724. }
  725. Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) {
  726. switch (event.type) {
  727. case SDL_JOYAXISMOTION: {
  728. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
  729. return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  730. static_cast<s32>(event.jaxis.axis),
  731. event.jaxis.value);
  732. }
  733. break;
  734. }
  735. case SDL_JOYBUTTONUP: {
  736. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) {
  737. return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  738. static_cast<s32>(event.jbutton.button));
  739. }
  740. break;
  741. }
  742. case SDL_JOYHATMOTION: {
  743. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) {
  744. return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
  745. static_cast<s32>(event.jhat.hat),
  746. static_cast<s32>(event.jhat.value));
  747. }
  748. break;
  749. }
  750. }
  751. return {};
  752. }
  753. Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
  754. const SDL_GameControllerButtonBind& binding) {
  755. switch (binding.bindType) {
  756. case SDL_CONTROLLER_BINDTYPE_NONE:
  757. break;
  758. case SDL_CONTROLLER_BINDTYPE_AXIS:
  759. return BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
  760. case SDL_CONTROLLER_BINDTYPE_BUTTON:
  761. return BuildButtonParamPackageForButton(port, guid, binding.value.button);
  762. case SDL_CONTROLLER_BINDTYPE_HAT:
  763. return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
  764. binding.value.hat.hat_mask);
  765. }
  766. return {};
  767. }
  768. Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x,
  769. int axis_y) {
  770. Common::ParamPackage params;
  771. params.Set("engine", "sdl");
  772. params.Set("port", port);
  773. params.Set("guid", guid);
  774. params.Set("axis_x", axis_x);
  775. params.Set("axis_y", axis_y);
  776. return params;
  777. }
  778. } // Anonymous namespace
  779. ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) {
  780. if (!params.Has("guid") || !params.Has("port")) {
  781. return {};
  782. }
  783. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  784. auto* controller = joystick->GetSDLGameController();
  785. if (controller == nullptr) {
  786. return {};
  787. }
  788. // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
  789. // We will add those afterwards
  790. // This list also excludes Screenshot since theres not really a mapping for that
  791. using ButtonBindings =
  792. std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
  793. static constexpr ButtonBindings switch_to_sdl_button{{
  794. {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
  795. {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
  796. {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
  797. {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
  798. {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
  799. {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
  800. {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  801. {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  802. {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
  803. {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
  804. {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
  805. {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
  806. {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
  807. {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
  808. {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  809. {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  810. {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
  811. }};
  812. // Add the missing bindings for ZL/ZR
  813. using ZBindings =
  814. std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
  815. static constexpr ZBindings switch_to_sdl_axis{{
  816. {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
  817. {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
  818. }};
  819. ButtonMapping mapping;
  820. mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
  821. for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
  822. const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
  823. mapping.insert_or_assign(
  824. switch_button,
  825. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  826. }
  827. for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
  828. const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
  829. mapping.insert_or_assign(
  830. switch_button,
  831. BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
  832. }
  833. return mapping;
  834. }
  835. AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
  836. if (!params.Has("guid") || !params.Has("port")) {
  837. return {};
  838. }
  839. const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
  840. auto* controller = joystick->GetSDLGameController();
  841. if (controller == nullptr) {
  842. return {};
  843. }
  844. AnalogMapping mapping = {};
  845. const auto& binding_left_x =
  846. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
  847. const auto& binding_left_y =
  848. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
  849. mapping.insert_or_assign(Settings::NativeAnalog::LStick,
  850. BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
  851. binding_left_x.value.axis,
  852. binding_left_y.value.axis));
  853. const auto& binding_right_x =
  854. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
  855. const auto& binding_right_y =
  856. SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
  857. mapping.insert_or_assign(Settings::NativeAnalog::RStick,
  858. BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
  859. binding_right_x.value.axis,
  860. binding_right_y.value.axis));
  861. return mapping;
  862. }
  863. namespace Polling {
  864. class SDLPoller : public InputCommon::Polling::DevicePoller {
  865. public:
  866. explicit SDLPoller(SDLState& state_) : state(state_) {}
  867. void Start([[maybe_unused]] const std::string& device_id) override {
  868. state.event_queue.Clear();
  869. state.polling = true;
  870. }
  871. void Stop() override {
  872. state.polling = false;
  873. }
  874. protected:
  875. SDLState& state;
  876. };
  877. class SDLButtonPoller final : public SDLPoller {
  878. public:
  879. explicit SDLButtonPoller(SDLState& state_) : SDLPoller(state_) {}
  880. Common::ParamPackage GetNextInput() override {
  881. SDL_Event event;
  882. while (state.event_queue.Pop(event)) {
  883. const auto package = FromEvent(event);
  884. if (package) {
  885. return *package;
  886. }
  887. }
  888. return {};
  889. }
  890. [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
  891. switch (event.type) {
  892. case SDL_JOYAXISMOTION:
  893. if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
  894. break;
  895. }
  896. [[fallthrough]];
  897. case SDL_JOYBUTTONUP:
  898. case SDL_JOYHATMOTION:
  899. return {SDLEventToButtonParamPackage(state, event)};
  900. }
  901. return std::nullopt;
  902. }
  903. };
  904. class SDLMotionPoller final : public SDLPoller {
  905. public:
  906. explicit SDLMotionPoller(SDLState& state_) : SDLPoller(state_) {}
  907. Common::ParamPackage GetNextInput() override {
  908. SDL_Event event;
  909. while (state.event_queue.Pop(event)) {
  910. const auto package = FromEvent(event);
  911. if (package) {
  912. return *package;
  913. }
  914. }
  915. return {};
  916. }
  917. [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
  918. switch (event.type) {
  919. case SDL_JOYAXISMOTION:
  920. if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
  921. break;
  922. }
  923. [[fallthrough]];
  924. case SDL_JOYBUTTONUP:
  925. case SDL_JOYHATMOTION:
  926. return {SDLEventToMotionParamPackage(state, event)};
  927. }
  928. return std::nullopt;
  929. }
  930. };
  931. /**
  932. * Attempts to match the press to a controller joy axis (left/right stick) and if a match
  933. * isn't found, checks if the event matches anything from SDLButtonPoller and uses that
  934. * instead
  935. */
  936. class SDLAnalogPreferredPoller final : public SDLPoller {
  937. public:
  938. explicit SDLAnalogPreferredPoller(SDLState& state_)
  939. : SDLPoller(state_), button_poller(state_) {}
  940. void Start(const std::string& device_id) override {
  941. SDLPoller::Start(device_id);
  942. // Reset stored axes
  943. analog_x_axis = -1;
  944. analog_y_axis = -1;
  945. }
  946. Common::ParamPackage GetNextInput() override {
  947. SDL_Event event;
  948. while (state.event_queue.Pop(event)) {
  949. // Filter out axis events that are below a threshold
  950. if (event.type == SDL_JOYAXISMOTION && std::abs(event.jaxis.value / 32767.0) < 0.5) {
  951. continue;
  952. }
  953. if (event.type == SDL_JOYAXISMOTION) {
  954. const auto axis = event.jaxis.axis;
  955. // In order to return a complete analog param, we need inputs for both axes.
  956. // First we take the x-axis (horizontal) input, then the y-axis (vertical) input.
  957. if (analog_x_axis == -1) {
  958. analog_x_axis = axis;
  959. } else if (analog_y_axis == -1 && analog_x_axis != axis) {
  960. analog_y_axis = axis;
  961. }
  962. } else {
  963. // If the press wasn't accepted as a joy axis, check for a button press
  964. auto button_press = button_poller.FromEvent(event);
  965. if (button_press) {
  966. return *button_press;
  967. }
  968. }
  969. }
  970. if (analog_x_axis != -1 && analog_y_axis != -1) {
  971. if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
  972. auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
  973. analog_x_axis, analog_y_axis);
  974. analog_x_axis = -1;
  975. analog_y_axis = -1;
  976. return params;
  977. }
  978. }
  979. return {};
  980. }
  981. private:
  982. int analog_x_axis = -1;
  983. int analog_y_axis = -1;
  984. SDLButtonPoller button_poller;
  985. };
  986. } // namespace Polling
  987. SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
  988. Pollers pollers;
  989. switch (type) {
  990. case InputCommon::Polling::DeviceType::AnalogPreferred:
  991. pollers.emplace_back(std::make_unique<Polling::SDLAnalogPreferredPoller>(*this));
  992. break;
  993. case InputCommon::Polling::DeviceType::Button:
  994. pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
  995. break;
  996. case InputCommon::Polling::DeviceType::Motion:
  997. pollers.emplace_back(std::make_unique<Polling::SDLMotionPoller>(*this));
  998. break;
  999. }
  1000. return pollers;
  1001. }
  1002. } // namespace InputCommon::SDL