sdl_impl.cpp 61 KB

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