Joystick.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812
  1. /**
  2. * Copyright (c) 2006-2022 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. // LOVE
  21. #include "common/config.h"
  22. #include "Joystick.h"
  23. #include "common/int.h"
  24. #include "sensor/sdl/Sensor.h"
  25. // SDL
  26. #include <SDL_version.h>
  27. // C++
  28. #include <algorithm>
  29. #include <limits>
  30. #ifndef SDL_TICKS_PASSED
  31. #define SDL_TICKS_PASSED(A, B) ((Sint32)((B) - (A)) <= 0)
  32. #endif
  33. namespace love
  34. {
  35. namespace joystick
  36. {
  37. namespace sdl
  38. {
  39. Joystick::Joystick(int id)
  40. : joyhandle(nullptr)
  41. , controller(nullptr)
  42. , haptic(nullptr)
  43. , instanceid(-1)
  44. , id(id)
  45. , vibration()
  46. {
  47. }
  48. Joystick::Joystick(int id, int joyindex)
  49. : joyhandle(nullptr)
  50. , controller(nullptr)
  51. , haptic(nullptr)
  52. , instanceid(-1)
  53. , id(id)
  54. , vibration()
  55. {
  56. open(joyindex);
  57. }
  58. Joystick::~Joystick()
  59. {
  60. close();
  61. }
  62. bool Joystick::open(int deviceindex)
  63. {
  64. close();
  65. joyhandle = SDL_JoystickOpen(deviceindex);
  66. if (joyhandle)
  67. {
  68. instanceid = SDL_JoystickInstanceID(joyhandle);
  69. // SDL_JoystickGetGUIDString uses 32 bytes plus the null terminator.
  70. char cstr[33];
  71. SDL_JoystickGUID sdlguid = SDL_JoystickGetGUID(joyhandle);
  72. SDL_JoystickGetGUIDString(sdlguid, cstr, (int) sizeof(cstr));
  73. pguid = std::string(cstr);
  74. // See if SDL thinks this is a Game Controller.
  75. openGamepad(deviceindex);
  76. // Prefer the Joystick name for consistency.
  77. const char *joyname = SDL_JoystickName(joyhandle);
  78. if (!joyname && controller)
  79. joyname = SDL_GameControllerName(controller);
  80. if (joyname)
  81. name = joyname;
  82. }
  83. return isConnected();
  84. }
  85. void Joystick::close()
  86. {
  87. if (haptic)
  88. SDL_HapticClose(haptic);
  89. if (controller)
  90. SDL_GameControllerClose(controller);
  91. if (joyhandle)
  92. SDL_JoystickClose(joyhandle);
  93. joyhandle = nullptr;
  94. controller = nullptr;
  95. haptic = nullptr;
  96. instanceid = -1;
  97. vibration = Vibration();
  98. }
  99. bool Joystick::isConnected() const
  100. {
  101. return joyhandle != nullptr && SDL_JoystickGetAttached(joyhandle);
  102. }
  103. const char *Joystick::getName() const
  104. {
  105. return name.c_str();
  106. }
  107. int Joystick::getAxisCount() const
  108. {
  109. return isConnected() ? SDL_JoystickNumAxes(joyhandle) : 0;
  110. }
  111. int Joystick::getButtonCount() const
  112. {
  113. return isConnected() ? SDL_JoystickNumButtons(joyhandle) : 0;
  114. }
  115. int Joystick::getHatCount() const
  116. {
  117. return isConnected() ? SDL_JoystickNumHats(joyhandle) : 0;
  118. }
  119. float Joystick::getAxis(int axisindex) const
  120. {
  121. if (!isConnected() || axisindex < 0 || axisindex >= getAxisCount())
  122. return 0;
  123. return clampval(((float) SDL_JoystickGetAxis(joyhandle, axisindex))/32768.0f);
  124. }
  125. std::vector<float> Joystick::getAxes() const
  126. {
  127. std::vector<float> axes;
  128. int count = getAxisCount();
  129. if (!isConnected() || count <= 0)
  130. return axes;
  131. axes.reserve(count);
  132. for (int i = 0; i < count; i++)
  133. axes.push_back(clampval(((float) SDL_JoystickGetAxis(joyhandle, i))/32768.0f));
  134. return axes;
  135. }
  136. Joystick::Hat Joystick::getHat(int hatindex) const
  137. {
  138. Hat h = HAT_INVALID;
  139. if (!isConnected() || hatindex < 0 || hatindex >= getHatCount())
  140. return h;
  141. getConstant(SDL_JoystickGetHat(joyhandle, hatindex), h);
  142. return h;
  143. }
  144. bool Joystick::isDown(const std::vector<int> &buttonlist) const
  145. {
  146. if (!isConnected())
  147. return false;
  148. int numbuttons = getButtonCount();
  149. for (int button : buttonlist)
  150. {
  151. if (button < 0 || button >= numbuttons)
  152. continue;
  153. if (SDL_JoystickGetButton(joyhandle, button) == 1)
  154. return true;
  155. }
  156. return false;
  157. }
  158. void Joystick::setPlayerIndex(int index)
  159. {
  160. if (!isConnected())
  161. return;
  162. #if SDL_VERSION_ATLEAST(2, 0, 12)
  163. SDL_JoystickSetPlayerIndex(joyhandle, index);
  164. #else
  165. LOVE_UNUSED(index);
  166. #endif
  167. }
  168. int Joystick::getPlayerIndex() const
  169. {
  170. if (!isConnected())
  171. return -1;
  172. #if SDL_VERSION_ATLEAST(2, 0, 12)
  173. return SDL_JoystickGetPlayerIndex(joyhandle);
  174. #else
  175. return -1;
  176. #endif
  177. }
  178. bool Joystick::openGamepad(int deviceindex)
  179. {
  180. if (!SDL_IsGameController(deviceindex))
  181. return false;
  182. if (isGamepad())
  183. {
  184. SDL_GameControllerClose(controller);
  185. controller = nullptr;
  186. }
  187. controller = SDL_GameControllerOpen(deviceindex);
  188. return isGamepad();
  189. }
  190. bool Joystick::isGamepad() const
  191. {
  192. return controller != nullptr;
  193. }
  194. Joystick::GamepadType Joystick::getGamepadType() const
  195. {
  196. if (controller == nullptr)
  197. return GAMEPAD_TYPE_UNKNOWN;
  198. #if SDL_VERSION_ATLEAST(2, 0, 12)
  199. switch (SDL_GameControllerGetType(controller))
  200. {
  201. case SDL_CONTROLLER_TYPE_UNKNOWN: return GAMEPAD_TYPE_UNKNOWN;
  202. case SDL_CONTROLLER_TYPE_XBOX360: return GAMEPAD_TYPE_XBOX360;
  203. case SDL_CONTROLLER_TYPE_XBOXONE: return GAMEPAD_TYPE_XBOXONE;
  204. case SDL_CONTROLLER_TYPE_PS3: return GAMEPAD_TYPE_PS3;
  205. case SDL_CONTROLLER_TYPE_PS4: return GAMEPAD_TYPE_PS4;
  206. case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO: return GAMEPAD_TYPE_NINTENDO_SWITCH_PRO;
  207. #if SDL_VERSION_ATLEAST(2, 0, 14)
  208. case SDL_CONTROLLER_TYPE_VIRTUAL: return GAMEPAD_TYPE_VIRTUAL;
  209. case SDL_CONTROLLER_TYPE_PS5: return GAMEPAD_TYPE_PS5;
  210. #endif
  211. #if SDL_VERSION_ATLEAST(2, 0, 16)
  212. case SDL_CONTROLLER_TYPE_AMAZON_LUNA: return GAMEPAD_TYPE_AMAZON_LUNA;
  213. case SDL_CONTROLLER_TYPE_GOOGLE_STADIA: return GAMEPAD_TYPE_STADIA;
  214. #endif
  215. #if SDL_VERSION_ATLEAST(2, 24, 0)
  216. case SDL_CONTROLLER_TYPE_NVIDIA_SHIELD: return GAMEPAD_TYPE_NVIDIA_SHIELD;
  217. case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT: return GAMEPAD_TYPE_JOYCON_LEFT;
  218. case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT: return GAMEPAD_TYPE_JOYCON_RIGHT;
  219. case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR: return GAMEPAD_TYPE_JOYCON_PAIR;
  220. #endif
  221. }
  222. #endif
  223. return GAMEPAD_TYPE_UNKNOWN;
  224. }
  225. float Joystick::getGamepadAxis(love::joystick::Joystick::GamepadAxis axis) const
  226. {
  227. if (!isConnected() || !isGamepad())
  228. return 0.f;
  229. SDL_GameControllerAxis sdlaxis;
  230. if (!getConstant(axis, sdlaxis))
  231. return 0.f;
  232. Sint16 value = SDL_GameControllerGetAxis(controller, sdlaxis);
  233. return clampval((float) value / 32768.0f);
  234. }
  235. bool Joystick::isGamepadDown(const std::vector<GamepadButton> &blist) const
  236. {
  237. if (!isConnected() || !isGamepad())
  238. return false;
  239. SDL_GameControllerButton sdlbutton;
  240. for (GamepadButton button : blist)
  241. {
  242. if (!getConstant(button, sdlbutton))
  243. continue;
  244. if (SDL_GameControllerGetButton(controller, sdlbutton) == 1)
  245. return true;
  246. }
  247. return false;
  248. }
  249. Joystick::JoystickInput Joystick::getGamepadMapping(const GamepadInput &input) const
  250. {
  251. Joystick::JoystickInput jinput;
  252. jinput.type = INPUT_TYPE_MAX_ENUM;
  253. if (!isGamepad())
  254. return jinput;
  255. SDL_GameControllerButtonBind sdlbind = {};
  256. sdlbind.bindType = SDL_CONTROLLER_BINDTYPE_NONE;
  257. SDL_GameControllerButton sdlbutton;
  258. SDL_GameControllerAxis sdlaxis;
  259. switch (input.type)
  260. {
  261. case INPUT_TYPE_BUTTON:
  262. if (getConstant(input.button, sdlbutton))
  263. sdlbind = SDL_GameControllerGetBindForButton(controller, sdlbutton);
  264. break;
  265. case INPUT_TYPE_AXIS:
  266. if (getConstant(input.axis, sdlaxis))
  267. sdlbind = SDL_GameControllerGetBindForAxis(controller, sdlaxis);
  268. break;
  269. default:
  270. break;
  271. }
  272. switch (sdlbind.bindType)
  273. {
  274. case SDL_CONTROLLER_BINDTYPE_BUTTON:
  275. jinput.type = INPUT_TYPE_BUTTON;
  276. jinput.button = sdlbind.value.button;
  277. break;
  278. case SDL_CONTROLLER_BINDTYPE_AXIS:
  279. jinput.type = INPUT_TYPE_AXIS;
  280. jinput.axis = sdlbind.value.axis;
  281. break;
  282. case SDL_CONTROLLER_BINDTYPE_HAT:
  283. if (getConstant(sdlbind.value.hat.hat_mask, jinput.hat.value))
  284. {
  285. jinput.type = INPUT_TYPE_HAT;
  286. jinput.hat.index = sdlbind.value.hat.hat;
  287. }
  288. break;
  289. case SDL_CONTROLLER_BINDTYPE_NONE:
  290. default:
  291. break;
  292. }
  293. return jinput;
  294. }
  295. std::string Joystick::getGamepadMappingString() const
  296. {
  297. char *sdlmapping = nullptr;
  298. if (controller != nullptr)
  299. sdlmapping = SDL_GameControllerMapping(controller);
  300. if (sdlmapping == nullptr)
  301. {
  302. SDL_JoystickGUID sdlguid = SDL_JoystickGetGUIDFromString(pguid.c_str());
  303. sdlmapping = SDL_GameControllerMappingForGUID(sdlguid);
  304. }
  305. if (sdlmapping == nullptr)
  306. return "";
  307. std::string mappingstr(sdlmapping);
  308. SDL_free(sdlmapping);
  309. // Matches SDL_GameControllerAddMappingsFromRW.
  310. if (mappingstr.find_last_of(',') != mappingstr.length() - 1)
  311. mappingstr += ",";
  312. mappingstr += "platform:" + std::string(SDL_GetPlatform());
  313. return mappingstr;
  314. }
  315. void *Joystick::getHandle() const
  316. {
  317. return joyhandle;
  318. }
  319. std::string Joystick::getGUID() const
  320. {
  321. // SDL2's GUIDs identify *classes* of devices, instead of unique devices.
  322. return pguid;
  323. }
  324. int Joystick::getInstanceID() const
  325. {
  326. return instanceid;
  327. }
  328. int Joystick::getID() const
  329. {
  330. return id;
  331. }
  332. void Joystick::getDeviceInfo(int &vendorID, int &productID, int &productVersion) const
  333. {
  334. if (joyhandle != nullptr)
  335. {
  336. vendorID = SDL_JoystickGetVendor(joyhandle);
  337. productID = SDL_JoystickGetProduct(joyhandle);
  338. productVersion = SDL_JoystickGetProductVersion(joyhandle);
  339. }
  340. else
  341. {
  342. vendorID = 0;
  343. productID = 0;
  344. productVersion = 0;
  345. }
  346. }
  347. bool Joystick::checkCreateHaptic()
  348. {
  349. if (!isConnected())
  350. return false;
  351. if (!SDL_WasInit(SDL_INIT_HAPTIC) && SDL_InitSubSystem(SDL_INIT_HAPTIC) < 0)
  352. return false;
  353. if (haptic && SDL_HapticIndex(haptic) != -1)
  354. return true;
  355. if (haptic)
  356. {
  357. SDL_HapticClose(haptic);
  358. haptic = nullptr;
  359. }
  360. haptic = SDL_HapticOpenFromJoystick(joyhandle);
  361. vibration = Vibration();
  362. return haptic != nullptr;
  363. }
  364. bool Joystick::isVibrationSupported()
  365. {
  366. #if SDL_VERSION_ATLEAST(2, 0, 18)
  367. if (isConnected() && SDL_JoystickHasRumble(joyhandle) == SDL_TRUE)
  368. return true;
  369. #endif
  370. if (!checkCreateHaptic())
  371. return false;
  372. unsigned int features = SDL_HapticQuery(haptic);
  373. if ((features & SDL_HAPTIC_LEFTRIGHT) != 0)
  374. return true;
  375. // Some gamepad drivers only support left/right motors via a custom effect.
  376. if (isGamepad() && (features & SDL_HAPTIC_CUSTOM) != 0)
  377. return true;
  378. // Test for simple sine wave support as a last resort.
  379. if ((features & SDL_HAPTIC_SINE) != 0)
  380. return true;
  381. return false;
  382. }
  383. bool Joystick::runVibrationEffect()
  384. {
  385. if (vibration.id != -1)
  386. {
  387. if (SDL_HapticUpdateEffect(haptic, vibration.id, &vibration.effect) == 0)
  388. {
  389. if (SDL_HapticRunEffect(haptic, vibration.id, 1) == 0)
  390. return true;
  391. }
  392. // If the effect fails to update, we should destroy and re-create it.
  393. SDL_HapticDestroyEffect(haptic, vibration.id);
  394. vibration.id = -1;
  395. }
  396. vibration.id = SDL_HapticNewEffect(haptic, &vibration.effect);
  397. if (vibration.id != -1 && SDL_HapticRunEffect(haptic, vibration.id, 1) == 0)
  398. return true;
  399. return false;
  400. }
  401. bool Joystick::setVibration(float left, float right, float duration)
  402. {
  403. left = std::min(std::max(left, 0.0f), 1.0f);
  404. right = std::min(std::max(right, 0.0f), 1.0f);
  405. if (left == 0.0f && right == 0.0f)
  406. return setVibration();
  407. if (!isConnected())
  408. {
  409. vibration.left = vibration.right = 0.0f;
  410. vibration.endtime = SDL_HAPTIC_INFINITY;
  411. return false;
  412. }
  413. Uint32 length = SDL_HAPTIC_INFINITY;
  414. if (duration >= 0.0f)
  415. {
  416. float maxduration = (float) (std::numeric_limits<Uint32>::max() / 1000.0);
  417. length = Uint32(std::min(duration, maxduration) * 1000);
  418. }
  419. bool success = false;
  420. if (SDL_JoystickRumble(joyhandle, (Uint16)(left * LOVE_UINT16_MAX), (Uint16)(right * LOVE_UINT16_MAX), length) == 0)
  421. success = true;
  422. if (!success && !checkCreateHaptic())
  423. return false;
  424. unsigned int features = SDL_HapticQuery(haptic);
  425. int axes = SDL_HapticNumAxes(haptic);
  426. if (!success && (features & SDL_HAPTIC_LEFTRIGHT) != 0)
  427. {
  428. memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
  429. vibration.effect.type = SDL_HAPTIC_LEFTRIGHT;
  430. vibration.effect.leftright.length = length;
  431. vibration.effect.leftright.large_magnitude = Uint16(left * LOVE_UINT16_MAX);
  432. vibration.effect.leftright.small_magnitude = Uint16(right * LOVE_UINT16_MAX);
  433. success = runVibrationEffect();
  434. }
  435. // Some gamepad drivers only give support for controlling individual motors
  436. // through a custom FF effect.
  437. if (!success && isGamepad() && (features & SDL_HAPTIC_CUSTOM) && axes == 2)
  438. {
  439. // NOTE: this may cause issues with drivers which support custom effects
  440. // but aren't similar to https://github.com/d235j/360Controller .
  441. // Custom effect data is clamped to 0x7FFF in SDL.
  442. vibration.data[0] = vibration.data[2] = Uint16(left * 0x7FFF);
  443. vibration.data[1] = vibration.data[3] = Uint16(right * 0x7FFF);
  444. memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
  445. vibration.effect.type = SDL_HAPTIC_CUSTOM;
  446. vibration.effect.custom.length = length;
  447. vibration.effect.custom.channels = 2;
  448. vibration.effect.custom.period = 10;
  449. vibration.effect.custom.samples = 2;
  450. vibration.effect.custom.data = vibration.data;
  451. success = runVibrationEffect();
  452. }
  453. // Fall back to a simple sine wave if all else fails. This only supports a
  454. // single strength value.
  455. if (!success && (features & SDL_HAPTIC_SINE) != 0)
  456. {
  457. memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
  458. vibration.effect.type = SDL_HAPTIC_SINE;
  459. vibration.effect.periodic.length = length;
  460. vibration.effect.periodic.period = 10;
  461. float strength = std::max(left, right);
  462. vibration.effect.periodic.magnitude = Sint16(strength * 0x7FFF);
  463. success = runVibrationEffect();
  464. }
  465. if (success)
  466. {
  467. vibration.left = left;
  468. vibration.right = right;
  469. if (length == SDL_HAPTIC_INFINITY)
  470. vibration.endtime = SDL_HAPTIC_INFINITY;
  471. else
  472. vibration.endtime = SDL_GetTicks() + length;
  473. }
  474. else
  475. {
  476. vibration.left = vibration.right = 0.0f;
  477. vibration.endtime = SDL_HAPTIC_INFINITY;
  478. }
  479. return success;
  480. }
  481. bool Joystick::setVibration()
  482. {
  483. bool success = false;
  484. if (!success)
  485. success = isConnected() && SDL_JoystickRumble(joyhandle, 0, 0, 0) == 0;
  486. if (!success && SDL_WasInit(SDL_INIT_HAPTIC) && haptic && SDL_HapticIndex(haptic) != -1)
  487. success = (SDL_HapticStopEffect(haptic, vibration.id) == 0);
  488. if (success)
  489. vibration.left = vibration.right = 0.0f;
  490. return success;
  491. }
  492. void Joystick::getVibration(float &left, float &right)
  493. {
  494. if (vibration.endtime != SDL_HAPTIC_INFINITY)
  495. {
  496. // With some drivers, the effect physically stops at the right time, but
  497. // SDL_HapticGetEffectStatus still thinks it's playing. So we explicitly
  498. // stop it once it's done, just to be sure.
  499. if (SDL_TICKS_PASSED(SDL_GetTicks(), vibration.endtime))
  500. {
  501. setVibration();
  502. vibration.endtime = SDL_HAPTIC_INFINITY;
  503. }
  504. }
  505. // Check if the haptic effect has stopped playing.
  506. int id = vibration.id;
  507. if (!haptic || id == -1 || SDL_HapticGetEffectStatus(haptic, id) != 1)
  508. vibration.left = vibration.right = 0.0f;
  509. left = vibration.left;
  510. right = vibration.right;
  511. }
  512. bool Joystick::hasSensor(Sensor::SensorType type) const
  513. {
  514. #if SDL_VERSION_ATLEAST(2, 0, 14) && defined(LOVE_ENABLE_SENSOR)
  515. using SDLSensor = love::sensor::sdl::Sensor;
  516. if (!isGamepad())
  517. return false;
  518. return SDL_GameControllerHasSensor(controller, SDLSensor::convert(type)) == SDL_TRUE;
  519. #else
  520. return false;
  521. #endif
  522. }
  523. bool Joystick::isSensorEnabled(Sensor::SensorType type) const
  524. {
  525. #if SDL_VERSION_ATLEAST(2, 0, 14) && defined(LOVE_ENABLE_SENSOR)
  526. using SDLSensor = love::sensor::sdl::Sensor;
  527. if (!isGamepad())
  528. return false;
  529. return SDL_GameControllerIsSensorEnabled(controller, SDLSensor::convert(type)) == SDL_TRUE;
  530. #else
  531. return false;
  532. #endif
  533. }
  534. void Joystick::setSensorEnabled(Sensor::SensorType type, bool enabled)
  535. {
  536. #if SDL_VERSION_ATLEAST(2, 0, 14) && defined(LOVE_ENABLE_SENSOR)
  537. using SDLSensor = love::sensor::sdl::Sensor;
  538. if (!isGamepad())
  539. throw love::Exception("Sensor is only supported on gamepad");
  540. if (SDL_GameControllerSetSensorEnabled(controller, SDLSensor::convert(type), enabled ? SDL_TRUE : SDL_FALSE) != 0)
  541. {
  542. const char *name = nullptr;
  543. SDLSensor::getConstant(type, name);
  544. throw love::Exception("Could not open \"%s\" SDL gamepad sensor (%s)", name, SDL_GetError());
  545. }
  546. #else
  547. throw love::Exception("Compiled version of SDL or LOVE does not support gamepad sensor");
  548. #endif
  549. }
  550. std::vector<float> Joystick::getSensorData(Sensor::SensorType type) const
  551. {
  552. #if SDL_VERSION_ATLEAST(2, 0, 14) && defined(LOVE_ENABLE_SENSOR)
  553. using SDLSensor = love::sensor::sdl::Sensor;
  554. if (!isGamepad())
  555. throw love::Exception("Sensor is only supported on gamepad");
  556. std::vector<float> data(3);
  557. if (!isSensorEnabled(type))
  558. {
  559. const char *name = nullptr;
  560. SDLSensor::getConstant(type, name);
  561. throw love::Exception("\"%s\" gamepad sensor is not enabled", name);
  562. }
  563. if (SDL_GameControllerGetSensorData(controller, SDLSensor::convert(type), data.data(), (int) data.size()) != 0)
  564. {
  565. const char *name = nullptr;
  566. SDLSensor::getConstant(type, name);
  567. throw love::Exception("Could not get \"%s\" SDL gamepad sensor data (%s)", name, SDL_GetError());
  568. }
  569. return data;
  570. #else
  571. throw love::Exception("Compiled version of SDL or LOVE does not support gamepad sensor");
  572. #endif
  573. }
  574. bool Joystick::getConstant(Uint8 in, Joystick::Hat &out)
  575. {
  576. return hats.find(in, out);
  577. }
  578. bool Joystick::getConstant(Joystick::Hat in, Uint8 &out)
  579. {
  580. return hats.find(in, out);
  581. }
  582. bool Joystick::getConstant(SDL_GameControllerAxis in, Joystick::GamepadAxis &out)
  583. {
  584. return gpAxes.find(in, out);
  585. }
  586. bool Joystick::getConstant(Joystick::GamepadAxis in, SDL_GameControllerAxis &out)
  587. {
  588. return gpAxes.find(in, out);
  589. }
  590. bool Joystick::getConstant(SDL_GameControllerButton in, Joystick::GamepadButton &out)
  591. {
  592. return gpButtons.find(in, out);
  593. }
  594. bool Joystick::getConstant(Joystick::GamepadButton in, SDL_GameControllerButton &out)
  595. {
  596. return gpButtons.find(in, out);
  597. }
  598. EnumMap<Joystick::Hat, Uint8, Joystick::HAT_MAX_ENUM>::Entry Joystick::hatEntries[] =
  599. {
  600. {Joystick::HAT_CENTERED, SDL_HAT_CENTERED},
  601. {Joystick::HAT_UP, SDL_HAT_UP},
  602. {Joystick::HAT_RIGHT, SDL_HAT_RIGHT},
  603. {Joystick::HAT_DOWN, SDL_HAT_DOWN},
  604. {Joystick::HAT_LEFT, SDL_HAT_LEFT},
  605. {Joystick::HAT_RIGHTUP, SDL_HAT_RIGHTUP},
  606. {Joystick::HAT_RIGHTDOWN, SDL_HAT_RIGHTDOWN},
  607. {Joystick::HAT_LEFTUP, SDL_HAT_LEFTUP},
  608. {Joystick::HAT_LEFTDOWN, SDL_HAT_LEFTDOWN},
  609. };
  610. EnumMap<Joystick::Hat, Uint8, Joystick::HAT_MAX_ENUM> Joystick::hats(Joystick::hatEntries, sizeof(Joystick::hatEntries));
  611. EnumMap<Joystick::GamepadAxis, SDL_GameControllerAxis, Joystick::GAMEPAD_AXIS_MAX_ENUM>::Entry Joystick::gpAxisEntries[] =
  612. {
  613. {Joystick::GAMEPAD_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTX},
  614. {Joystick::GAMEPAD_AXIS_LEFTY, SDL_CONTROLLER_AXIS_LEFTY},
  615. {Joystick::GAMEPAD_AXIS_RIGHTX, SDL_CONTROLLER_AXIS_RIGHTX},
  616. {Joystick::GAMEPAD_AXIS_RIGHTY, SDL_CONTROLLER_AXIS_RIGHTY},
  617. {Joystick::GAMEPAD_AXIS_TRIGGERLEFT, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
  618. {Joystick::GAMEPAD_AXIS_TRIGGERRIGHT, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
  619. };
  620. EnumMap<Joystick::GamepadAxis, SDL_GameControllerAxis, Joystick::GAMEPAD_AXIS_MAX_ENUM> Joystick::gpAxes(Joystick::gpAxisEntries, sizeof(Joystick::gpAxisEntries));
  621. EnumMap<Joystick::GamepadButton, SDL_GameControllerButton, Joystick::GAMEPAD_BUTTON_MAX_ENUM>::Entry Joystick::gpButtonEntries[] =
  622. {
  623. {Joystick::GAMEPAD_BUTTON_A, SDL_CONTROLLER_BUTTON_A},
  624. {Joystick::GAMEPAD_BUTTON_B, SDL_CONTROLLER_BUTTON_B},
  625. {Joystick::GAMEPAD_BUTTON_X, SDL_CONTROLLER_BUTTON_X},
  626. {Joystick::GAMEPAD_BUTTON_Y, SDL_CONTROLLER_BUTTON_Y},
  627. {Joystick::GAMEPAD_BUTTON_BACK, SDL_CONTROLLER_BUTTON_BACK},
  628. {Joystick::GAMEPAD_BUTTON_GUIDE, SDL_CONTROLLER_BUTTON_GUIDE},
  629. {Joystick::GAMEPAD_BUTTON_START, SDL_CONTROLLER_BUTTON_START},
  630. {Joystick::GAMEPAD_BUTTON_LEFTSTICK, SDL_CONTROLLER_BUTTON_LEFTSTICK},
  631. {Joystick::GAMEPAD_BUTTON_RIGHTSTICK, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
  632. {Joystick::GAMEPAD_BUTTON_LEFTSHOULDER, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  633. {Joystick::GAMEPAD_BUTTON_RIGHTSHOULDER, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  634. {Joystick::GAMEPAD_BUTTON_DPAD_UP, SDL_CONTROLLER_BUTTON_DPAD_UP},
  635. {Joystick::GAMEPAD_BUTTON_DPAD_DOWN, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
  636. {Joystick::GAMEPAD_BUTTON_DPAD_LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
  637. {Joystick::GAMEPAD_BUTTON_DPAD_RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
  638. #if SDL_VERSION_ATLEAST(2, 0, 14)
  639. {Joystick::GAMEPAD_BUTTON_MISC1, SDL_CONTROLLER_BUTTON_MISC1},
  640. {Joystick::GAMEPAD_BUTTON_PADDLE1, SDL_CONTROLLER_BUTTON_PADDLE1},
  641. {Joystick::GAMEPAD_BUTTON_PADDLE2, SDL_CONTROLLER_BUTTON_PADDLE2},
  642. {Joystick::GAMEPAD_BUTTON_PADDLE3, SDL_CONTROLLER_BUTTON_PADDLE3},
  643. {Joystick::GAMEPAD_BUTTON_PADDLE4, SDL_CONTROLLER_BUTTON_PADDLE4},
  644. {Joystick::GAMEPAD_BUTTON_TOUCHPAD, SDL_CONTROLLER_BUTTON_TOUCHPAD},
  645. #endif
  646. };
  647. EnumMap<Joystick::GamepadButton, SDL_GameControllerButton, Joystick::GAMEPAD_BUTTON_MAX_ENUM> Joystick::gpButtons(Joystick::gpButtonEntries, sizeof(Joystick::gpButtonEntries));
  648. } // sdl
  649. } // joystick
  650. } // love