Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

sdlinput.cpp 8.9 KiB

11 anni fa
11 anni fa
11 anni fa
11 anni fa
11 anni fa
11 anni fa
11 anni fa
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://www.wtfpl.net/ for more details.
  9. //
  10. #include <lol/engine-internal.h>
  11. #if USE_SDL
  12. # if HAVE_SDL_SDL_H
  13. # include <SDL/SDL.h>
  14. # else
  15. # include <SDL.h>
  16. # endif
  17. #endif
  18. #include "sdlinput.h"
  19. #include "input/input_internal.h"
  20. /* We force joystick polling because no events are received when
  21. * there is no SDL display (eg. on the Raspberry Pi). */
  22. #define SDL_FORCE_POLL_JOYSTICK 1
  23. #if EMSCRIPTEN
  24. #define MOUSE_SPEED_MOD 10.f
  25. #else
  26. #define MOUSE_SPEED_MOD 100.f
  27. #endif
  28. namespace lol
  29. {
  30. /*
  31. * SDL Input implementation class
  32. */
  33. class SdlInputData
  34. {
  35. friend class SdlInput;
  36. private:
  37. void Tick(float seconds);
  38. static ivec2 GetMousePos();
  39. static void SetMousePos(ivec2 position);
  40. #if USE_SDL
  41. SdlInputData(int app_w, int app_h, int screen_w, int screen_h) :
  42. m_prevmouse(ivec2::zero),
  43. m_app(vec2((float)app_w, (float)app_h)),
  44. m_screen(vec2((float)screen_w, (float)screen_h)),
  45. m_mousecapture(false)
  46. { }
  47. array<SDL_Joystick*, InputDeviceInternal*> m_joysticks;
  48. InputDeviceInternal* m_mouse;
  49. InputDeviceInternal* m_keyboard;
  50. ivec2 m_prevmouse;
  51. vec2 m_app;
  52. vec2 m_screen;
  53. bool m_mousecapture;
  54. #endif // USE_SDL
  55. };
  56. /*
  57. * Public SdlInput class
  58. */
  59. SdlInput::SdlInput(int app_w, int app_h, int screen_w, int screen_h)
  60. #if USE_SDL
  61. : m_data(new SdlInputData(app_w, app_h, screen_w, screen_h))
  62. #endif //USE_SDL
  63. {
  64. #if USE_SDL && !USE_SDL2
  65. /* Enable Unicode translation of keyboard events */
  66. SDL_EnableUNICODE(1);
  67. #endif
  68. #if USE_SDL
  69. SDL_Init(SDL_INIT_TIMER | SDL_INIT_JOYSTICK);
  70. m_data->m_keyboard = InputDeviceInternal::CreateStandardKeyboard();
  71. m_data->m_mouse = InputDeviceInternal::CreateStandardMouse();
  72. # if !EMSCRIPTEN
  73. # if SDL_FORCE_POLL_JOYSTICK
  74. SDL_JoystickEventState(SDL_QUERY);
  75. # else
  76. SDL_JoystickEventState(SDL_ENABLE);
  77. # endif //SDL_FORCE_POLL_JOYSTICK
  78. /* Register all the joysticks we can find, and let the input
  79. * system decide what it wants to track. */
  80. for (int i = 0; i < SDL_NumJoysticks(); i++)
  81. {
  82. SDL_Joystick *sdlstick = SDL_JoystickOpen(i);
  83. /* Blacklist some devices:
  84. * - HDAPS, it's not a real joystick.
  85. * - X360 controllers, Xinput handles them better since
  86. * it won't think there is only one trigger axis. */
  87. # if USE_SDL2
  88. char const *name = SDL_JoystickName(sdlstick);
  89. # else
  90. char const *name = SDL_JoystickName(i);
  91. # endif
  92. if (strstr(name, "HDAPS")
  93. # if USE_XINPUT
  94. || strstr(name, "XBOX 360 For Windows")
  95. # endif //USE_XINPUT
  96. || false)
  97. {
  98. SDL_JoystickClose(sdlstick);
  99. continue;
  100. }
  101. InputDeviceInternal* stick = new InputDeviceInternal(String::Printf("Joystick%d", i+1).C());
  102. for (int j = 0; j < SDL_JoystickNumAxes(sdlstick); ++j)
  103. stick->AddAxis(String::Printf("Axis%d", j + 1).C());
  104. for (int j = 0; j < SDL_JoystickNumButtons(sdlstick); ++j)
  105. stick->AddKey(String::Printf("Button%d", j + 1).C());
  106. m_data->m_joysticks.Push(sdlstick, stick);
  107. }
  108. # endif //EMSCRIPTEN
  109. #else
  110. UNUSED(app_w, app_h, screen_w, screen_h);
  111. #endif //USE_SDL
  112. m_gamegroup = GAMEGROUP_BEFORE;
  113. }
  114. SdlInput::~SdlInput()
  115. {
  116. #if USE_SDL && !EMSCRIPTEN
  117. /* Unregister all the joysticks we added */
  118. while (m_data->m_joysticks.Count())
  119. {
  120. SDL_JoystickClose(m_data->m_joysticks[0].m1);
  121. delete m_data->m_joysticks[0].m2;
  122. m_data->m_joysticks.Remove(0);
  123. }
  124. #endif
  125. delete m_data;
  126. }
  127. void SdlInput::TickGame(float seconds)
  128. {
  129. Entity::TickGame(seconds);
  130. #if !_WIN32
  131. m_data->Tick(seconds);
  132. #endif
  133. }
  134. void SdlInput::TickDraw(float seconds, Scene &scene)
  135. {
  136. Entity::TickDraw(seconds, scene);
  137. #if _WIN32
  138. m_data->Tick(seconds);
  139. #endif //_WIN32
  140. }
  141. void SdlInputData::Tick(float seconds)
  142. {
  143. #if USE_SDL
  144. /* Pump all joystick events because no event is coming to us. */
  145. # if SDL_FORCE_POLL_JOYSTICK && !EMSCRIPTEN
  146. SDL_JoystickUpdate();
  147. for (int j = 0; j < m_joysticks.Count(); j++)
  148. {
  149. for (int i = 0; i < SDL_JoystickNumButtons(m_joysticks[j].m1); i++)
  150. m_joysticks[j].m2->SetKey(i, SDL_JoystickGetButton(m_joysticks[j].m1, i) != 0);
  151. for (int i = 0; i < SDL_JoystickNumAxes(m_joysticks[j].m1); i++)
  152. m_joysticks[j].m2->SetAxis(i, (float)SDL_JoystickGetAxis(m_joysticks[j].m1, i) / 32768.f);
  153. }
  154. # endif
  155. m_mouse->SetAxis(4, 0);
  156. /* Handle keyboard and WM events */
  157. SDL_Event event;
  158. while (SDL_PollEvent(&event))
  159. {
  160. switch (event.type)
  161. {
  162. case SDL_QUIT:
  163. Ticker::Shutdown();
  164. break;
  165. #if 0
  166. case SDL_KEYDOWN:
  167. if (event.key.keysym.unicode)
  168. fprintf(stderr, "%c (0x%04X)\n", event.key.keysym.unicode, event.key.keysym.unicode);
  169. break;
  170. #endif
  171. case SDL_MOUSEBUTTONDOWN:
  172. case SDL_MOUSEBUTTONUP:
  173. {
  174. # if !USE_SDL2
  175. if (event.button.button != SDL_BUTTON_WHEELUP && event.button.button != SDL_BUTTON_WHEELDOWN)
  176. m_mouse->SetKey(event.button.button - 1, event.type == SDL_MOUSEBUTTONDOWN);
  177. else
  178. m_mouse->SetAxis(4, (event.button.button != SDL_BUTTON_WHEELUP) ? (1) : (-1));
  179. # endif
  180. // TODO: mouse wheel as axis
  181. break;
  182. }
  183. # if !SDL_FORCE_POLL_JOYSTICK
  184. case SDL_JOYAXISMOTION:
  185. m_joysticks[event.jaxis.which].m2->SetAxis(event.jaxis.axis, (float)event.jaxis.value / 32768.f);
  186. break;
  187. case SDL_JOYBUTTONUP:
  188. case SDL_JOYBUTTONDOWN:
  189. m_joysticks[event.jbutton.which].m2->SetKey(event.jbutton.button, event.jbutton.state);
  190. break;
  191. # endif
  192. }
  193. }
  194. /* Handle mouse input */
  195. ivec2 mouse = SdlInputData::GetMousePos();
  196. if (InputDeviceInternal::GetMouseCapture() != m_mousecapture)
  197. {
  198. m_mousecapture = InputDeviceInternal::GetMouseCapture();
  199. # if USE_SDL2
  200. SDL_SetRelativeMouseMode(m_mousecapture ? SDL_TRUE : SDL_FALSE);
  201. # else
  202. SDL_WM_GrabInput(m_mousecapture ? SDL_GRAB_ON : SDL_GRAB_OFF);
  203. # endif
  204. mouse = (ivec2)m_app / 2;
  205. SdlInputData::SetMousePos(mouse);
  206. //SDL_ShowCursor(m_mousecapture ? SDL_DISABLE : SDL_ENABLE);
  207. }
  208. if (mouse.x >= 0 && mouse.x < m_app.x && mouse.y >= 0 && mouse.y < m_app.y)
  209. {
  210. //We need the max if we want coherent mouse speed between axis
  211. float max_screen_size = lol::max(m_screen.x, m_screen.y);
  212. vec2 vmouse = vec2(mouse);
  213. vec2 vprevmouse = vec2(m_prevmouse);
  214. m_mouse->SetCursor(0, vmouse / m_app, mouse);
  215. // Note: 100.0f is an arbitrary value that makes it feel about the same than an xbox controller joystick
  216. m_mouse->SetAxis(0, (mouse.x - vprevmouse.x) * MOUSE_SPEED_MOD / max_screen_size);
  217. // Y Axis is also negated to match the usual joystick Y axis (negatives values are for the upper direction)
  218. m_mouse->SetAxis(1,-(mouse.y - vprevmouse.y) * MOUSE_SPEED_MOD / max_screen_size);
  219. //Pixel movement
  220. m_mouse->SetAxis(2, (mouse.x - vprevmouse.x));
  221. m_mouse->SetAxis(3,-(mouse.y - vprevmouse.y));
  222. }
  223. //Mouse is focused, Validate the InScreen Key
  224. //Hardcoded 3, not very nice.
  225. # if !EMSCRIPTEN && !USE_SDL2
  226. m_mouse->SetKey(3, !!(SDL_GetAppState() & SDL_APPMOUSEFOCUS));
  227. #else
  228. // Emscripten doesn't seem to handle SDL_APPMOUSEFOCUS
  229. // SDL2 doesn't have SDL_APPMOUSEFOCUS either
  230. m_mouse->SetKey(3, true);
  231. #endif
  232. if (m_mousecapture)
  233. {
  234. mouse = ivec2(m_app * .5f);
  235. SdlInputData::SetMousePos(mouse);
  236. }
  237. m_prevmouse = mouse;
  238. # if USE_SDL2
  239. Uint8 const *sdlstate = SDL_GetKeyboardState(nullptr);
  240. # else
  241. Uint8 *sdlstate = SDL_GetKeyState(nullptr);
  242. # endif
  243. int keyindex = 0;
  244. # define KEY_FUNC(name, index) \
  245. m_keyboard->SetKey(keyindex++, sdlstate[index] != 0);
  246. /* FIXME: we ignore SDLK_WORLD_0, which means our list of
  247. * keys and SDL's list of keys could be out of sync. */
  248. # include "input/keys.h"
  249. # undef KEY_FUNC
  250. #else
  251. UNUSED(seconds);
  252. #endif //USE_SDL
  253. }
  254. // NOTE: these two functions are pointless now and could be inlined directly
  255. ivec2 SdlInputData::GetMousePos()
  256. {
  257. ivec2 ret(-1, -1);
  258. #if USE_SDL
  259. # if !EMSCRIPTEN && !USE_SDL2
  260. if (SDL_GetAppState() & SDL_APPMOUSEFOCUS)
  261. # endif
  262. {
  263. SDL_GetMouseState(&ret.x, &ret.y);
  264. ret.y = Video::GetSize().y - 1 - ret.y;
  265. }
  266. #endif //USE_SDL
  267. return ret;
  268. }
  269. void SdlInputData::SetMousePos(ivec2 position)
  270. {
  271. #if USE_SDL2
  272. // FIXME: how do I warped mouse?
  273. #elif USE_SDL
  274. SDL_WarpMouse((uint16_t)position.x, (uint16_t)position.y);
  275. #else
  276. UNUSED(position);
  277. #endif //USE_SDL
  278. }
  279. } /* namespace lol */