SDL  2.0
SDL_emscriptenevents.c
Go to the documentation of this file.
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
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
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
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
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);
383 }
384 
385 EM_BOOL
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);
391 }
392 
393 EM_BOOL
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) {
401  }
402 
403 
404  SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_FOCUS ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
406 }
407 
408 EM_BOOL
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++) {
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);
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)) {
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
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
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  }
521 }
522 
523 EM_BOOL
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
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 
572  }
573  }
574 
575  return 0;
576 }
577 
578 EM_BOOL
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
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
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
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 
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: */
GLuint id
int Emscripten_HandleCanvasResize(int eventType, const void *reserved, void *userData)
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
Sint64 SDL_FingerID
Definition: SDL_touch.h:42
#define SDL_BUTTON_RIGHT
Definition: SDL_mouse.h:284
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
#define SDL_GetHint
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, float x, float y, float pressure)
Definition: SDL_touch.c:216
#define SDL_ENABLE
Definition: SDL_events.h:722
GLfloat f
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
SDL_Window * window
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:103
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:161
#define SDL_TOUCH_MOUSEID
Definition: SDL_touch.h:53
SDL_FingerID first_finger
void Emscripten_RegisterEventHandlers(SDL_WindowData *data)
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
Definition: SDL_keyboard.c:661
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, float x, float y, float pressure)
Definition: SDL_touch.c:278
#define SDL_GetEventState(type)
Definition: SDL_events.h:735
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:188
#define SDL_BUTTON_LEFT
Definition: SDL_mouse.h:282
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:774
GLenum target
SDL_EventType
The types of events that can be delivered.
Definition: SDL_events.h:55
Sint64 SDL_TouchID
Definition: SDL_touch.h:41
#define SDL_BUTTON_MIDDLE
Definition: SDL_mouse.h:283
int SDL_AddTouch(SDL_TouchID touchID, const char *name)
Definition: SDL_touch.c:130
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:143
SDL_bool
Definition: SDL_stdinc.h:130
unsigned int uint32_t
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:47
void SDL_ResetKeyboard(void)
Definition: SDL_keyboard.c:564
#define SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT
override the binding element for keyboard inputs for Emscripten builds
Definition: SDL_hints.h:649
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:90
int SDL_SendMouseWheel(SDL_Window *window, SDL_MouseID mouseID, int x, int y, SDL_MouseWheelDirection direction)
Definition: SDL_mouse.c:420
GLubyte GLubyte GLubyte GLubyte w
#define FULLSCREEN_MASK
Definition: SDL_video.c:142
#define SDL_PRESSED
Definition: SDL_events.h:50
void Emscripten_UnregisterEventHandlers(SDL_WindowData *data)
Uint32 flags
Definition: SDL_sysvideo.h:81
#define SDL_RELEASED
Definition: SDL_events.h:49
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
Definition: SDL_mouse.c:414
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:43
SDL_bool fullscreen_resize
GLfloat GLfloat GLfloat GLfloat h