src/video/emscripten/SDL_emscriptenevents.c
author Boris Gjenero <boris.gjenero@gmail.com>
Tue, 13 Sep 2016 00:03:48 -0700
changeset 10327 47d840cce014
parent 10326 b7059a6e0de7
child 10328 3e6cd603c977
permissions -rw-r--r--
Listen for blur and focus events on window instead of canvas

Blur and focus events were not arriving for the canvas in
Firefox 35 and Chrome 40.
     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, 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     SDL_SendMouseButton(window_data->window, 0, eventType == EMSCRIPTEN_EVENT_MOUSEDOWN ? SDL_PRESSED : SDL_RELEASED, sdl_button);
   354     return 1;
   355 }
   356 
   357 EM_BOOL
   358 Emscripten_HandleMouseFocus(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
   359 {
   360     SDL_WindowData *window_data = userData;
   361 
   362     int mx = mouseEvent->canvasX, my = mouseEvent->canvasY;
   363     EmscriptenPointerlockChangeEvent pointerlock_status;
   364 
   365     /* check for pointer lock */
   366     int isPointerLockSupported = emscripten_get_pointerlock_status(&pointerlock_status);
   367     int isPointerLocked = isPointerLockSupported == EMSCRIPTEN_RESULT_SUCCESS  ? pointerlock_status.isActive : SDL_FALSE;
   368 
   369     if (!isPointerLocked) {
   370         /* rescale (in case canvas is being scaled)*/
   371         double client_w, client_h;
   372         emscripten_get_element_css_size(NULL, &client_w, &client_h);
   373 
   374         mx = mx * (window_data->window->w / client_w);
   375         my = my * (window_data->window->h / client_h);
   376         SDL_SendMouseMotion(window_data->window, 0, isPointerLocked, mx, my);
   377     }
   378 
   379     SDL_SetMouseFocus(eventType == EMSCRIPTEN_EVENT_MOUSEENTER ? window_data->window : NULL);
   380     return 1;
   381 }
   382 
   383 EM_BOOL
   384 Emscripten_HandleWheel(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)
   385 {
   386     SDL_WindowData *window_data = userData;
   387     SDL_SendMouseWheel(window_data->window, 0, wheelEvent->deltaX, -wheelEvent->deltaY, SDL_MOUSEWHEEL_NORMAL);
   388     return 1;
   389 }
   390 
   391 EM_BOOL
   392 Emscripten_HandleFocus(int eventType, const EmscriptenFocusEvent *wheelEvent, void *userData)
   393 {
   394     SDL_WindowData *window_data = userData;
   395     SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_FOCUS ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
   396     return 1;
   397 }
   398 
   399 EM_BOOL
   400 Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
   401 {
   402     SDL_WindowData *window_data = userData;
   403     int i;
   404     double client_w, client_h;
   405 
   406     SDL_TouchID deviceId = 1;
   407     if (SDL_AddTouch(deviceId, "") < 0) {
   408          return 0;
   409     }
   410 
   411     emscripten_get_element_css_size(NULL, &client_w, &client_h);
   412 
   413     for (i = 0; i < touchEvent->numTouches; i++) {
   414         SDL_FingerID id;
   415         float x, y;
   416 
   417         if (!touchEvent->touches[i].isChanged)
   418             continue;
   419 
   420         id = touchEvent->touches[i].identifier;
   421         x = touchEvent->touches[i].canvasX / client_w;
   422         y = touchEvent->touches[i].canvasY / client_h;
   423 
   424         if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) {
   425             if (!window_data->finger_touching) {
   426                 window_data->finger_touching = SDL_TRUE;
   427                 window_data->first_finger = id;
   428                 SDL_SendMouseMotion(window_data->window, SDL_TOUCH_MOUSEID, 0, x, y);
   429                 SDL_SendMouseButton(window_data->window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
   430             }
   431             SDL_SendTouch(deviceId, id, SDL_TRUE, x, y, 1.0f);
   432         } else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) {
   433             if ((window_data->finger_touching) && (window_data->first_finger == id)) {
   434                 SDL_SendMouseMotion(window_data->window, SDL_TOUCH_MOUSEID, 0, x, y);
   435             }
   436             SDL_SendTouchMotion(deviceId, id, x, y, 1.0f);
   437         } else {
   438             if ((window_data->finger_touching) && (window_data->first_finger == id)) {
   439                 SDL_SendMouseButton(window_data->window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
   440                 window_data->finger_touching = SDL_FALSE;
   441             }
   442             SDL_SendTouch(deviceId, id, SDL_FALSE, x, y, 1.0f);
   443         }
   444     }
   445 
   446 
   447     return 1;
   448 }
   449 
   450 EM_BOOL
   451 Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
   452 {
   453     Uint32 scancode;
   454 
   455     /* .keyCode is deprecated, but still the most reliable way to get keys */
   456     if (keyEvent->keyCode < SDL_arraysize(emscripten_scancode_table)) {
   457         scancode = emscripten_scancode_table[keyEvent->keyCode];
   458 
   459         if (scancode != SDL_SCANCODE_UNKNOWN) {
   460 
   461             if (keyEvent->location == DOM_KEY_LOCATION_RIGHT) {
   462                 switch (scancode) {
   463                     case SDL_SCANCODE_LSHIFT:
   464                         scancode = SDL_SCANCODE_RSHIFT;
   465                         break;
   466                     case SDL_SCANCODE_LCTRL:
   467                         scancode = SDL_SCANCODE_RCTRL;
   468                         break;
   469                     case SDL_SCANCODE_LALT:
   470                         scancode = SDL_SCANCODE_RALT;
   471                         break;
   472                     case SDL_SCANCODE_LGUI:
   473                         scancode = SDL_SCANCODE_RGUI;
   474                         break;
   475                 }
   476             }
   477             SDL_SendKeyboardKey(eventType == EMSCRIPTEN_EVENT_KEYDOWN ?
   478                                 SDL_PRESSED : SDL_RELEASED, scancode);
   479         }
   480     }
   481 
   482     /* if we prevent keydown, we won't get keypress
   483      * also we need to ALWAYS prevent backspace and tab otherwise chrome takes action and does bad navigation UX
   484      */
   485     return SDL_GetEventState(SDL_TEXTINPUT) != SDL_ENABLE || eventType != EMSCRIPTEN_EVENT_KEYDOWN
   486             || keyEvent->keyCode == 8 /* backspace */ || keyEvent->keyCode == 9 /* tab */;
   487 }
   488 
   489 EM_BOOL
   490 Emscripten_HandleKeyPress(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
   491 {
   492     char text[5];
   493     if (Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text)) {
   494         SDL_SendKeyboardText(text);
   495     }
   496     return 1;
   497 }
   498 
   499 EM_BOOL
   500 Emscripten_HandleFullscreenChange(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData)
   501 {
   502     SDL_WindowData *window_data = userData;
   503     if(fullscreenChangeEvent->isFullscreen)
   504     {
   505         SDL_bool is_desktop_fullscreen;
   506         window_data->window->flags |= window_data->requested_fullscreen_mode;
   507 
   508         window_data->requested_fullscreen_mode = 0;
   509 
   510         if(!window_data->requested_fullscreen_mode)
   511             window_data->window->flags |= SDL_WINDOW_FULLSCREEN; /*we didn't reqest fullscreen*/
   512     }
   513     else
   514     {
   515         window_data->window->flags &= ~FULLSCREEN_MASK;
   516     }
   517 
   518     return 0;
   519 }
   520 
   521 EM_BOOL
   522 Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)
   523 {
   524     SDL_WindowData *window_data = userData;
   525     if(!(window_data->window->flags & FULLSCREEN_MASK))
   526     {
   527         /* this will only work if the canvas size is set through css */
   528         if(window_data->window->flags & SDL_WINDOW_RESIZABLE)
   529         {
   530             double w = window_data->window->w;
   531             double h = window_data->window->h;
   532 
   533             if(window_data->external_size) {
   534                 emscripten_get_element_css_size(NULL, &w, &h);
   535             }
   536 
   537             emscripten_set_canvas_size(w * window_data->pixel_ratio, h * window_data->pixel_ratio);
   538 
   539             /* set_canvas_size unsets this */
   540             if (!window_data->external_size && window_data->pixel_ratio != 1.0f) {
   541                 emscripten_set_element_css_size(NULL, w, h);
   542             }
   543 
   544             SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, w, h);
   545         }
   546     }
   547 
   548     return 0;
   549 }
   550 
   551 EM_BOOL
   552 Emscripten_HandleCanvasResize(int eventType, const void *reserved, void *userData)
   553 {
   554     /*this is used during fullscreen changes*/
   555     SDL_WindowData *window_data = userData;
   556 
   557     if(window_data->fullscreen_resize)
   558     {
   559         double css_w, css_h;
   560         emscripten_get_element_css_size(NULL, &css_w, &css_h);
   561         SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, css_w, css_h);
   562     }
   563 
   564     return 0;
   565 }
   566 
   567 EM_BOOL
   568 Emscripten_HandleVisibilityChange(int eventType, const EmscriptenVisibilityChangeEvent *visEvent, void *userData)
   569 {
   570     SDL_WindowData *window_data = userData;
   571     SDL_SendWindowEvent(window_data->window, visEvent->hidden ? SDL_WINDOWEVENT_HIDDEN : SDL_WINDOWEVENT_SHOWN, 0, 0);
   572     return 0;
   573 }
   574 
   575 void
   576 Emscripten_RegisterEventHandlers(SDL_WindowData *data)
   577 {
   578     /* There is only one window and that window is the canvas */
   579     emscripten_set_mousemove_callback("#canvas", data, 0, Emscripten_HandleMouseMove);
   580 
   581     emscripten_set_mousedown_callback("#canvas", data, 0, Emscripten_HandleMouseButton);
   582     emscripten_set_mouseup_callback("#document", data, 0, Emscripten_HandleMouseButton);
   583 
   584     emscripten_set_mouseenter_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
   585     emscripten_set_mouseleave_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
   586 
   587     emscripten_set_wheel_callback("#canvas", data, 0, Emscripten_HandleWheel);
   588 
   589     emscripten_set_focus_callback("#window", data, 0, Emscripten_HandleFocus);
   590     emscripten_set_blur_callback("#window", data, 0, Emscripten_HandleFocus);
   591 
   592     emscripten_set_touchstart_callback("#canvas", data, 0, Emscripten_HandleTouch);
   593     emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch);
   594     emscripten_set_touchmove_callback("#canvas", data, 0, Emscripten_HandleTouch);
   595     emscripten_set_touchcancel_callback("#canvas", data, 0, Emscripten_HandleTouch);
   596 
   597     /* Keyboard events are awkward */
   598     const char *keyElement = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
   599     if (!keyElement) keyElement = "#window";
   600 
   601     emscripten_set_keydown_callback(keyElement, data, 0, Emscripten_HandleKey);
   602     emscripten_set_keyup_callback(keyElement, data, 0, Emscripten_HandleKey);
   603     emscripten_set_keypress_callback(keyElement, data, 0, Emscripten_HandleKeyPress);
   604 
   605     emscripten_set_fullscreenchange_callback("#document", data, 0, Emscripten_HandleFullscreenChange);
   606 
   607     emscripten_set_resize_callback("#window", data, 0, Emscripten_HandleResize);
   608 
   609     emscripten_set_visibilitychange_callback(data, 0, Emscripten_HandleVisibilityChange);
   610 }
   611 
   612 void
   613 Emscripten_UnregisterEventHandlers(SDL_WindowData *data)
   614 {
   615     /* only works due to having one window */
   616     emscripten_set_mousemove_callback("#canvas", NULL, 0, NULL);
   617 
   618     emscripten_set_mousedown_callback("#canvas", NULL, 0, NULL);
   619     emscripten_set_mouseup_callback("#document", NULL, 0, NULL);
   620 
   621     emscripten_set_mouseenter_callback("#canvas", NULL, 0, NULL);
   622     emscripten_set_mouseleave_callback("#canvas", NULL, 0, NULL);
   623 
   624     emscripten_set_wheel_callback("#canvas", NULL, 0, NULL);
   625 
   626     emscripten_set_focus_callback("#window", NULL, 0, NULL);
   627     emscripten_set_blur_callback("#window", NULL, 0, NULL);
   628 
   629     emscripten_set_touchstart_callback("#canvas", NULL, 0, NULL);
   630     emscripten_set_touchend_callback("#canvas", NULL, 0, NULL);
   631     emscripten_set_touchmove_callback("#canvas", NULL, 0, NULL);
   632     emscripten_set_touchcancel_callback("#canvas", NULL, 0, NULL);
   633 
   634     const char *target = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
   635     if (!target) {
   636         target = "#window";
   637     }
   638 
   639     emscripten_set_keydown_callback(target, NULL, 0, NULL);
   640     emscripten_set_keyup_callback(target, NULL, 0, NULL);
   641 
   642     emscripten_set_keypress_callback(target, NULL, 0, NULL);
   643 
   644     emscripten_set_fullscreenchange_callback("#document", NULL, 0, NULL);
   645 
   646     emscripten_set_resize_callback("#window", NULL, 0, NULL);
   647 
   648     emscripten_set_visibilitychange_callback(NULL, 0, NULL);
   649 }
   650 
   651 #endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
   652 
   653 /* vi: set ts=4 sw=4 expandtab: */