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_UNKNOWN,
221  /* 175 */ SDL_SCANCODE_UNKNOWN,
222  /* 176 */ SDL_SCANCODE_UNKNOWN,
223  /* 177 */ SDL_SCANCODE_UNKNOWN,
224  /* 178 */ SDL_SCANCODE_UNKNOWN,
225  /* 179 */ SDL_SCANCODE_UNKNOWN,
226  /* 180 */ SDL_SCANCODE_UNKNOWN,
227  /* 181 */ SDL_SCANCODE_UNKNOWN,
228  /* 182 */ SDL_SCANCODE_UNKNOWN,
229  /* 183 */ SDL_SCANCODE_UNKNOWN,
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 = mouseEvent->canvasX, my = mouseEvent->canvasY;
305  EmscriptenPointerlockChangeEvent pointerlock_status;
306 
307  /* check for pointer lock */
308  emscripten_get_pointerlock_status(&pointerlock_status);
309 
310  if (pointerlock_status.isActive) {
311  mx = mouseEvent->movementX;
312  my = mouseEvent->movementY;
313  }
314 
315  /* rescale (in case canvas is being scaled)*/
316  double client_w, client_h;
317  emscripten_get_element_css_size(NULL, &client_w, &client_h);
318 
319  mx = mx * (window_data->window->w / (client_w * window_data->pixel_ratio));
320  my = my * (window_data->window->h / (client_h * window_data->pixel_ratio));
321 
322  SDL_SendMouseMotion(window_data->window, 0, pointerlock_status.isActive, mx, my);
323  return 0;
324 }
325 
326 EM_BOOL
327 Emscripten_HandleMouseButton(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
328 {
329  SDL_WindowData *window_data = userData;
330  uint32_t sdl_button;
331  switch (mouseEvent->button) {
332  case 0:
333  sdl_button = SDL_BUTTON_LEFT;
334  break;
335  case 1:
336  sdl_button = SDL_BUTTON_MIDDLE;
337  break;
338  case 2:
339  sdl_button = SDL_BUTTON_RIGHT;
340  break;
341  default:
342  return 0;
343  }
344  SDL_SendMouseButton(window_data->window, 0, eventType == EMSCRIPTEN_EVENT_MOUSEDOWN ? SDL_PRESSED : SDL_RELEASED, sdl_button);
345  return 1;
346 }
347 
348 EM_BOOL
349 Emscripten_HandleMouseFocus(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
350 {
351  SDL_WindowData *window_data = userData;
352  SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_MOUSEENTER ? SDL_WINDOWEVENT_ENTER : SDL_WINDOWEVENT_LEAVE, 0, 0);
353  return 1;
354 }
355 
356 EM_BOOL
357 Emscripten_HandleWheel(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)
358 {
359  SDL_WindowData *window_data = userData;
360  SDL_SendMouseWheel(window_data->window, 0, wheelEvent->deltaX, -wheelEvent->deltaY, SDL_MOUSEWHEEL_NORMAL);
361  return 1;
362 }
363 
364 EM_BOOL
365 Emscripten_HandleFocus(int eventType, const EmscriptenFocusEvent *wheelEvent, void *userData)
366 {
367  SDL_WindowData *window_data = userData;
368  SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_FOCUS ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
369  return 1;
370 }
371 
372 EM_BOOL
373 Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
374 {
375  SDL_WindowData *window_data = userData;
376  int i;
377 
378  SDL_TouchID deviceId = 1;
379  if (SDL_AddTouch(deviceId, "") < 0) {
380  return 0;
381  }
382 
383  for (i = 0; i < touchEvent->numTouches; i++) {
385  float x, y;
386 
387  if (!touchEvent->touches[i].isChanged)
388  continue;
389 
390  id = touchEvent->touches[i].identifier;
391  x = touchEvent->touches[i].canvasX / (float)window_data->windowed_width;
392  y = touchEvent->touches[i].canvasY / (float)window_data->windowed_height;
393 
394  if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) {
395  SDL_SendTouchMotion(deviceId, id, x, y, 1.0f);
396  } else if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) {
397  SDL_SendTouch(deviceId, id, SDL_TRUE, x, y, 1.0f);
398  } else {
399  SDL_SendTouch(deviceId, id, SDL_FALSE, x, y, 1.0f);
400  }
401  }
402 
403 
404  return 1;
405 }
406 
407 EM_BOOL
408 Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
409 {
410  Uint32 scancode;
411 
412  /* .keyCode is deprecated, but still the most reliable way to get keys */
413  if (keyEvent->keyCode < SDL_arraysize(emscripten_scancode_table)) {
414  scancode = emscripten_scancode_table[keyEvent->keyCode];
415 
416  if (scancode != SDL_SCANCODE_UNKNOWN) {
417 
418  if (keyEvent->location == DOM_KEY_LOCATION_RIGHT) {
419  switch (scancode) {
420  case SDL_SCANCODE_LSHIFT:
421  scancode = SDL_SCANCODE_RSHIFT;
422  break;
423  case SDL_SCANCODE_LCTRL:
424  scancode = SDL_SCANCODE_RCTRL;
425  break;
426  case SDL_SCANCODE_LALT:
427  scancode = SDL_SCANCODE_RALT;
428  break;
429  case SDL_SCANCODE_LGUI:
430  scancode = SDL_SCANCODE_RGUI;
431  break;
432  }
433  }
434  SDL_SendKeyboardKey(eventType == EMSCRIPTEN_EVENT_KEYDOWN ?
435  SDL_PRESSED : SDL_RELEASED, scancode);
436  }
437  }
438 
439  /* if we prevent keydown, we won't get keypress
440  * also we need to ALWAYS prevent backspace and tab otherwise chrome takes action and does bad navigation UX
441  */
442  return SDL_GetEventState(SDL_TEXTINPUT) != SDL_ENABLE || eventType != EMSCRIPTEN_EVENT_KEYDOWN
443  || keyEvent->keyCode == 8 /* backspace */ || keyEvent->keyCode == 9 /* tab */;
444 }
445 
446 EM_BOOL
447 Emscripten_HandleKeyPress(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
448 {
449  char text[5];
450  if (Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text)) {
451  SDL_SendKeyboardText(text);
452  }
453  return 1;
454 }
455 
456 EM_BOOL
457 Emscripten_HandleFullscreenChange(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData)
458 {
459  /*make sure this is actually our element going fullscreen*/
460  if(SDL_strcmp(fullscreenChangeEvent->id, "SDLFullscreenElement") != 0)
461  return 0;
462 
463  SDL_WindowData *window_data = userData;
464  if(fullscreenChangeEvent->isFullscreen)
465  {
466  SDL_bool is_desktop_fullscreen;
467  window_data->window->flags |= window_data->requested_fullscreen_mode;
468 
469  if(!window_data->requested_fullscreen_mode)
470  window_data->window->flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; /*we didn't reqest fullscreen*/
471 
472  window_data->requested_fullscreen_mode = 0;
473 
474  is_desktop_fullscreen = (window_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
475 
476  /*update size*/
477  if(window_data->window->flags & SDL_WINDOW_RESIZABLE || is_desktop_fullscreen)
478  {
479  emscripten_set_canvas_size(fullscreenChangeEvent->screenWidth, fullscreenChangeEvent->screenHeight);
480  SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, fullscreenChangeEvent->screenWidth, fullscreenChangeEvent->screenHeight);
481  }
482  else
483  {
484  /*preserve ratio*/
485  double w = window_data->window->w;
486  double h = window_data->window->h;
487  double factor = SDL_min(fullscreenChangeEvent->screenWidth / w, fullscreenChangeEvent->screenHeight / h);
488  emscripten_set_element_css_size(NULL, w * factor, h * factor);
489  }
490  }
491  else
492  {
493  EM_ASM({
494  //un-reparent canvas (similar to Module.requestFullscreen)
495  var canvas = Module['canvas'];
496  if(canvas.parentNode.id == "SDLFullscreenElement") {
497  var canvasContainer = canvas.parentNode;
498  canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
499  canvasContainer.parentNode.removeChild(canvasContainer);
500  }
501  });
502  double unscaled_w = window_data->windowed_width / window_data->pixel_ratio;
503  double unscaled_h = window_data->windowed_height / window_data->pixel_ratio;
504  emscripten_set_canvas_size(window_data->windowed_width, window_data->windowed_height);
505 
506  if (!window_data->external_size && window_data->pixel_ratio != 1.0f) {
507  emscripten_set_element_css_size(NULL, unscaled_w, unscaled_h);
508  }
509 
510  SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, unscaled_w, unscaled_h);
511 
512  window_data->window->flags &= ~FULLSCREEN_MASK;
513  }
514 
515  return 0;
516 }
517 
518 EM_BOOL
519 Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)
520 {
521  SDL_WindowData *window_data = userData;
522  if(window_data->window->flags & FULLSCREEN_MASK)
523  {
524  SDL_bool is_desktop_fullscreen = (window_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
525 
526  if(window_data->window->flags & SDL_WINDOW_RESIZABLE || is_desktop_fullscreen)
527  {
528  emscripten_set_canvas_size(uiEvent->windowInnerWidth * window_data->pixel_ratio, uiEvent->windowInnerHeight * window_data->pixel_ratio);
529  SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, uiEvent->windowInnerWidth, uiEvent->windowInnerHeight);
530  }
531  }
532  else
533  {
534  /* this will only work if the canvas size is set through css */
535  if(window_data->window->flags & SDL_WINDOW_RESIZABLE)
536  {
537  double w = window_data->window->w;
538  double h = window_data->window->h;
539 
540  if(window_data->external_size) {
541  emscripten_get_element_css_size(NULL, &w, &h);
542  }
543 
544  emscripten_set_canvas_size(w * window_data->pixel_ratio, h * window_data->pixel_ratio);
545 
546  /* set_canvas_size unsets this */
547  if (!window_data->external_size && window_data->pixel_ratio != 1.0f) {
548  emscripten_set_element_css_size(NULL, w, h);
549  }
550 
552  }
553  }
554 
555  return 0;
556 }
557 
558 EM_BOOL
559 Emscripten_HandleVisibilityChange(int eventType, const EmscriptenVisibilityChangeEvent *visEvent, void *userData)
560 {
561  SDL_WindowData *window_data = userData;
562  SDL_SendWindowEvent(window_data->window, visEvent->hidden ? SDL_WINDOWEVENT_HIDDEN : SDL_WINDOWEVENT_SHOWN, 0, 0);
563  return 0;
564 }
565 
566 void
568 {
569  /* There is only one window and that window is the canvas */
570  emscripten_set_mousemove_callback("#canvas", data, 0, Emscripten_HandleMouseMove);
571 
572  emscripten_set_mousedown_callback("#canvas", data, 0, Emscripten_HandleMouseButton);
573  emscripten_set_mouseup_callback("#canvas", data, 0, Emscripten_HandleMouseButton);
574 
575  emscripten_set_mouseenter_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
576  emscripten_set_mouseleave_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
577 
578  emscripten_set_wheel_callback("#canvas", data, 0, Emscripten_HandleWheel);
579 
580  emscripten_set_focus_callback("#canvas", data, 0, Emscripten_HandleFocus);
581  emscripten_set_blur_callback("#canvas", data, 0, Emscripten_HandleFocus);
582 
583  emscripten_set_touchstart_callback("#canvas", data, 0, Emscripten_HandleTouch);
584  emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch);
585  emscripten_set_touchmove_callback("#canvas", data, 0, Emscripten_HandleTouch);
586  emscripten_set_touchcancel_callback("#canvas", data, 0, Emscripten_HandleTouch);
587 
588  /* Keyboard events are awkward */
589  const char *keyElement = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
590  if (!keyElement) keyElement = "#window";
591 
592  emscripten_set_keydown_callback(keyElement, data, 0, Emscripten_HandleKey);
593  emscripten_set_keyup_callback(keyElement, data, 0, Emscripten_HandleKey);
594  emscripten_set_keypress_callback(keyElement, data, 0, Emscripten_HandleKeyPress);
595 
596  emscripten_set_fullscreenchange_callback("#document", data, 0, Emscripten_HandleFullscreenChange);
597 
598  emscripten_set_resize_callback("#window", data, 0, Emscripten_HandleResize);
599 
600  emscripten_set_visibilitychange_callback(data, 0, Emscripten_HandleVisibilityChange);
601 }
602 
603 void
605 {
606  /* only works due to having one window */
607  emscripten_set_mousemove_callback("#canvas", NULL, 0, NULL);
608 
609  emscripten_set_mousedown_callback("#canvas", NULL, 0, NULL);
610  emscripten_set_mouseup_callback("#canvas", NULL, 0, NULL);
611 
612  emscripten_set_mouseenter_callback("#canvas", NULL, 0, NULL);
613  emscripten_set_mouseleave_callback("#canvas", NULL, 0, NULL);
614 
615  emscripten_set_wheel_callback("#canvas", NULL, 0, NULL);
616 
617  emscripten_set_focus_callback("#canvas", NULL, 0, NULL);
618  emscripten_set_blur_callback("#canvas", NULL, 0, NULL);
619 
620  emscripten_set_touchstart_callback("#canvas", NULL, 0, NULL);
621  emscripten_set_touchend_callback("#canvas", NULL, 0, NULL);
622  emscripten_set_touchmove_callback("#canvas", NULL, 0, NULL);
623  emscripten_set_touchcancel_callback("#canvas", NULL, 0, NULL);
624 
626  if (!target) {
627  target = "#window";
628  }
629 
630  emscripten_set_keydown_callback(target, NULL, 0, NULL);
631  emscripten_set_keyup_callback(target, NULL, 0, NULL);
632 
633  emscripten_set_keypress_callback(target, NULL, 0, NULL);
634 
635  emscripten_set_fullscreenchange_callback("#document", NULL, 0, NULL);
636 
637  emscripten_set_resize_callback("#window", NULL, 0, NULL);
638 
639  emscripten_set_visibilitychange_callback(NULL, 0, NULL);
640 }
641 
642 #endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
643 
644 /* vi: set ts=4 sw=4 expandtab: */
GLuint id
#define SDL_min(x, y)
Definition: SDL_stdinc.h:345
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:155
Sint64 SDL_FingerID
Definition: SDL_touch.h:42
#define SDL_BUTTON_RIGHT
Definition: SDL_mouse.h:282
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:718
GLfloat f
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
SDL_Window * window
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
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
SDL_bool
Definition: SDL_stdinc.h:126
#define SDL_GetEventState(type)
Definition: SDL_events.h:731
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:280
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:774
Sint64 SDL_TouchID
Definition: SDL_touch.h:41
#define SDL_BUTTON_MIDDLE
Definition: SDL_mouse.h:281
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:42
#define NULL
Definition: begin_code.h:143
unsigned int uint32_t
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:34
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
#define SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT
override the binding element for keyboard inputs for Emscripten builds
Definition: SDL_hints.h:610
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
int SDL_SendMouseWheel(SDL_Window *window, SDL_MouseID mouseID, int x, int y, SDL_MouseWheelDirection direction)
Definition: SDL_mouse.c:406
GLubyte GLubyte GLubyte GLubyte w
#define SDL_strcmp
#define FULLSCREEN_MASK
Definition: SDL_video.c:138
#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
GLenum target
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
Definition: SDL_mouse.c:326
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:43
GLfloat GLfloat GLfloat GLfloat h