SDL_emscriptenevents.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "../../SDL_internal.h"
  19. #if SDL_VIDEO_DRIVER_EMSCRIPTEN
  20. #include <emscripten/html5.h>
  21. #include "../../events/SDL_events_c.h"
  22. #include "../../events/SDL_keyboard_c.h"
  23. #include "../../events/SDL_touch_c.h"
  24. #include "SDL_emscriptenevents.h"
  25. #include "SDL_emscriptenvideo.h"
  26. #include "SDL_hints.h"
  27. #define FULLSCREEN_MASK ( SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN )
  28. /*
  29. .keyCode to scancode
  30. https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
  31. https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
  32. */
  33. static const SDL_Scancode emscripten_scancode_table[] = {
  34. /* 0 */ SDL_SCANCODE_UNKNOWN,
  35. /* 1 */ SDL_SCANCODE_UNKNOWN,
  36. /* 2 */ SDL_SCANCODE_UNKNOWN,
  37. /* 3 */ SDL_SCANCODE_CANCEL,
  38. /* 4 */ SDL_SCANCODE_UNKNOWN,
  39. /* 5 */ SDL_SCANCODE_UNKNOWN,
  40. /* 6 */ SDL_SCANCODE_HELP,
  41. /* 7 */ SDL_SCANCODE_UNKNOWN,
  42. /* 8 */ SDL_SCANCODE_BACKSPACE,
  43. /* 9 */ SDL_SCANCODE_TAB,
  44. /* 10 */ SDL_SCANCODE_UNKNOWN,
  45. /* 11 */ SDL_SCANCODE_UNKNOWN,
  46. /* 12 */ SDL_SCANCODE_UNKNOWN,
  47. /* 13 */ SDL_SCANCODE_RETURN,
  48. /* 14 */ SDL_SCANCODE_UNKNOWN,
  49. /* 15 */ SDL_SCANCODE_UNKNOWN,
  50. /* 16 */ SDL_SCANCODE_LSHIFT,
  51. /* 17 */ SDL_SCANCODE_LCTRL,
  52. /* 18 */ SDL_SCANCODE_LALT,
  53. /* 19 */ SDL_SCANCODE_PAUSE,
  54. /* 20 */ SDL_SCANCODE_CAPSLOCK,
  55. /* 21 */ SDL_SCANCODE_UNKNOWN,
  56. /* 22 */ SDL_SCANCODE_UNKNOWN,
  57. /* 23 */ SDL_SCANCODE_UNKNOWN,
  58. /* 24 */ SDL_SCANCODE_UNKNOWN,
  59. /* 25 */ SDL_SCANCODE_UNKNOWN,
  60. /* 26 */ SDL_SCANCODE_UNKNOWN,
  61. /* 27 */ SDL_SCANCODE_ESCAPE,
  62. /* 28 */ SDL_SCANCODE_UNKNOWN,
  63. /* 29 */ SDL_SCANCODE_UNKNOWN,
  64. /* 30 */ SDL_SCANCODE_UNKNOWN,
  65. /* 31 */ SDL_SCANCODE_UNKNOWN,
  66. /* 32 */ SDL_SCANCODE_SPACE,
  67. /* 33 */ SDL_SCANCODE_PAGEUP,
  68. /* 34 */ SDL_SCANCODE_PAGEDOWN,
  69. /* 35 */ SDL_SCANCODE_END,
  70. /* 36 */ SDL_SCANCODE_HOME,
  71. /* 37 */ SDL_SCANCODE_LEFT,
  72. /* 38 */ SDL_SCANCODE_UP,
  73. /* 39 */ SDL_SCANCODE_RIGHT,
  74. /* 40 */ SDL_SCANCODE_DOWN,
  75. /* 41 */ SDL_SCANCODE_UNKNOWN,
  76. /* 42 */ SDL_SCANCODE_UNKNOWN,
  77. /* 43 */ SDL_SCANCODE_UNKNOWN,
  78. /* 44 */ SDL_SCANCODE_UNKNOWN,
  79. /* 45 */ SDL_SCANCODE_INSERT,
  80. /* 46 */ SDL_SCANCODE_DELETE,
  81. /* 47 */ SDL_SCANCODE_UNKNOWN,
  82. /* 48 */ SDL_SCANCODE_0,
  83. /* 49 */ SDL_SCANCODE_1,
  84. /* 50 */ SDL_SCANCODE_2,
  85. /* 51 */ SDL_SCANCODE_3,
  86. /* 52 */ SDL_SCANCODE_4,
  87. /* 53 */ SDL_SCANCODE_5,
  88. /* 54 */ SDL_SCANCODE_6,
  89. /* 55 */ SDL_SCANCODE_7,
  90. /* 56 */ SDL_SCANCODE_8,
  91. /* 57 */ SDL_SCANCODE_9,
  92. /* 58 */ SDL_SCANCODE_UNKNOWN,
  93. /* 59 */ SDL_SCANCODE_SEMICOLON,
  94. /* 60 */ SDL_SCANCODE_UNKNOWN,
  95. /* 61 */ SDL_SCANCODE_EQUALS,
  96. /* 62 */ SDL_SCANCODE_UNKNOWN,
  97. /* 63 */ SDL_SCANCODE_UNKNOWN,
  98. /* 64 */ SDL_SCANCODE_UNKNOWN,
  99. /* 65 */ SDL_SCANCODE_A,
  100. /* 66 */ SDL_SCANCODE_B,
  101. /* 67 */ SDL_SCANCODE_C,
  102. /* 68 */ SDL_SCANCODE_D,
  103. /* 69 */ SDL_SCANCODE_E,
  104. /* 70 */ SDL_SCANCODE_F,
  105. /* 71 */ SDL_SCANCODE_G,
  106. /* 72 */ SDL_SCANCODE_H,
  107. /* 73 */ SDL_SCANCODE_I,
  108. /* 74 */ SDL_SCANCODE_J,
  109. /* 75 */ SDL_SCANCODE_K,
  110. /* 76 */ SDL_SCANCODE_L,
  111. /* 77 */ SDL_SCANCODE_M,
  112. /* 78 */ SDL_SCANCODE_N,
  113. /* 79 */ SDL_SCANCODE_O,
  114. /* 80 */ SDL_SCANCODE_P,
  115. /* 81 */ SDL_SCANCODE_Q,
  116. /* 82 */ SDL_SCANCODE_R,
  117. /* 83 */ SDL_SCANCODE_S,
  118. /* 84 */ SDL_SCANCODE_T,
  119. /* 85 */ SDL_SCANCODE_U,
  120. /* 86 */ SDL_SCANCODE_V,
  121. /* 87 */ SDL_SCANCODE_W,
  122. /* 88 */ SDL_SCANCODE_X,
  123. /* 89 */ SDL_SCANCODE_Y,
  124. /* 90 */ SDL_SCANCODE_Z,
  125. /* 91 */ SDL_SCANCODE_LGUI,
  126. /* 92 */ SDL_SCANCODE_UNKNOWN,
  127. /* 93 */ SDL_SCANCODE_APPLICATION,
  128. /* 94 */ SDL_SCANCODE_UNKNOWN,
  129. /* 95 */ SDL_SCANCODE_UNKNOWN,
  130. /* 96 */ SDL_SCANCODE_KP_0,
  131. /* 97 */ SDL_SCANCODE_KP_1,
  132. /* 98 */ SDL_SCANCODE_KP_2,
  133. /* 99 */ SDL_SCANCODE_KP_3,
  134. /* 100 */ SDL_SCANCODE_KP_4,
  135. /* 101 */ SDL_SCANCODE_KP_5,
  136. /* 102 */ SDL_SCANCODE_KP_6,
  137. /* 103 */ SDL_SCANCODE_KP_7,
  138. /* 104 */ SDL_SCANCODE_KP_8,
  139. /* 105 */ SDL_SCANCODE_KP_9,
  140. /* 106 */ SDL_SCANCODE_KP_MULTIPLY,
  141. /* 107 */ SDL_SCANCODE_KP_PLUS,
  142. /* 108 */ SDL_SCANCODE_UNKNOWN,
  143. /* 109 */ SDL_SCANCODE_KP_MINUS,
  144. /* 110 */ SDL_SCANCODE_KP_PERIOD,
  145. /* 111 */ SDL_SCANCODE_KP_DIVIDE,
  146. /* 112 */ SDL_SCANCODE_F1,
  147. /* 113 */ SDL_SCANCODE_F2,
  148. /* 114 */ SDL_SCANCODE_F3,
  149. /* 115 */ SDL_SCANCODE_F4,
  150. /* 116 */ SDL_SCANCODE_F5,
  151. /* 117 */ SDL_SCANCODE_F6,
  152. /* 118 */ SDL_SCANCODE_F7,
  153. /* 119 */ SDL_SCANCODE_F8,
  154. /* 120 */ SDL_SCANCODE_F9,
  155. /* 121 */ SDL_SCANCODE_F10,
  156. /* 122 */ SDL_SCANCODE_F11,
  157. /* 123 */ SDL_SCANCODE_F12,
  158. /* 124 */ SDL_SCANCODE_F13,
  159. /* 125 */ SDL_SCANCODE_F14,
  160. /* 126 */ SDL_SCANCODE_F15,
  161. /* 127 */ SDL_SCANCODE_F16,
  162. /* 128 */ SDL_SCANCODE_F17,
  163. /* 129 */ SDL_SCANCODE_F18,
  164. /* 130 */ SDL_SCANCODE_F19,
  165. /* 131 */ SDL_SCANCODE_F20,
  166. /* 132 */ SDL_SCANCODE_F21,
  167. /* 133 */ SDL_SCANCODE_F22,
  168. /* 134 */ SDL_SCANCODE_F23,
  169. /* 135 */ SDL_SCANCODE_F24,
  170. /* 136 */ SDL_SCANCODE_UNKNOWN,
  171. /* 137 */ SDL_SCANCODE_UNKNOWN,
  172. /* 138 */ SDL_SCANCODE_UNKNOWN,
  173. /* 139 */ SDL_SCANCODE_UNKNOWN,
  174. /* 140 */ SDL_SCANCODE_UNKNOWN,
  175. /* 141 */ SDL_SCANCODE_UNKNOWN,
  176. /* 142 */ SDL_SCANCODE_UNKNOWN,
  177. /* 143 */ SDL_SCANCODE_UNKNOWN,
  178. /* 144 */ SDL_SCANCODE_NUMLOCKCLEAR,
  179. /* 145 */ SDL_SCANCODE_SCROLLLOCK,
  180. /* 146 */ SDL_SCANCODE_UNKNOWN,
  181. /* 147 */ SDL_SCANCODE_UNKNOWN,
  182. /* 148 */ SDL_SCANCODE_UNKNOWN,
  183. /* 149 */ SDL_SCANCODE_UNKNOWN,
  184. /* 150 */ SDL_SCANCODE_UNKNOWN,
  185. /* 151 */ SDL_SCANCODE_UNKNOWN,
  186. /* 152 */ SDL_SCANCODE_UNKNOWN,
  187. /* 153 */ SDL_SCANCODE_UNKNOWN,
  188. /* 154 */ SDL_SCANCODE_UNKNOWN,
  189. /* 155 */ SDL_SCANCODE_UNKNOWN,
  190. /* 156 */ SDL_SCANCODE_UNKNOWN,
  191. /* 157 */ SDL_SCANCODE_UNKNOWN,
  192. /* 158 */ SDL_SCANCODE_UNKNOWN,
  193. /* 159 */ SDL_SCANCODE_UNKNOWN,
  194. /* 160 */ SDL_SCANCODE_UNKNOWN,
  195. /* 161 */ SDL_SCANCODE_UNKNOWN,
  196. /* 162 */ SDL_SCANCODE_UNKNOWN,
  197. /* 163 */ SDL_SCANCODE_UNKNOWN,
  198. /* 164 */ SDL_SCANCODE_UNKNOWN,
  199. /* 165 */ SDL_SCANCODE_UNKNOWN,
  200. /* 166 */ SDL_SCANCODE_UNKNOWN,
  201. /* 167 */ SDL_SCANCODE_UNKNOWN,
  202. /* 168 */ SDL_SCANCODE_UNKNOWN,
  203. /* 169 */ SDL_SCANCODE_UNKNOWN,
  204. /* 170 */ SDL_SCANCODE_UNKNOWN,
  205. /* 171 */ SDL_SCANCODE_UNKNOWN,
  206. /* 172 */ SDL_SCANCODE_UNKNOWN,
  207. /* 173 */ SDL_SCANCODE_MINUS, /*FX*/
  208. /* 174 */ SDL_SCANCODE_VOLUMEDOWN, /*IE, Chrome*/
  209. /* 175 */ SDL_SCANCODE_VOLUMEUP, /*IE, Chrome*/
  210. /* 176 */ SDL_SCANCODE_AUDIONEXT, /*IE, Chrome*/
  211. /* 177 */ SDL_SCANCODE_AUDIOPREV, /*IE, Chrome*/
  212. /* 178 */ SDL_SCANCODE_UNKNOWN,
  213. /* 179 */ SDL_SCANCODE_AUDIOPLAY, /*IE, Chrome*/
  214. /* 180 */ SDL_SCANCODE_UNKNOWN,
  215. /* 181 */ SDL_SCANCODE_AUDIOMUTE, /*FX*/
  216. /* 182 */ SDL_SCANCODE_VOLUMEDOWN, /*FX*/
  217. /* 183 */ SDL_SCANCODE_VOLUMEUP, /*FX*/
  218. /* 184 */ SDL_SCANCODE_UNKNOWN,
  219. /* 185 */ SDL_SCANCODE_UNKNOWN,
  220. /* 186 */ SDL_SCANCODE_SEMICOLON, /*IE, Chrome, D3E legacy*/
  221. /* 187 */ SDL_SCANCODE_EQUALS, /*IE, Chrome, D3E legacy*/
  222. /* 188 */ SDL_SCANCODE_COMMA,
  223. /* 189 */ SDL_SCANCODE_MINUS, /*IE, Chrome, D3E legacy*/
  224. /* 190 */ SDL_SCANCODE_PERIOD,
  225. /* 191 */ SDL_SCANCODE_SLASH,
  226. /* 192 */ SDL_SCANCODE_GRAVE, /*FX, D3E legacy (SDL_SCANCODE_APOSTROPHE in IE/Chrome)*/
  227. /* 193 */ SDL_SCANCODE_UNKNOWN,
  228. /* 194 */ SDL_SCANCODE_UNKNOWN,
  229. /* 195 */ SDL_SCANCODE_UNKNOWN,
  230. /* 196 */ SDL_SCANCODE_UNKNOWN,
  231. /* 197 */ SDL_SCANCODE_UNKNOWN,
  232. /* 198 */ SDL_SCANCODE_UNKNOWN,
  233. /* 199 */ SDL_SCANCODE_UNKNOWN,
  234. /* 200 */ SDL_SCANCODE_UNKNOWN,
  235. /* 201 */ SDL_SCANCODE_UNKNOWN,
  236. /* 202 */ SDL_SCANCODE_UNKNOWN,
  237. /* 203 */ SDL_SCANCODE_UNKNOWN,
  238. /* 204 */ SDL_SCANCODE_UNKNOWN,
  239. /* 205 */ SDL_SCANCODE_UNKNOWN,
  240. /* 206 */ SDL_SCANCODE_UNKNOWN,
  241. /* 207 */ SDL_SCANCODE_UNKNOWN,
  242. /* 208 */ SDL_SCANCODE_UNKNOWN,
  243. /* 209 */ SDL_SCANCODE_UNKNOWN,
  244. /* 210 */ SDL_SCANCODE_UNKNOWN,
  245. /* 211 */ SDL_SCANCODE_UNKNOWN,
  246. /* 212 */ SDL_SCANCODE_UNKNOWN,
  247. /* 213 */ SDL_SCANCODE_UNKNOWN,
  248. /* 214 */ SDL_SCANCODE_UNKNOWN,
  249. /* 215 */ SDL_SCANCODE_UNKNOWN,
  250. /* 216 */ SDL_SCANCODE_UNKNOWN,
  251. /* 217 */ SDL_SCANCODE_UNKNOWN,
  252. /* 218 */ SDL_SCANCODE_UNKNOWN,
  253. /* 219 */ SDL_SCANCODE_LEFTBRACKET,
  254. /* 220 */ SDL_SCANCODE_BACKSLASH,
  255. /* 221 */ SDL_SCANCODE_RIGHTBRACKET,
  256. /* 222 */ SDL_SCANCODE_APOSTROPHE, /*FX, D3E legacy*/
  257. };
  258. /* "borrowed" from SDL_windowsevents.c */
  259. int
  260. Emscripten_ConvertUTF32toUTF8(Uint32 codepoint, char * text)
  261. {
  262. if (codepoint <= 0x7F) {
  263. text[0] = (char) codepoint;
  264. text[1] = '\0';
  265. } else if (codepoint <= 0x7FF) {
  266. text[0] = 0xC0 | (char) ((codepoint >> 6) & 0x1F);
  267. text[1] = 0x80 | (char) (codepoint & 0x3F);
  268. text[2] = '\0';
  269. } else if (codepoint <= 0xFFFF) {
  270. text[0] = 0xE0 | (char) ((codepoint >> 12) & 0x0F);
  271. text[1] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
  272. text[2] = 0x80 | (char) (codepoint & 0x3F);
  273. text[3] = '\0';
  274. } else if (codepoint <= 0x10FFFF) {
  275. text[0] = 0xF0 | (char) ((codepoint >> 18) & 0x0F);
  276. text[1] = 0x80 | (char) ((codepoint >> 12) & 0x3F);
  277. text[2] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
  278. text[3] = 0x80 | (char) (codepoint & 0x3F);
  279. text[4] = '\0';
  280. } else {
  281. return SDL_FALSE;
  282. }
  283. return SDL_TRUE;
  284. }
  285. EM_BOOL
  286. Emscripten_HandleMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
  287. {
  288. SDL_WindowData *window_data = userData;
  289. int mx, my;
  290. static double residualx = 0, residualy = 0;
  291. EmscriptenPointerlockChangeEvent pointerlock_status;
  292. /* rescale (in case canvas is being scaled)*/
  293. double client_w, client_h, xscale, yscale;
  294. emscripten_get_element_css_size(NULL, &client_w, &client_h);
  295. xscale = window_data->window->w / client_w;
  296. yscale = window_data->window->h / client_h;
  297. /* check for pointer lock */
  298. int isPointerLockSupported = emscripten_get_pointerlock_status(&pointerlock_status);
  299. int isPointerLocked = isPointerLockSupported == EMSCRIPTEN_RESULT_SUCCESS ? pointerlock_status.isActive : SDL_FALSE;
  300. if (isPointerLocked) {
  301. residualx += mouseEvent->movementX * xscale;
  302. residualy += mouseEvent->movementY * yscale;
  303. /* Let slow sub-pixel motion accumulate. Don't lose it. */
  304. mx = residualx;
  305. residualx -= mx;
  306. my = residualy;
  307. residualy -= my;
  308. } else {
  309. mx = mouseEvent->canvasX * xscale;
  310. my = mouseEvent->canvasY * yscale;
  311. }
  312. SDL_SendMouseMotion(window_data->window, 0, isPointerLocked, mx, my);
  313. return 0;
  314. }
  315. EM_BOOL
  316. Emscripten_HandleMouseButton(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
  317. {
  318. SDL_WindowData *window_data = userData;
  319. uint32_t sdl_button;
  320. switch (mouseEvent->button) {
  321. case 0:
  322. sdl_button = SDL_BUTTON_LEFT;
  323. break;
  324. case 1:
  325. sdl_button = SDL_BUTTON_MIDDLE;
  326. break;
  327. case 2:
  328. sdl_button = SDL_BUTTON_RIGHT;
  329. break;
  330. default:
  331. return 0;
  332. }
  333. SDL_EventType sdl_event_type = (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN ? SDL_PRESSED : SDL_RELEASED);
  334. SDL_SendMouseButton(window_data->window, 0, sdl_event_type, sdl_button);
  335. return SDL_GetEventState(sdl_event_type) == SDL_ENABLE;
  336. }
  337. EM_BOOL
  338. Emscripten_HandleMouseFocus(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
  339. {
  340. SDL_WindowData *window_data = userData;
  341. int mx = mouseEvent->canvasX, my = mouseEvent->canvasY;
  342. EmscriptenPointerlockChangeEvent pointerlock_status;
  343. /* check for pointer lock */
  344. int isPointerLockSupported = emscripten_get_pointerlock_status(&pointerlock_status);
  345. int isPointerLocked = isPointerLockSupported == EMSCRIPTEN_RESULT_SUCCESS ? pointerlock_status.isActive : SDL_FALSE;
  346. if (!isPointerLocked) {
  347. /* rescale (in case canvas is being scaled)*/
  348. double client_w, client_h;
  349. emscripten_get_element_css_size(NULL, &client_w, &client_h);
  350. mx = mx * (window_data->window->w / client_w);
  351. my = my * (window_data->window->h / client_h);
  352. SDL_SendMouseMotion(window_data->window, 0, isPointerLocked, mx, my);
  353. }
  354. SDL_SetMouseFocus(eventType == EMSCRIPTEN_EVENT_MOUSEENTER ? window_data->window : NULL);
  355. return SDL_GetEventState(SDL_WINDOWEVENT) == SDL_ENABLE;
  356. }
  357. EM_BOOL
  358. Emscripten_HandleWheel(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)
  359. {
  360. SDL_WindowData *window_data = userData;
  361. SDL_SendMouseWheel(window_data->window, 0, wheelEvent->deltaX, -wheelEvent->deltaY, SDL_MOUSEWHEEL_NORMAL);
  362. return SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE;
  363. }
  364. EM_BOOL
  365. Emscripten_HandleFocus(int eventType, const EmscriptenFocusEvent *wheelEvent, void *userData)
  366. {
  367. SDL_WindowData *window_data = userData;
  368. /* If the user switches away while keys are pressed (such as
  369. * via Alt+Tab), key release events won't be received. */
  370. if (eventType == EMSCRIPTEN_EVENT_BLUR) {
  371. SDL_ResetKeyboard();
  372. }
  373. SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_FOCUS ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
  374. return SDL_GetEventState(SDL_WINDOWEVENT) == SDL_ENABLE;
  375. }
  376. EM_BOOL
  377. Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
  378. {
  379. SDL_WindowData *window_data = userData;
  380. int i;
  381. double client_w, client_h;
  382. int preventDefault = 0;
  383. SDL_TouchID deviceId = 1;
  384. if (SDL_AddTouch(deviceId, "") < 0) {
  385. return 0;
  386. }
  387. emscripten_get_element_css_size(NULL, &client_w, &client_h);
  388. for (i = 0; i < touchEvent->numTouches; i++) {
  389. SDL_FingerID id;
  390. float x, y;
  391. if (!touchEvent->touches[i].isChanged)
  392. continue;
  393. id = touchEvent->touches[i].identifier;
  394. x = touchEvent->touches[i].canvasX / client_w;
  395. y = touchEvent->touches[i].canvasY / client_h;
  396. if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) {
  397. if (!window_data->finger_touching) {
  398. window_data->finger_touching = SDL_TRUE;
  399. window_data->first_finger = id;
  400. SDL_SendMouseMotion(window_data->window, SDL_TOUCH_MOUSEID, 0, x, y);
  401. SDL_SendMouseButton(window_data->window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
  402. }
  403. SDL_SendTouch(deviceId, id, SDL_TRUE, x, y, 1.0f);
  404. if (!preventDefault && SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
  405. preventDefault = 1;
  406. }
  407. } else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) {
  408. if ((window_data->finger_touching) && (window_data->first_finger == id)) {
  409. SDL_SendMouseMotion(window_data->window, SDL_TOUCH_MOUSEID, 0, x, y);
  410. }
  411. SDL_SendTouchMotion(deviceId, id, x, y, 1.0f);
  412. if (!preventDefault && SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
  413. preventDefault = 1;
  414. }
  415. } else {
  416. if ((window_data->finger_touching) && (window_data->first_finger == id)) {
  417. SDL_SendMouseButton(window_data->window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
  418. window_data->finger_touching = SDL_FALSE;
  419. }
  420. SDL_SendTouch(deviceId, id, SDL_FALSE, x, y, 1.0f);
  421. if (!preventDefault && SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
  422. preventDefault = 1;
  423. }
  424. }
  425. }
  426. return preventDefault;
  427. }
  428. EM_BOOL
  429. Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
  430. {
  431. Uint32 scancode;
  432. /* .keyCode is deprecated, but still the most reliable way to get keys */
  433. if (keyEvent->keyCode < SDL_arraysize(emscripten_scancode_table)) {
  434. scancode = emscripten_scancode_table[keyEvent->keyCode];
  435. if (scancode != SDL_SCANCODE_UNKNOWN) {
  436. if (keyEvent->location == DOM_KEY_LOCATION_RIGHT) {
  437. switch (scancode) {
  438. case SDL_SCANCODE_LSHIFT:
  439. scancode = SDL_SCANCODE_RSHIFT;
  440. break;
  441. case SDL_SCANCODE_LCTRL:
  442. scancode = SDL_SCANCODE_RCTRL;
  443. break;
  444. case SDL_SCANCODE_LALT:
  445. scancode = SDL_SCANCODE_RALT;
  446. break;
  447. case SDL_SCANCODE_LGUI:
  448. scancode = SDL_SCANCODE_RGUI;
  449. break;
  450. }
  451. }
  452. SDL_SendKeyboardKey(eventType == EMSCRIPTEN_EVENT_KEYDOWN ? SDL_PRESSED : SDL_RELEASED, scancode);
  453. }
  454. }
  455. SDL_bool prevent_default = SDL_GetEventState(eventType == EMSCRIPTEN_EVENT_KEYDOWN ? SDL_KEYDOWN : SDL_KEYUP) == SDL_ENABLE;
  456. /* if TEXTINPUT events are enabled we can't prevent keydown or we won't get keypress
  457. * we need to ALWAYS prevent backspace and tab otherwise chrome takes action and does bad navigation UX
  458. */
  459. if (eventType == EMSCRIPTEN_EVENT_KEYDOWN && SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE && keyEvent->keyCode != 8 /* backspace */ && keyEvent->keyCode != 9 /* tab */)
  460. prevent_default = SDL_FALSE;
  461. return prevent_default;
  462. }
  463. EM_BOOL
  464. Emscripten_HandleKeyPress(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
  465. {
  466. char text[5];
  467. if (Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text)) {
  468. SDL_SendKeyboardText(text);
  469. }
  470. return SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE;
  471. }
  472. EM_BOOL
  473. Emscripten_HandleFullscreenChange(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData)
  474. {
  475. SDL_WindowData *window_data = userData;
  476. if(fullscreenChangeEvent->isFullscreen)
  477. {
  478. window_data->window->flags |= window_data->requested_fullscreen_mode;
  479. window_data->requested_fullscreen_mode = 0;
  480. if(!window_data->requested_fullscreen_mode)
  481. window_data->window->flags |= SDL_WINDOW_FULLSCREEN; /*we didn't reqest fullscreen*/
  482. }
  483. else
  484. {
  485. window_data->window->flags &= ~FULLSCREEN_MASK;
  486. }
  487. return 0;
  488. }
  489. EM_BOOL
  490. Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)
  491. {
  492. SDL_WindowData *window_data = userData;
  493. /* update pixel ratio */
  494. window_data->pixel_ratio = emscripten_get_device_pixel_ratio();
  495. if(!(window_data->window->flags & FULLSCREEN_MASK))
  496. {
  497. /* this will only work if the canvas size is set through css */
  498. if(window_data->window->flags & SDL_WINDOW_RESIZABLE)
  499. {
  500. double w = window_data->window->w;
  501. double h = window_data->window->h;
  502. if(window_data->external_size) {
  503. emscripten_get_element_css_size(NULL, &w, &h);
  504. }
  505. emscripten_set_canvas_size(w * window_data->pixel_ratio, h * window_data->pixel_ratio);
  506. /* set_canvas_size unsets this */
  507. if (!window_data->external_size && window_data->pixel_ratio != 1.0f) {
  508. emscripten_set_element_css_size(NULL, w, h);
  509. }
  510. SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, w, h);
  511. }
  512. }
  513. return 0;
  514. }
  515. EM_BOOL
  516. Emscripten_HandleCanvasResize(int eventType, const void *reserved, void *userData)
  517. {
  518. /*this is used during fullscreen changes*/
  519. SDL_WindowData *window_data = userData;
  520. if(window_data->fullscreen_resize)
  521. {
  522. double css_w, css_h;
  523. emscripten_get_element_css_size(NULL, &css_w, &css_h);
  524. SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, css_w, css_h);
  525. }
  526. return 0;
  527. }
  528. EM_BOOL
  529. Emscripten_HandleVisibilityChange(int eventType, const EmscriptenVisibilityChangeEvent *visEvent, void *userData)
  530. {
  531. SDL_WindowData *window_data = userData;
  532. SDL_SendWindowEvent(window_data->window, visEvent->hidden ? SDL_WINDOWEVENT_HIDDEN : SDL_WINDOWEVENT_SHOWN, 0, 0);
  533. return 0;
  534. }
  535. void
  536. Emscripten_RegisterEventHandlers(SDL_WindowData *data)
  537. {
  538. /* There is only one window and that window is the canvas */
  539. emscripten_set_mousemove_callback("#canvas", data, 0, Emscripten_HandleMouseMove);
  540. emscripten_set_mousedown_callback("#canvas", data, 0, Emscripten_HandleMouseButton);
  541. emscripten_set_mouseup_callback("#document", data, 0, Emscripten_HandleMouseButton);
  542. emscripten_set_mouseenter_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
  543. emscripten_set_mouseleave_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
  544. emscripten_set_wheel_callback("#canvas", data, 0, Emscripten_HandleWheel);
  545. emscripten_set_focus_callback("#window", data, 0, Emscripten_HandleFocus);
  546. emscripten_set_blur_callback("#window", data, 0, Emscripten_HandleFocus);
  547. emscripten_set_touchstart_callback("#canvas", data, 0, Emscripten_HandleTouch);
  548. emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch);
  549. emscripten_set_touchmove_callback("#canvas", data, 0, Emscripten_HandleTouch);
  550. emscripten_set_touchcancel_callback("#canvas", data, 0, Emscripten_HandleTouch);
  551. /* Keyboard events are awkward */
  552. const char *keyElement = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
  553. if (!keyElement) keyElement = "#window";
  554. emscripten_set_keydown_callback(keyElement, data, 0, Emscripten_HandleKey);
  555. emscripten_set_keyup_callback(keyElement, data, 0, Emscripten_HandleKey);
  556. emscripten_set_keypress_callback(keyElement, data, 0, Emscripten_HandleKeyPress);
  557. emscripten_set_fullscreenchange_callback("#document", data, 0, Emscripten_HandleFullscreenChange);
  558. emscripten_set_resize_callback("#window", data, 0, Emscripten_HandleResize);
  559. emscripten_set_visibilitychange_callback(data, 0, Emscripten_HandleVisibilityChange);
  560. }
  561. void
  562. Emscripten_UnregisterEventHandlers(SDL_WindowData *data)
  563. {
  564. /* only works due to having one window */
  565. emscripten_set_mousemove_callback("#canvas", NULL, 0, NULL);
  566. emscripten_set_mousedown_callback("#canvas", NULL, 0, NULL);
  567. emscripten_set_mouseup_callback("#document", NULL, 0, NULL);
  568. emscripten_set_mouseenter_callback("#canvas", NULL, 0, NULL);
  569. emscripten_set_mouseleave_callback("#canvas", NULL, 0, NULL);
  570. emscripten_set_wheel_callback("#canvas", NULL, 0, NULL);
  571. emscripten_set_focus_callback("#window", NULL, 0, NULL);
  572. emscripten_set_blur_callback("#window", NULL, 0, NULL);
  573. emscripten_set_touchstart_callback("#canvas", NULL, 0, NULL);
  574. emscripten_set_touchend_callback("#canvas", NULL, 0, NULL);
  575. emscripten_set_touchmove_callback("#canvas", NULL, 0, NULL);
  576. emscripten_set_touchcancel_callback("#canvas", NULL, 0, NULL);
  577. const char *target = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
  578. if (!target) {
  579. target = "#window";
  580. }
  581. emscripten_set_keydown_callback(target, NULL, 0, NULL);
  582. emscripten_set_keyup_callback(target, NULL, 0, NULL);
  583. emscripten_set_keypress_callback(target, NULL, 0, NULL);
  584. emscripten_set_fullscreenchange_callback("#document", NULL, 0, NULL);
  585. emscripten_set_resize_callback("#window", NULL, 0, NULL);
  586. emscripten_set_visibilitychange_callback(NULL, 0, NULL);
  587. }
  588. #endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
  589. /* vi: set ts=4 sw=4 expandtab: */