Joystick.cpp 22 KB

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