InputSdl.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Window/Input.h>
  6. #include <AnKi/Window/InputSdl.h>
  7. #include <AnKi/Window/NativeWindowSdl.h>
  8. #include <AnKi/Util/Logger.h>
  9. #include <SDL3/SDL.h>
  10. namespace anki {
  11. static MouseButton sdlMouseButtonToAnKi(const U32 sdl)
  12. {
  13. MouseButton out = MouseButton::kCount;
  14. switch(sdl)
  15. {
  16. case SDL_BUTTON_LEFT:
  17. out = MouseButton::kLeft;
  18. break;
  19. case SDL_BUTTON_RIGHT:
  20. out = MouseButton::kRight;
  21. break;
  22. case SDL_BUTTON_MIDDLE:
  23. out = MouseButton::kMiddle;
  24. break;
  25. }
  26. return out;
  27. }
  28. static KeyCode sdlKeytoAnKi(SDL_Keycode sdlk)
  29. {
  30. KeyCode akk = KeyCode::kUnknown;
  31. switch(sdlk)
  32. {
  33. #define ANKI_KEY_CODE(ak, sdl) \
  34. case SDLK_##sdl: \
  35. akk = KeyCode::k##ak; \
  36. break;
  37. #include <AnKi/Window/KeyCode.def.h>
  38. #undef ANKI_KEY_CODE
  39. }
  40. ANKI_ASSERT(akk != KeyCode::kUnknown);
  41. return akk;
  42. }
  43. template<>
  44. template<>
  45. Input& MakeSingletonPtr<Input>::allocateSingleton<>()
  46. {
  47. ANKI_ASSERT(m_global == nullptr);
  48. m_global = new InputSdl;
  49. #if ANKI_ASSERTIONS_ENABLED
  50. ++g_singletonsAllocated;
  51. #endif
  52. return *m_global;
  53. }
  54. template<>
  55. void MakeSingletonPtr<Input>::freeSingleton()
  56. {
  57. if(m_global)
  58. {
  59. delete static_cast<InputSdl*>(m_global);
  60. m_global = nullptr;
  61. #if ANKI_ASSERTIONS_ENABLED
  62. --g_singletonsAllocated;
  63. #endif
  64. }
  65. }
  66. Error Input::init()
  67. {
  68. return static_cast<InputSdl*>(this)->initInternal();
  69. }
  70. Error Input::handleEvents()
  71. {
  72. InputSdl* self = static_cast<InputSdl*>(this);
  73. return self->handleEventsInternal();
  74. }
  75. void Input::moveMouseNdc(const Vec2& pos)
  76. {
  77. if(pos != m_mousePosNdc)
  78. {
  79. const F32 x = F32(NativeWindow::getSingleton().getWidth()) * (pos.x * 0.5f + 0.5f);
  80. const F32 y = F32(NativeWindow::getSingleton().getHeight()) * (-pos.y * 0.5f + 0.5f);
  81. SDL_WarpMouseInWindow(static_cast<NativeWindowSdl&>(NativeWindow::getSingleton()).m_sdlWindow, x, y);
  82. // SDL doesn't generate a SDL_MOUSEMOTION event if the cursor is outside the window. Push that event
  83. SDL_Event event;
  84. event.type = SDL_EVENT_MOUSE_MOTION;
  85. event.button.x = x;
  86. event.button.y = y;
  87. SDL_PushEvent(&event);
  88. }
  89. }
  90. void Input::hideCursor(Bool hide)
  91. {
  92. InputSdl* self = static_cast<InputSdl*>(this);
  93. self->m_crntHideCursor = hide;
  94. }
  95. Bool Input::hasTouchDevice() const
  96. {
  97. return false;
  98. }
  99. void Input::setMouseCursor(MouseCursor cursor)
  100. {
  101. ANKI_ASSERT(cursor < MouseCursor::kCount);
  102. InputSdl* self = static_cast<InputSdl*>(this);
  103. self->m_crntMouseCursor = cursor;
  104. }
  105. InputSdl::~InputSdl()
  106. {
  107. for(MouseCursor cursor : EnumIterable<MouseCursor>())
  108. {
  109. if(m_cursors[cursor])
  110. {
  111. SDL_DestroyCursor(m_cursors[cursor]);
  112. }
  113. }
  114. }
  115. Error InputSdl::initInternal()
  116. {
  117. m_cursors[MouseCursor::kArrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT);
  118. m_cursors[MouseCursor::kTextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_TEXT);
  119. m_cursors[MouseCursor::kResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_MOVE);
  120. m_cursors[MouseCursor::kResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NS_RESIZE);
  121. m_cursors[MouseCursor::kResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_EW_RESIZE);
  122. m_cursors[MouseCursor::kResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NESW_RESIZE);
  123. m_cursors[MouseCursor::kResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NWSE_RESIZE);
  124. m_cursors[MouseCursor::kHand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_POINTER);
  125. m_cursors[MouseCursor::kWait] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT);
  126. m_cursors[MouseCursor::kProgress] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_PROGRESS);
  127. m_cursors[MouseCursor::kNotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NOT_ALLOWED);
  128. for(MouseCursor cursor : EnumIterable<MouseCursor>())
  129. {
  130. if(!m_cursors[cursor])
  131. {
  132. ANKI_WIND_LOGE("Failed to create cursor: %u", U32(cursor));
  133. return Error::kFunctionFailed;
  134. }
  135. }
  136. // Call once to clear first events
  137. return handleEvents();
  138. }
  139. Error InputSdl::handleEventsInternal()
  140. {
  141. m_textInput[0] = '\0';
  142. // add the times a key is being pressed
  143. for(I32& k : m_keys)
  144. {
  145. if(k > 0)
  146. {
  147. ++k;
  148. }
  149. else if(k < 0)
  150. {
  151. k = 0;
  152. }
  153. }
  154. for(I32& k : m_mouseBtns)
  155. {
  156. if(k > 0)
  157. {
  158. ++k;
  159. }
  160. else if(k < 0)
  161. {
  162. k = 0;
  163. }
  164. }
  165. m_prevMousePosNdc = m_mousePosNdc;
  166. SDL_Event event = {};
  167. KeyCode akkey = KeyCode::kCount;
  168. if(!SDL_StartTextInput(static_cast<NativeWindowSdl&>(NativeWindow::getSingleton()).m_sdlWindow))
  169. {
  170. ANKI_WIND_LOGE("SDL_StartTextInput() failed: %s", SDL_GetError());
  171. }
  172. MouseButton scrollKeyEvent = MouseButton::kCount;
  173. while(SDL_PollEvent(&event))
  174. {
  175. switch(event.type)
  176. {
  177. case SDL_EVENT_KEY_DOWN:
  178. // key.repeat adds a delay but we only want the 1st time the key is pressed
  179. if(!event.key.repeat)
  180. {
  181. akkey = sdlKeytoAnKi(event.key.key);
  182. m_keys[akkey] = 1;
  183. }
  184. break;
  185. case SDL_EVENT_KEY_UP:
  186. akkey = sdlKeytoAnKi(event.key.key);
  187. m_keys[akkey] = -1;
  188. break;
  189. case SDL_EVENT_MOUSE_BUTTON_DOWN:
  190. {
  191. MouseButton mb = sdlMouseButtonToAnKi(event.button.button);
  192. if(mb != MouseButton::kCount)
  193. {
  194. m_mouseBtns[mb] = 1;
  195. }
  196. break;
  197. }
  198. case SDL_EVENT_MOUSE_BUTTON_UP:
  199. {
  200. MouseButton mb = sdlMouseButtonToAnKi(event.button.button);
  201. if(mb != MouseButton::kCount)
  202. {
  203. m_mouseBtns[mb] = -1;
  204. }
  205. break;
  206. }
  207. case SDL_EVENT_MOUSE_WHEEL:
  208. {
  209. const MouseButton btn = (event.wheel.y > 0.0f) ? MouseButton::kScrollUp : MouseButton::kScrollDown;
  210. m_mouseBtns[btn] = max(m_mouseBtns[btn] + 1, 1);
  211. scrollKeyEvent = btn;
  212. break;
  213. }
  214. case SDL_EVENT_MOUSE_MOTION:
  215. m_mousePosNdc.x = F32(event.button.x) / F32(NativeWindow::getSingleton().getWidth()) * 2.0f - 1.0f;
  216. m_mousePosNdc.y = -(F32(event.button.y) / F32(NativeWindow::getSingleton().getHeight()) * 2.0f - 1.0f);
  217. break;
  218. case SDL_EVENT_QUIT:
  219. ANKI_WIND_LOGI("Recieved SDL_EVENT_QUIT");
  220. addEvent(InputEvent::kWindowClosed);
  221. break;
  222. case SDL_EVENT_TEXT_INPUT:
  223. std::strncpy(&m_textInput[0], event.text.text, m_textInput.getSize() - 1);
  224. break;
  225. }
  226. } // end while events
  227. if(scrollKeyEvent != MouseButton::kScrollDown)
  228. {
  229. m_mouseBtns[MouseButton::kScrollDown] = (m_mouseBtns[MouseButton::kScrollDown] > 0) ? -1 : 0;
  230. }
  231. if(scrollKeyEvent != MouseButton::kScrollUp)
  232. {
  233. m_mouseBtns[MouseButton::kScrollUp] = (m_mouseBtns[MouseButton::kScrollUp] > 0) ? -1 : 0;
  234. }
  235. // Lock mouse
  236. if(m_lockCurs)
  237. {
  238. moveMouseNdc(Vec2(0.0f));
  239. }
  240. if(m_crntMouseCursor != m_prevMouseCursor)
  241. {
  242. SDL_SetCursor(m_cursors[m_crntMouseCursor]);
  243. m_prevMouseCursor = m_crntMouseCursor;
  244. }
  245. if(m_crntHideCursor != m_prevHideCursor)
  246. {
  247. m_prevHideCursor = m_crntHideCursor;
  248. if(m_crntHideCursor)
  249. {
  250. if(!SDL_HideCursor())
  251. {
  252. ANKI_WIND_LOGE("SDL_HideCursor() failed: %s", SDL_GetError());
  253. }
  254. if(!SDL_SetWindowRelativeMouseMode(static_cast<NativeWindowSdl&>(NativeWindow::getSingleton()).m_sdlWindow, true))
  255. {
  256. ANKI_WIND_LOGE("SDL_SetWindowRelativeMouseMode() failed: %s", SDL_GetError());
  257. }
  258. }
  259. else
  260. {
  261. if(!SDL_ShowCursor())
  262. {
  263. ANKI_WIND_LOGE("SDL_ShowCursor() failed: %s", SDL_GetError());
  264. }
  265. if(!SDL_SetWindowRelativeMouseMode(static_cast<NativeWindowSdl&>(NativeWindow::getSingleton()).m_sdlWindow, false))
  266. {
  267. ANKI_WIND_LOGE("SDL_SetWindowRelativeMouseMode() failed: %s", SDL_GetError());
  268. }
  269. }
  270. }
  271. return Error::kNone;
  272. }
  273. } // end namespace anki