SDL  2.0
SDL_emscriptenevents.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 static 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 static EM_BOOL
301 Emscripten_HandlePointerLockChange(int eventType, const EmscriptenPointerlockChangeEvent *changeEvent, void *userData)
302 {
303  SDL_WindowData *window_data = (SDL_WindowData *) userData;
304  /* keep track of lock losses, so we can regrab if/when appropriate. */
305  window_data->has_pointer_lock = changeEvent->isActive;
306  return 0;
307 }
308 
309 
310 static EM_BOOL
311 Emscripten_HandleMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
312 {
313  SDL_WindowData *window_data = userData;
314  const int isPointerLocked = window_data->has_pointer_lock;
315  int mx, my;
316  static double residualx = 0, residualy = 0;
317 
318  /* rescale (in case canvas is being scaled)*/
319  double client_w, client_h, xscale, yscale;
320  emscripten_get_element_css_size(NULL, &client_w, &client_h);
321  xscale = window_data->window->w / client_w;
322  yscale = window_data->window->h / client_h;
323 
324  if (isPointerLocked) {
325  residualx += mouseEvent->movementX * xscale;
326  residualy += mouseEvent->movementY * yscale;
327  /* Let slow sub-pixel motion accumulate. Don't lose it. */
328  mx = residualx;
329  residualx -= mx;
330  my = residualy;
331  residualy -= my;
332  } else {
333  mx = mouseEvent->canvasX * xscale;
334  my = mouseEvent->canvasY * yscale;
335  }
336 
337  SDL_SendMouseMotion(window_data->window, 0, isPointerLocked, mx, my);
338  return 0;
339 }
340 
341 static EM_BOOL
342 Emscripten_HandleMouseButton(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
343 {
344  SDL_WindowData *window_data = userData;
345  Uint8 sdl_button;
346  Uint8 sdl_button_state;
347  SDL_EventType sdl_event_type;
348 
349  switch (mouseEvent->button) {
350  case 0:
351  sdl_button = SDL_BUTTON_LEFT;
352  break;
353  case 1:
354  sdl_button = SDL_BUTTON_MIDDLE;
355  break;
356  case 2:
357  sdl_button = SDL_BUTTON_RIGHT;
358  break;
359  default:
360  return 0;
361  }
362 
363  if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) {
364  if (SDL_GetMouse()->relative_mode && !window_data->has_pointer_lock) {
365  emscripten_request_pointerlock(NULL, 0); /* try to regrab lost pointer lock. */
366  }
367  sdl_button_state = SDL_PRESSED;
368  sdl_event_type = SDL_MOUSEBUTTONDOWN;
369  } else {
370  sdl_button_state = SDL_RELEASED;
371  sdl_event_type = SDL_MOUSEBUTTONUP;
372  }
373  SDL_SendMouseButton(window_data->window, 0, sdl_button_state, sdl_button);
374  return SDL_GetEventState(sdl_event_type) == SDL_ENABLE;
375 }
376 
377 static EM_BOOL
378 Emscripten_HandleMouseFocus(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
379 {
380  SDL_WindowData *window_data = userData;
381 
382  int mx = mouseEvent->canvasX, my = mouseEvent->canvasY;
383  const int isPointerLocked = window_data->has_pointer_lock;
384 
385  if (!isPointerLocked) {
386  /* rescale (in case canvas is being scaled)*/
387  double client_w, client_h;
388  emscripten_get_element_css_size(NULL, &client_w, &client_h);
389 
390  mx = mx * (window_data->window->w / client_w);
391  my = my * (window_data->window->h / client_h);
392  SDL_SendMouseMotion(window_data->window, 0, isPointerLocked, mx, my);
393  }
394 
395  SDL_SetMouseFocus(eventType == EMSCRIPTEN_EVENT_MOUSEENTER ? window_data->window : NULL);
397 }
398 
399 static EM_BOOL
400 Emscripten_HandleWheel(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)
401 {
402  SDL_WindowData *window_data = userData;
403  SDL_SendMouseWheel(window_data->window, 0, (float)wheelEvent->deltaX, (float)-wheelEvent->deltaY, SDL_MOUSEWHEEL_NORMAL);
405 }
406 
407 static EM_BOOL
408 Emscripten_HandleFocus(int eventType, const EmscriptenFocusEvent *wheelEvent, void *userData)
409 {
410  SDL_WindowData *window_data = userData;
411  /* If the user switches away while keys are pressed (such as
412  * via Alt+Tab), key release events won't be received. */
413  if (eventType == EMSCRIPTEN_EVENT_BLUR) {
415  }
416 
417 
418  SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_FOCUS ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
420 }
421 
422 static EM_BOOL
423 Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
424 {
425  SDL_WindowData *window_data = userData;
426  int i;
427  double client_w, client_h;
428  int preventDefault = 0;
429 
430  SDL_TouchID deviceId = 1;
431  if (SDL_AddTouch(deviceId, "") < 0) {
432  return 0;
433  }
434 
435  emscripten_get_element_css_size(NULL, &client_w, &client_h);
436 
437  for (i = 0; i < touchEvent->numTouches; i++) {
439  float x, y;
440  int mx, my;
441 
442  if (!touchEvent->touches[i].isChanged)
443  continue;
444 
445  id = touchEvent->touches[i].identifier;
446  x = touchEvent->touches[i].canvasX / client_w;
447  y = touchEvent->touches[i].canvasY / client_h;
448 
449  mx = x * window_data->window->w;
450  my = y * window_data->window->h;
451 
452  if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) {
453  if (!window_data->finger_touching) {
454  window_data->finger_touching = SDL_TRUE;
455  window_data->first_finger = id;
456  SDL_SendMouseMotion(window_data->window, SDL_TOUCH_MOUSEID, 0, mx, my);
458  }
459  SDL_SendTouch(deviceId, id, SDL_TRUE, x, y, 1.0f);
460 
461  if (!preventDefault && SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
462  preventDefault = 1;
463  }
464  } else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) {
465  if ((window_data->finger_touching) && (window_data->first_finger == id)) {
466  SDL_SendMouseMotion(window_data->window, SDL_TOUCH_MOUSEID, 0, mx, my);
467  }
468  SDL_SendTouchMotion(deviceId, id, x, y, 1.0f);
469 
470  if (!preventDefault && SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
471  preventDefault = 1;
472  }
473  } else {
474  if ((window_data->finger_touching) && (window_data->first_finger == id)) {
476  window_data->finger_touching = SDL_FALSE;
477  }
478  SDL_SendTouch(deviceId, id, SDL_FALSE, x, y, 1.0f);
479 
480  if (!preventDefault && SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
481  preventDefault = 1;
482  }
483  }
484  }
485 
486  return preventDefault;
487 }
488 
489 static EM_BOOL
490 Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
491 {
492  Uint32 scancode;
493  SDL_bool prevent_default;
494  SDL_bool is_nav_key;
495 
496  /* .keyCode is deprecated, but still the most reliable way to get keys */
497  if (keyEvent->keyCode < SDL_arraysize(emscripten_scancode_table)) {
498  scancode = emscripten_scancode_table[keyEvent->keyCode];
499 
500  if (scancode != SDL_SCANCODE_UNKNOWN) {
501 
502  if (keyEvent->location == DOM_KEY_LOCATION_RIGHT) {
503  switch (scancode) {
504  case SDL_SCANCODE_LSHIFT:
505  scancode = SDL_SCANCODE_RSHIFT;
506  break;
507  case SDL_SCANCODE_LCTRL:
508  scancode = SDL_SCANCODE_RCTRL;
509  break;
510  case SDL_SCANCODE_LALT:
511  scancode = SDL_SCANCODE_RALT;
512  break;
513  case SDL_SCANCODE_LGUI:
514  scancode = SDL_SCANCODE_RGUI;
515  break;
516  }
517  }
518  SDL_SendKeyboardKey(eventType == EMSCRIPTEN_EVENT_KEYDOWN ? SDL_PRESSED : SDL_RELEASED, scancode);
519  }
520  }
521 
522  prevent_default = SDL_GetEventState(eventType == EMSCRIPTEN_EVENT_KEYDOWN ? SDL_KEYDOWN : SDL_KEYUP) == SDL_ENABLE;
523 
524  /* if TEXTINPUT events are enabled we can't prevent keydown or we won't get keypress
525  * we need to ALWAYS prevent backspace and tab otherwise chrome takes action and does bad navigation UX
526  */
527  is_nav_key = keyEvent->keyCode == 8 /* backspace */ ||
528  keyEvent->keyCode == 9 /* tab */ ||
529  keyEvent->keyCode == 37 /* left */ ||
530  keyEvent->keyCode == 38 /* up */ ||
531  keyEvent->keyCode == 39 /* right */ ||
532  keyEvent->keyCode == 40 /* down */;
533 
534  if (eventType == EMSCRIPTEN_EVENT_KEYDOWN && SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE && !is_nav_key)
535  prevent_default = SDL_FALSE;
536 
537  return prevent_default;
538 }
539 
540 static EM_BOOL
541 Emscripten_HandleKeyPress(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
542 {
543  char text[5];
544  if (Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text)) {
545  SDL_SendKeyboardText(text);
546  }
548 }
549 
550 static EM_BOOL
551 Emscripten_HandleFullscreenChange(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData)
552 {
553  SDL_WindowData *window_data = userData;
554  if(fullscreenChangeEvent->isFullscreen)
555  {
556  window_data->window->flags |= window_data->requested_fullscreen_mode;
557 
558  window_data->requested_fullscreen_mode = 0;
559 
560  if(!window_data->requested_fullscreen_mode)
561  window_data->window->flags |= SDL_WINDOW_FULLSCREEN; /*we didn't reqest fullscreen*/
562  }
563  else
564  {
565  window_data->window->flags &= ~FULLSCREEN_MASK;
566  }
567 
568  return 0;
569 }
570 
571 static EM_BOOL
572 Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)
573 {
574  SDL_WindowData *window_data = userData;
575 
576  /* update pixel ratio */
577  if (window_data->window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
578  window_data->pixel_ratio = emscripten_get_device_pixel_ratio();
579  }
580 
581  if(!(window_data->window->flags & FULLSCREEN_MASK))
582  {
583  /* this will only work if the canvas size is set through css */
584  if(window_data->window->flags & SDL_WINDOW_RESIZABLE)
585  {
586  double w = window_data->window->w;
587  double h = window_data->window->h;
588 
589  if(window_data->external_size) {
590  emscripten_get_element_css_size(NULL, &w, &h);
591  }
592 
593  emscripten_set_canvas_size(w * window_data->pixel_ratio, h * window_data->pixel_ratio);
594 
595  /* set_canvas_size unsets this */
596  if (!window_data->external_size && window_data->pixel_ratio != 1.0f) {
597  emscripten_set_element_css_size(NULL, w, h);
598  }
599 
601  }
602  }
603 
604  return 0;
605 }
606 
607 EM_BOOL
608 Emscripten_HandleCanvasResize(int eventType, const void *reserved, void *userData)
609 {
610  /*this is used during fullscreen changes*/
611  SDL_WindowData *window_data = userData;
612 
613  if(window_data->fullscreen_resize)
614  {
615  double css_w, css_h;
616  emscripten_get_element_css_size(NULL, &css_w, &css_h);
617  SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, css_w, css_h);
618  }
619 
620  return 0;
621 }
622 
623 static EM_BOOL
624 Emscripten_HandleVisibilityChange(int eventType, const EmscriptenVisibilityChangeEvent *visEvent, void *userData)
625 {
626  SDL_WindowData *window_data = userData;
627  SDL_SendWindowEvent(window_data->window, visEvent->hidden ? SDL_WINDOWEVENT_HIDDEN : SDL_WINDOWEVENT_SHOWN, 0, 0);
628  return 0;
629 }
630 
631 void
633 {
634  const char *keyElement;
635 
636  /* There is only one window and that window is the canvas */
637  emscripten_set_mousemove_callback("#canvas", data, 0, Emscripten_HandleMouseMove);
638 
639  emscripten_set_mousedown_callback("#canvas", data, 0, Emscripten_HandleMouseButton);
640  emscripten_set_mouseup_callback("#document", data, 0, Emscripten_HandleMouseButton);
641 
642  emscripten_set_mouseenter_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
643  emscripten_set_mouseleave_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
644 
645  emscripten_set_wheel_callback("#canvas", data, 0, Emscripten_HandleWheel);
646 
647  emscripten_set_focus_callback("#window", data, 0, Emscripten_HandleFocus);
648  emscripten_set_blur_callback("#window", data, 0, Emscripten_HandleFocus);
649 
650  emscripten_set_touchstart_callback("#canvas", data, 0, Emscripten_HandleTouch);
651  emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch);
652  emscripten_set_touchmove_callback("#canvas", data, 0, Emscripten_HandleTouch);
653  emscripten_set_touchcancel_callback("#canvas", data, 0, Emscripten_HandleTouch);
654 
655  emscripten_set_pointerlockchange_callback("#document", data, 0, Emscripten_HandlePointerLockChange);
656 
657  /* Keyboard events are awkward */
659  if (!keyElement) keyElement = "#window";
660 
661  emscripten_set_keydown_callback(keyElement, data, 0, Emscripten_HandleKey);
662  emscripten_set_keyup_callback(keyElement, data, 0, Emscripten_HandleKey);
663  emscripten_set_keypress_callback(keyElement, data, 0, Emscripten_HandleKeyPress);
664 
665  emscripten_set_fullscreenchange_callback("#document", data, 0, Emscripten_HandleFullscreenChange);
666 
667  emscripten_set_resize_callback("#window", data, 0, Emscripten_HandleResize);
668 
669  emscripten_set_visibilitychange_callback(data, 0, Emscripten_HandleVisibilityChange);
670 }
671 
672 void
674 {
675  const char *target;
676 
677  /* only works due to having one window */
678  emscripten_set_mousemove_callback("#canvas", NULL, 0, NULL);
679 
680  emscripten_set_mousedown_callback("#canvas", NULL, 0, NULL);
681  emscripten_set_mouseup_callback("#document", NULL, 0, NULL);
682 
683  emscripten_set_mouseenter_callback("#canvas", NULL, 0, NULL);
684  emscripten_set_mouseleave_callback("#canvas", NULL, 0, NULL);
685 
686  emscripten_set_wheel_callback("#canvas", NULL, 0, NULL);
687 
688  emscripten_set_focus_callback("#window", NULL, 0, NULL);
689  emscripten_set_blur_callback("#window", NULL, 0, NULL);
690 
691  emscripten_set_touchstart_callback("#canvas", NULL, 0, NULL);
692  emscripten_set_touchend_callback("#canvas", NULL, 0, NULL);
693  emscripten_set_touchmove_callback("#canvas", NULL, 0, NULL);
694  emscripten_set_touchcancel_callback("#canvas", NULL, 0, NULL);
695 
696  emscripten_set_pointerlockchange_callback("#document", NULL, 0, NULL);
697 
699  if (!target) {
700  target = "#window";
701  }
702 
703  emscripten_set_keydown_callback(target, NULL, 0, NULL);
704  emscripten_set_keyup_callback(target, NULL, 0, NULL);
705  emscripten_set_keypress_callback(target, NULL, 0, NULL);
706 
707  emscripten_set_fullscreenchange_callback("#document", NULL, 0, NULL);
708 
709  emscripten_set_resize_callback("#window", NULL, 0, NULL);
710 
711  emscripten_set_visibilitychange_callback(NULL, 0, NULL);
712 }
713 
714 #endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
715 
716 /* vi: set ts=4 sw=4 expandtab: */
GLuint id
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:112
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
EM_BOOL Emscripten_HandleCanvasResize(int eventType, const void *reserved, void *userData)
Sint64 SDL_FingerID
Definition: SDL_touch.h:42
GLfloat GLfloat GLfloat GLfloat h
#define SDL_BUTTON_RIGHT
Definition: SDL_mouse.h:284
#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:222
#define SDL_ENABLE
Definition: SDL_events.h:722
GLfloat f
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
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:151
uint32_t Uint32
Definition: SDL_stdinc.h:181
#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:679
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, float x, float y, float pressure)
Definition: SDL_touch.c:284
#define SDL_GetEventState(type)
Definition: SDL_events.h:735
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:237
#define SDL_BUTTON_LEFT
Definition: SDL_mouse.h:282
uint8_t Uint8
Definition: SDL_stdinc.h:157
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:789
GLubyte GLubyte GLubyte GLubyte w
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
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
int SDL_AddTouch(SDL_TouchID touchID, const char *name)
Definition: SDL_touch.c:136
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
GLenum target
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:139
int SDL_SendMouseWheel(SDL_Window *window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction)
Definition: SDL_mouse.c:512
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:47
void SDL_ResetKeyboard(void)
Definition: SDL_keyboard.c:572
#define SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT
override the binding element for keyboard inputs for Emscripten builds
Definition: SDL_hints.h:779
GLenum GLenum GLuint GLint GLint GLint yscale
Definition: gl2ext.h:2243
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
GLenum GLenum GLuint GLint GLint xscale
Definition: gl2ext.h:2243
#define FULLSCREEN_MASK
Definition: SDL_video.c:147
#define SDL_PRESSED
Definition: SDL_events.h:50
void Emscripten_UnregisterEventHandlers(SDL_WindowData *data)
Uint32 flags
Definition: SDL_sysvideo.h:83
#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:506
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:43
SDL_bool fullscreen_resize