Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

sdlinput.cpp 8.9 KiB

11 år sedan
11 år sedan
11 år sedan
11 år sedan
11 år sedan
11 år sedan
11 år sedan
11 år sedan
11 år sedan
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 */