Joystick.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. /**
  2. * Copyright (c) 2006-2014 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. // C++
  25. #include <algorithm>
  26. #include <limits>
  27. #ifndef SDL_TICKS_PASSED
  28. #define SDL_TICKS_PASSED(A, B) ((Sint32)((B) - (A)) <= 0)
  29. #endif
  30. namespace love
  31. {
  32. namespace joystick
  33. {
  34. namespace sdl
  35. {
  36. Joystick::Joystick(int id)
  37. : joyhandle(nullptr)
  38. , controller(nullptr)
  39. , haptic(nullptr)
  40. , instanceid(-1)
  41. , id(id)
  42. , vibration()
  43. {
  44. }
  45. Joystick::Joystick(int id, int joyindex)
  46. : joyhandle(nullptr)
  47. , controller(nullptr)
  48. , haptic(nullptr)
  49. , instanceid(-1)
  50. , id(id)
  51. , vibration()
  52. {
  53. open(joyindex);
  54. }
  55. Joystick::~Joystick()
  56. {
  57. close();
  58. }
  59. bool Joystick::open(int deviceindex)
  60. {
  61. close();
  62. joyhandle = SDL_JoystickOpen(deviceindex);
  63. if (joyhandle)
  64. {
  65. instanceid = SDL_JoystickInstanceID(joyhandle);
  66. // SDL_JoystickGetGUIDString uses 32 bytes plus the null terminator.
  67. char cstr[33];
  68. SDL_JoystickGUID sdlguid = SDL_JoystickGetGUID(joyhandle);
  69. SDL_JoystickGetGUIDString(sdlguid, cstr, (int) sizeof(cstr));
  70. pguid = std::string(cstr);
  71. // See if SDL thinks this is a Game Controller.
  72. openGamepad(deviceindex);
  73. // Prefer the Joystick name for consistency.
  74. const char *joyname = SDL_JoystickName(joyhandle);
  75. if (!joyname && controller)
  76. joyname = SDL_GameControllerName(controller);
  77. if (joyname)
  78. name = joyname;
  79. }
  80. return isConnected();
  81. }
  82. void Joystick::close()
  83. {
  84. if (haptic)
  85. SDL_HapticClose(haptic);
  86. if (controller)
  87. SDL_GameControllerClose(controller);
  88. if (joyhandle)
  89. SDL_JoystickClose(joyhandle);
  90. joyhandle = nullptr;
  91. controller = nullptr;
  92. haptic = nullptr;
  93. instanceid = -1;
  94. vibration = Vibration();
  95. }
  96. bool Joystick::isConnected() const
  97. {
  98. return joyhandle != nullptr && SDL_JoystickGetAttached(joyhandle);
  99. }
  100. const char *Joystick::getName() const
  101. {
  102. // Use the saved name if this Joystick isn't connected anymore.
  103. if (!isConnected())
  104. return name.c_str();
  105. // Prefer the Joystick name for consistency.
  106. const char *joyname = SDL_JoystickName(joyhandle);
  107. if (!joyname && isGamepad())
  108. joyname = SDL_GameControllerName(controller);
  109. return joyname;
  110. }
  111. int Joystick::getAxisCount() const
  112. {
  113. return isConnected() ? SDL_JoystickNumAxes(joyhandle) : 0;
  114. }
  115. int Joystick::getButtonCount() const
  116. {
  117. return isConnected() ? SDL_JoystickNumButtons(joyhandle) : 0;
  118. }
  119. int Joystick::getHatCount() const
  120. {
  121. return isConnected() ? SDL_JoystickNumHats(joyhandle) : 0;
  122. }
  123. float Joystick::getAxis(int axisindex) const
  124. {
  125. if (!isConnected() || axisindex < 0 || axisindex >= getAxisCount())
  126. return 0;
  127. return clampval(((float) SDL_JoystickGetAxis(joyhandle, axisindex))/32768.0f);
  128. }
  129. std::vector<float> Joystick::getAxes() const
  130. {
  131. std::vector<float> axes;
  132. int count = getAxisCount();
  133. if (!isConnected() || count <= 0)
  134. return axes;
  135. axes.reserve(count);
  136. for (int i = 0; i < count; i++)
  137. axes.push_back(clampval(((float) SDL_JoystickGetAxis(joyhandle, i))/32768.0f));
  138. return axes;
  139. }
  140. Joystick::Hat Joystick::getHat(int hatindex) const
  141. {
  142. Hat h = HAT_INVALID;
  143. if (!isConnected() || hatindex < 0 || hatindex >= getHatCount())
  144. return h;
  145. getConstant(SDL_JoystickGetHat(joyhandle, hatindex), h);
  146. return h;
  147. }
  148. bool Joystick::isDown(const std::vector<int> &buttonlist) const
  149. {
  150. if (!isConnected())
  151. return false;
  152. int num = getButtonCount();
  153. for (size_t i = 0; i < buttonlist.size(); i++)
  154. {
  155. int button = buttonlist[i];
  156. if (button >= 0 && button < num && SDL_JoystickGetButton(joyhandle, button) == 1)
  157. return true;
  158. }
  159. return false;
  160. }
  161. bool Joystick::openGamepad(int deviceindex)
  162. {
  163. if (!SDL_IsGameController(deviceindex))
  164. return false;
  165. if (isGamepad())
  166. {
  167. SDL_GameControllerClose(controller);
  168. controller = nullptr;
  169. }
  170. controller = SDL_GameControllerOpen(deviceindex);
  171. return isGamepad();
  172. }
  173. bool Joystick::isGamepad() const
  174. {
  175. return controller != nullptr;
  176. }
  177. float Joystick::getGamepadAxis(love::joystick::Joystick::GamepadAxis axis) const
  178. {
  179. if (!isConnected() || !isGamepad())
  180. return 0.f;
  181. SDL_GameControllerAxis sdlaxis;
  182. if (!getConstant(axis, sdlaxis))
  183. return 0.f;
  184. Sint16 value = SDL_GameControllerGetAxis(controller, sdlaxis);
  185. return clampval((float) value / 32768.0f);
  186. }
  187. bool Joystick::isGamepadDown(const std::vector<GamepadButton> &blist) const
  188. {
  189. if (!isConnected() || !isGamepad())
  190. return false;
  191. SDL_GameControllerButton sdlbutton;
  192. for (size_t i = 0; i < blist.size(); i++)
  193. {
  194. if (!getConstant(blist[i], sdlbutton))
  195. continue;
  196. if (SDL_GameControllerGetButton(controller, sdlbutton) == 1)
  197. return true;
  198. }
  199. return false;
  200. }
  201. void *Joystick::getHandle() const
  202. {
  203. return joyhandle;
  204. }
  205. std::string Joystick::getGUID() const
  206. {
  207. // SDL2's GUIDs identify *classes* of devices, instead of unique devices.
  208. return pguid;
  209. }
  210. int Joystick::getInstanceID() const
  211. {
  212. return instanceid;
  213. }
  214. int Joystick::getID() const
  215. {
  216. return id;
  217. }
  218. bool Joystick::checkCreateHaptic()
  219. {
  220. if (!isConnected())
  221. return false;
  222. if (!SDL_WasInit(SDL_INIT_HAPTIC) && SDL_InitSubSystem(SDL_INIT_HAPTIC) < 0)
  223. return false;
  224. if (haptic && SDL_HapticIndex(haptic) != -1)
  225. return true;
  226. if (haptic)
  227. {
  228. SDL_HapticClose(haptic);
  229. haptic = nullptr;
  230. }
  231. haptic = SDL_HapticOpenFromJoystick(joyhandle);
  232. vibration = Vibration();
  233. return haptic != nullptr;
  234. }
  235. bool Joystick::isVibrationSupported()
  236. {
  237. if (!checkCreateHaptic())
  238. return false;
  239. unsigned int features = SDL_HapticQuery(haptic);
  240. if ((features & SDL_HAPTIC_LEFTRIGHT) != 0)
  241. return true;
  242. // Some gamepad drivers only support left/right motors via a custom effect.
  243. if (isGamepad() && (features & SDL_HAPTIC_CUSTOM) != 0)
  244. return true;
  245. // Test for simple sine wave support as a last resort.
  246. if ((features & SDL_HAPTIC_SINE) != 0)
  247. return true;
  248. return false;
  249. }
  250. bool Joystick::runVibrationEffect()
  251. {
  252. if (vibration.id != -1)
  253. {
  254. if (SDL_HapticUpdateEffect(haptic, vibration.id, &vibration.effect) == 0)
  255. {
  256. if (SDL_HapticRunEffect(haptic, vibration.id, 1) == 0)
  257. return true;
  258. }
  259. // If the effect fails to update, we should destroy and re-create it.
  260. SDL_HapticDestroyEffect(haptic, vibration.id);
  261. vibration.id = -1;
  262. }
  263. vibration.id = SDL_HapticNewEffect(haptic, &vibration.effect);
  264. if (vibration.id != -1 && SDL_HapticRunEffect(haptic, vibration.id, 1) == 0)
  265. return true;
  266. return false;
  267. }
  268. bool Joystick::setVibration(float left, float right, float duration)
  269. {
  270. left = std::min(std::max(left, 0.0f), 1.0f);
  271. right = std::min(std::max(right, 0.0f), 1.0f);
  272. if (left == 0.0f && right == 0.0f)
  273. return setVibration();
  274. if (!checkCreateHaptic())
  275. return false;
  276. Uint32 length = SDL_HAPTIC_INFINITY;
  277. if (duration >= 0.0f)
  278. {
  279. float maxduration = std::numeric_limits<Uint32>::max() / 1000.0f;
  280. length = Uint32(std::min(duration, maxduration) * 1000);
  281. }
  282. bool success = false;
  283. unsigned int features = SDL_HapticQuery(haptic);
  284. int axes = SDL_HapticNumAxes(haptic);
  285. if ((features & SDL_HAPTIC_LEFTRIGHT) != 0)
  286. {
  287. memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
  288. vibration.effect.type = SDL_HAPTIC_LEFTRIGHT;
  289. vibration.effect.leftright.length = length;
  290. vibration.effect.leftright.large_magnitude = Uint16(left * LOVE_UINT16_MAX);
  291. vibration.effect.leftright.small_magnitude = Uint16(right * LOVE_UINT16_MAX);
  292. success = runVibrationEffect();
  293. }
  294. // Some gamepad drivers only give support for controlling individual motors
  295. // through a custom FF effect.
  296. if (!success && isGamepad() && (features & SDL_HAPTIC_CUSTOM) && axes == 2)
  297. {
  298. // NOTE: this may cause issues with drivers which support custom effects
  299. // but aren't similar to https://github.com/d235j/360Controller .
  300. // Custom effect data is clamped to 0x7FFF in SDL.
  301. vibration.data[0] = vibration.data[2] = Uint16(left * 0x7FFF);
  302. vibration.data[1] = vibration.data[3] = Uint16(right * 0x7FFF);
  303. memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
  304. vibration.effect.type = SDL_HAPTIC_CUSTOM;
  305. vibration.effect.custom.length = length;
  306. vibration.effect.custom.channels = 2;
  307. vibration.effect.custom.period = 10;
  308. vibration.effect.custom.samples = 2;
  309. vibration.effect.custom.data = vibration.data;
  310. success = runVibrationEffect();
  311. }
  312. // Fall back to a simple sine wave if all else fails. This only supports a
  313. // single strength value.
  314. if (!success && (features & SDL_HAPTIC_SINE) != 0)
  315. {
  316. memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
  317. vibration.effect.type = SDL_HAPTIC_SINE;
  318. vibration.effect.periodic.length = length;
  319. vibration.effect.periodic.period = 10;
  320. float strength = std::max(left, right);
  321. vibration.effect.periodic.magnitude = Sint16(strength * 0x7FFF);
  322. success = runVibrationEffect();
  323. }
  324. if (success)
  325. {
  326. vibration.left = left;
  327. vibration.right = right;
  328. if (length == SDL_HAPTIC_INFINITY)
  329. vibration.endtime = SDL_HAPTIC_INFINITY;
  330. else
  331. vibration.endtime = SDL_GetTicks() + length;
  332. }
  333. else
  334. {
  335. vibration.left = vibration.right = 0.0f;
  336. vibration.endtime = SDL_HAPTIC_INFINITY;
  337. }
  338. return success;
  339. }
  340. bool Joystick::setVibration()
  341. {
  342. bool success = true;
  343. if (SDL_WasInit(SDL_INIT_HAPTIC) && haptic && SDL_HapticIndex(haptic) != -1)
  344. success = (SDL_HapticStopEffect(haptic, vibration.id) == 0);
  345. if (success)
  346. vibration.left = vibration.right = 0.0f;
  347. return success;
  348. }
  349. void Joystick::getVibration(float &left, float &right)
  350. {
  351. if (vibration.endtime != SDL_HAPTIC_INFINITY)
  352. {
  353. // With some drivers, the effect physically stops at the right time, but
  354. // SDL_HapticGetEffectStatus still thinks it's playing. So we explicitly
  355. // stop it once it's done, just to be sure.
  356. if (SDL_TICKS_PASSED(SDL_GetTicks(), vibration.endtime))
  357. {
  358. setVibration();
  359. vibration.endtime = SDL_HAPTIC_INFINITY;
  360. }
  361. }
  362. // Check if the haptic effect has stopped playing.
  363. int id = vibration.id;
  364. if (!haptic || id == -1 || SDL_HapticGetEffectStatus(haptic, id) != 1)
  365. vibration.left = vibration.right = 0.0f;
  366. left = vibration.left;
  367. right = vibration.right;
  368. }
  369. bool Joystick::getConstant(Uint8 in, Joystick::Hat &out)
  370. {
  371. return hats.find(in, out);
  372. }
  373. bool Joystick::getConstant(Joystick::Hat in, Uint8 &out)
  374. {
  375. return hats.find(in, out);
  376. }
  377. bool Joystick::getConstant(SDL_GameControllerAxis in, Joystick::GamepadAxis &out)
  378. {
  379. return gpAxes.find(in, out);
  380. }
  381. bool Joystick::getConstant(Joystick::GamepadAxis in, SDL_GameControllerAxis &out)
  382. {
  383. return gpAxes.find(in, out);
  384. }
  385. bool Joystick::getConstant(SDL_GameControllerButton in, Joystick::GamepadButton &out)
  386. {
  387. return gpButtons.find(in, out);
  388. }
  389. bool Joystick::getConstant(Joystick::GamepadButton in, SDL_GameControllerButton &out)
  390. {
  391. return gpButtons.find(in, out);
  392. }
  393. EnumMap<Joystick::Hat, Uint8, Joystick::HAT_MAX_ENUM>::Entry Joystick::hatEntries[] =
  394. {
  395. {Joystick::HAT_CENTERED, SDL_HAT_CENTERED},
  396. {Joystick::HAT_UP, SDL_HAT_UP},
  397. {Joystick::HAT_RIGHT, SDL_HAT_RIGHT},
  398. {Joystick::HAT_DOWN, SDL_HAT_DOWN},
  399. {Joystick::HAT_LEFT, SDL_HAT_LEFT},
  400. {Joystick::HAT_RIGHTUP, SDL_HAT_RIGHTUP},
  401. {Joystick::HAT_RIGHTDOWN, SDL_HAT_RIGHTDOWN},
  402. {Joystick::HAT_LEFTUP, SDL_HAT_LEFTUP},
  403. {Joystick::HAT_LEFTDOWN, SDL_HAT_LEFTDOWN},
  404. };
  405. EnumMap<Joystick::Hat, Uint8, Joystick::HAT_MAX_ENUM> Joystick::hats(Joystick::hatEntries, sizeof(Joystick::hatEntries));
  406. EnumMap<Joystick::GamepadAxis, SDL_GameControllerAxis, Joystick::GAMEPAD_AXIS_MAX_ENUM>::Entry Joystick::gpAxisEntries[] =
  407. {
  408. {Joystick::GAMEPAD_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTX},
  409. {Joystick::GAMEPAD_AXIS_LEFTY, SDL_CONTROLLER_AXIS_LEFTY},
  410. {Joystick::GAMEPAD_AXIS_RIGHTX, SDL_CONTROLLER_AXIS_RIGHTX},
  411. {Joystick::GAMEPAD_AXIS_RIGHTY, SDL_CONTROLLER_AXIS_RIGHTY},
  412. {Joystick::GAMEPAD_AXIS_TRIGGERLEFT, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
  413. {Joystick::GAMEPAD_AXIS_TRIGGERRIGHT, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
  414. };
  415. EnumMap<Joystick::GamepadAxis, SDL_GameControllerAxis, Joystick::GAMEPAD_AXIS_MAX_ENUM> Joystick::gpAxes(Joystick::gpAxisEntries, sizeof(Joystick::gpAxisEntries));
  416. EnumMap<Joystick::GamepadButton, SDL_GameControllerButton, Joystick::GAMEPAD_BUTTON_MAX_ENUM>::Entry Joystick::gpButtonEntries[] =
  417. {
  418. {Joystick::GAMEPAD_BUTTON_A, SDL_CONTROLLER_BUTTON_A},
  419. {Joystick::GAMEPAD_BUTTON_B, SDL_CONTROLLER_BUTTON_B},
  420. {Joystick::GAMEPAD_BUTTON_X, SDL_CONTROLLER_BUTTON_X},
  421. {Joystick::GAMEPAD_BUTTON_Y, SDL_CONTROLLER_BUTTON_Y},
  422. {Joystick::GAMEPAD_BUTTON_BACK, SDL_CONTROLLER_BUTTON_BACK},
  423. {Joystick::GAMEPAD_BUTTON_GUIDE, SDL_CONTROLLER_BUTTON_GUIDE},
  424. {Joystick::GAMEPAD_BUTTON_START, SDL_CONTROLLER_BUTTON_START},
  425. {Joystick::GAMEPAD_BUTTON_LEFTSTICK, SDL_CONTROLLER_BUTTON_LEFTSTICK},
  426. {Joystick::GAMEPAD_BUTTON_RIGHTSTICK, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
  427. {Joystick::GAMEPAD_BUTTON_LEFTSHOULDER, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
  428. {Joystick::GAMEPAD_BUTTON_RIGHTSHOULDER, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
  429. {Joystick::GAMEPAD_BUTTON_DPAD_UP, SDL_CONTROLLER_BUTTON_DPAD_UP},
  430. {Joystick::GAMEPAD_BUTTON_DPAD_DOWN, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
  431. {Joystick::GAMEPAD_BUTTON_DPAD_LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
  432. {Joystick::GAMEPAD_BUTTON_DPAD_RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
  433. };
  434. EnumMap<Joystick::GamepadButton, SDL_GameControllerButton, Joystick::GAMEPAD_BUTTON_MAX_ENUM> Joystick::gpButtons(Joystick::gpButtonEntries, sizeof(Joystick::gpButtonEntries));
  435. } // sdl
  436. } // joystick
  437. } // love