InputSDL.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. //
  2. // InputSDL.cpp
  3. // konvergo
  4. //
  5. // Created by Lionel CHAZALLON on 16/10/2014.
  6. //
  7. //
  8. #include <QKeyEvent>
  9. #include "InputSDL.h"
  10. #include "QsLog.h"
  11. #include <climits>
  12. #include <cstdlib>
  13. ///////////////////////////////////////////////////////////////////////////////////////////////////
  14. bool InputSDLWorker::initialize()
  15. {
  16. // close if it was previously inited
  17. close();
  18. // init SDL
  19. if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
  20. {
  21. QLOG_ERROR() << "SDL failed to initialize : " << SDL_GetError();
  22. return false;
  23. }
  24. SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
  25. SDL_JoystickEventState(SDL_ENABLE);
  26. refreshJoystickList();
  27. return true;
  28. }
  29. //////////////////////////////////////////////////////////////////////////////////////////////////
  30. void InputSDLWorker::close()
  31. {
  32. if (SDL_WasInit(SDL_INIT_JOYSTICK))
  33. {
  34. QLOG_INFO() << "SDL is closing.";
  35. // we need to close all the openned joysticks here and then exit the thread
  36. for (int joyid = 0; joyid < m_joysticks.size(); joyid++)
  37. SDL_JoystickClose(m_joysticks[joyid]);
  38. SDL_Quit();
  39. }
  40. }
  41. ///////////////////////////////////////////////////////////////////////////////////////////////////
  42. QString InputSDLWorker::nameForId(SDL_JoystickID id)
  43. {
  44. if (m_joysticks.contains(id))
  45. return SDL_JoystickName(m_joysticks[id]);
  46. return "unknown joystick";
  47. }
  48. ///////////////////////////////////////////////////////////////////////////////////////////////////
  49. void InputSDLWorker::run()
  50. {
  51. QElapsedTimer polltimer;
  52. while (true)
  53. {
  54. SDL_Event event;
  55. // startpoint for polling loop
  56. polltimer.restart();
  57. while (SDL_PollEvent(&event))
  58. {
  59. switch (event.type)
  60. {
  61. case SDL_QUIT:
  62. return;
  63. break;
  64. case SDL_JOYBUTTONDOWN:
  65. {
  66. emit receivedInput(nameForId(event.jbutton.which), QString("KEY_BUTTON_%1").arg(event.jbutton.button, true));
  67. break;
  68. }
  69. case SDL_JOYBUTTONUP:
  70. {
  71. emit receivedInput(nameForId(event.jbutton.which), QString("KEY_BUTTON_%1").arg(event.jbutton.button), false);
  72. break;
  73. }
  74. case SDL_JOYDEVICEADDED:
  75. {
  76. QLOG_INFO() << "SDL detected device was added.";
  77. refreshJoystickList();
  78. break;
  79. }
  80. case SDL_JOYDEVICEREMOVED:
  81. {
  82. QLOG_INFO() << "SDL detected device was removed.";
  83. refreshJoystickList();
  84. break;
  85. }
  86. case SDL_JOYHATMOTION:
  87. {
  88. QString hatName("KEY_HAT_");
  89. bool pressed = true;
  90. switch (event.jhat.value)
  91. {
  92. case SDL_HAT_CENTERED:
  93. if (!m_lastHat.isEmpty())
  94. hatName = m_lastHat;
  95. else
  96. hatName += "CENTERED";
  97. pressed = false;
  98. break;
  99. case SDL_HAT_UP:
  100. hatName += "UP";
  101. break;
  102. case SDL_HAT_DOWN:
  103. hatName += "DOWN";
  104. break;
  105. case SDL_HAT_RIGHT:
  106. hatName += "RIGHT";
  107. break;
  108. case SDL_HAT_LEFT:
  109. hatName += "LEFT";
  110. break;
  111. default:
  112. break;
  113. }
  114. m_lastHat = hatName;
  115. emit receivedInput(nameForId(event.jhat.which), hatName, pressed);
  116. break;
  117. }
  118. case SDL_JOYAXISMOTION:
  119. {
  120. auto axis = event.jaxis.axis;
  121. auto value = event.jaxis.value;
  122. QLOG_DEBUG() << "JoyAxisMotion:" << axis << value;
  123. // handle the Digital conversion of the analog axis
  124. if (std::abs(value) > 32768 / 2)
  125. {
  126. bool up = value < 0;
  127. if (!m_axisState.contains(axis))
  128. {
  129. emit receivedInput(nameForId(event.jaxis.which), QString("KEY_AXIS_%1_%2").arg(axis).arg(up ? "UP" : "DOWN"), true);
  130. m_axisState.insert(axis, up);
  131. }
  132. else if (m_axisState.value(axis) != up)
  133. {
  134. emit receivedInput(nameForId(event.jaxis.which), QString("KEY_AXIS_%1_%2").arg(axis).arg(m_axisState.value(axis) ? "UP" : "DOWN"), false);
  135. m_axisState.remove(axis);
  136. }
  137. }
  138. else if (std::abs(value) < 10000 && m_axisState.contains(axis)) // back to the center.
  139. {
  140. emit receivedInput(nameForId(event.jaxis.which), QString("KEY_AXIS_%1_%2").arg(axis).arg(m_axisState.value(axis) ? "UP" : "DOWN"), false);
  141. m_axisState.remove(axis);
  142. }
  143. break;
  144. }
  145. default:
  146. {
  147. QLOG_WARN() << "Unhandled SDL event:" << event.type;
  148. break;
  149. }
  150. }
  151. }
  152. // make the poll time fixed to SDL_POLL_TIME
  153. if (polltimer.elapsed() < SDL_POLL_TIME)
  154. QThread::msleep(SDL_POLL_TIME - polltimer.elapsed());
  155. }
  156. }
  157. //////////////////////////////////////////////////////////////////////////////////////////////////
  158. void InputSDLWorker::refreshJoystickList()
  159. {
  160. // close all openned joysticks
  161. SDLJoystickMapIterator it = m_joysticks.constBegin();
  162. while (it != m_joysticks.constEnd())
  163. {
  164. if (SDL_JoystickGetAttached(m_joysticks[it.key()]))
  165. SDL_JoystickClose(m_joysticks[it.key()]);
  166. it++;
  167. }
  168. m_joysticks.clear();
  169. // list all the joysticks and open them
  170. int numJoysticks = SDL_NumJoysticks();
  171. QLOG_INFO() << "SDL found " << numJoysticks << " joysticks";
  172. for (int joyid = 0; joyid < numJoysticks; joyid++)
  173. {
  174. SDL_Joystick* joystick = SDL_JoystickOpen(joyid);
  175. if (joystick)
  176. {
  177. int instanceid = SDL_JoystickInstanceID(joystick);
  178. QLOG_INFO() << "JoyStick #" << instanceid << " is " << SDL_JoystickName(joystick) << " with "
  179. << SDL_JoystickNumButtons(joystick) << " buttons and " << SDL_JoystickNumAxes(joystick)
  180. << "axes";
  181. m_joysticks[instanceid] = joystick;
  182. m_axisState.clear();
  183. }
  184. }
  185. }
  186. ///////////////////////////////////////////////////////////////////////////////////////////////////
  187. InputSDL::InputSDL(QObject* parent) : InputBase(parent)
  188. {
  189. m_thread = new QThread(this);
  190. m_sdlworker = new InputSDLWorker(nullptr);
  191. m_sdlworker->moveToThread(m_thread);
  192. connect(this, &InputSDL::run, m_sdlworker, &InputSDLWorker::run);
  193. connect(m_sdlworker, &InputSDLWorker::receivedInput, this, &InputBase::receivedInput);
  194. m_thread->start();
  195. }
  196. ///////////////////////////////////////////////////////////////////////////////////////////////////
  197. InputSDL::~InputSDL()
  198. {
  199. close();
  200. if (m_thread->isRunning())
  201. {
  202. m_thread->terminate();
  203. m_thread->wait();
  204. }
  205. }
  206. //////////////////////////////////////////////////////////////////////////////////////////////////
  207. bool InputSDL::initInput()
  208. {
  209. bool retValue;
  210. QMetaObject::invokeMethod(m_sdlworker, "initialize", Qt::BlockingQueuedConnection,
  211. Q_RETURN_ARG(bool, retValue));
  212. if (retValue)
  213. emit run();
  214. return retValue;
  215. }
  216. //////////////////////////////////////////////////////////////////////////////////////////////////
  217. void InputSDL::close()
  218. {
  219. QMetaObject::invokeMethod(m_sdlworker, "close");
  220. }