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