InputSDL.cpp 7.2 KB

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