src/video/emscripten/SDL_emscriptenevents.c
author Charlie Birks <admin@daftgames.net>
Tue, 13 Sep 2016 00:04:00 -0700
changeset 10337 8b18f8e41813
parent 10330 6928ce726856
child 10338 638ec32cfcce
permissions -rw-r--r--
Add mapping for media keys
     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     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     /* If the user switches away while keys are pressed (such as
   396      * via Alt+Tab), key release events won't be received. */
   397     if (eventType == EMSCRIPTEN_EVENT_BLUR) {
   398         SDL_ResetKeyboard();
   399     }
   400     SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_FOCUS ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
   401     return 1;
   402 }
   403 
   404 EM_BOOL
   405 Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
   406 {
   407     SDL_WindowData *window_data = userData;
   408     int i;
   409     double client_w, client_h;
   410 
   411     SDL_TouchID deviceId = 1;
   412     if (SDL_AddTouch(deviceId, "") < 0) {
   413          return 0;
   414     }
   415 
   416     emscripten_get_element_css_size(NULL, &client_w, &client_h);
   417 
   418     for (i = 0; i < touchEvent->numTouches; i++) {
   419         SDL_FingerID id;
   420         float x, y;
   421 
   422         if (!touchEvent->touches[i].isChanged)
   423             continue;
   424 
   425         id = touchEvent->touches[i].identifier;
   426         x = touchEvent->touches[i].canvasX / client_w;
   427         y = touchEvent->touches[i].canvasY / client_h;
   428 
   429         if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) {
   430             if (!window_data->finger_touching) {
   431                 window_data->finger_touching = SDL_TRUE;
   432                 window_data->first_finger = id;
   433                 SDL_SendMouseMotion(window_data->window, SDL_TOUCH_MOUSEID, 0, x, y);
   434                 SDL_SendMouseButton(window_data->window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
   435             }
   436             SDL_SendTouch(deviceId, id, SDL_TRUE, x, y, 1.0f);
   437         } else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) {
   438             if ((window_data->finger_touching) && (window_data->first_finger == id)) {
   439                 SDL_SendMouseMotion(window_data->window, SDL_TOUCH_MOUSEID, 0, x, y);
   440             }
   441             SDL_SendTouchMotion(deviceId, id, x, y, 1.0f);
   442         } else {
   443             if ((window_data->finger_touching) && (window_data->first_finger == id)) {
   444                 SDL_SendMouseButton(window_data->window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
   445                 window_data->finger_touching = SDL_FALSE;
   446             }
   447             SDL_SendTouch(deviceId, id, SDL_FALSE, x, y, 1.0f);
   448         }
   449     }
   450 
   451 
   452     return 1;
   453 }
   454 
   455 EM_BOOL
   456 Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
   457 {
   458     Uint32 scancode;
   459 
   460     /* .keyCode is deprecated, but still the most reliable way to get keys */
   461     if (keyEvent->keyCode < SDL_arraysize(emscripten_scancode_table)) {
   462         scancode = emscripten_scancode_table[keyEvent->keyCode];
   463 
   464         if (scancode != SDL_SCANCODE_UNKNOWN) {
   465 
   466             if (keyEvent->location == DOM_KEY_LOCATION_RIGHT) {
   467                 switch (scancode) {
   468                     case SDL_SCANCODE_LSHIFT:
   469                         scancode = SDL_SCANCODE_RSHIFT;
   470                         break;
   471                     case SDL_SCANCODE_LCTRL:
   472                         scancode = SDL_SCANCODE_RCTRL;
   473                         break;
   474                     case SDL_SCANCODE_LALT:
   475                         scancode = SDL_SCANCODE_RALT;
   476                         break;
   477                     case SDL_SCANCODE_LGUI:
   478                         scancode = SDL_SCANCODE_RGUI;
   479                         break;
   480                 }
   481             }
   482             SDL_SendKeyboardKey(eventType == EMSCRIPTEN_EVENT_KEYDOWN ?
   483                                 SDL_PRESSED : SDL_RELEASED, scancode);
   484         }
   485     }
   486 
   487     /* if we prevent keydown, we won't get keypress
   488      * also we need to ALWAYS prevent backspace and tab otherwise chrome takes action and does bad navigation UX
   489      */
   490     return SDL_GetEventState(SDL_TEXTINPUT) != SDL_ENABLE || eventType != EMSCRIPTEN_EVENT_KEYDOWN
   491             || keyEvent->keyCode == 8 /* backspace */ || keyEvent->keyCode == 9 /* tab */;
   492 }
   493 
   494 EM_BOOL
   495 Emscripten_HandleKeyPress(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
   496 {
   497     char text[5];
   498     if (Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text)) {
   499         SDL_SendKeyboardText(text);
   500     }
   501     return 1;
   502 }
   503 
   504 EM_BOOL
   505 Emscripten_HandleFullscreenChange(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData)
   506 {
   507     SDL_WindowData *window_data = userData;
   508     if(fullscreenChangeEvent->isFullscreen)
   509     {
   510         window_data->window->flags |= window_data->requested_fullscreen_mode;
   511 
   512         window_data->requested_fullscreen_mode = 0;
   513 
   514         if(!window_data->requested_fullscreen_mode)
   515             window_data->window->flags |= SDL_WINDOW_FULLSCREEN; /*we didn't reqest fullscreen*/
   516     }
   517     else
   518     {
   519         window_data->window->flags &= ~FULLSCREEN_MASK;
   520     }
   521 
   522     return 0;
   523 }
   524 
   525 EM_BOOL
   526 Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)
   527 {
   528     SDL_WindowData *window_data = userData;
   529     if(!(window_data->window->flags & FULLSCREEN_MASK))
   530     {
   531         /* this will only work if the canvas size is set through css */
   532         if(window_data->window->flags & SDL_WINDOW_RESIZABLE)
   533         {
   534             double w = window_data->window->w;
   535             double h = window_data->window->h;
   536 
   537             if(window_data->external_size) {
   538                 emscripten_get_element_css_size(NULL, &w, &h);
   539             }
   540 
   541             emscripten_set_canvas_size(w * window_data->pixel_ratio, h * window_data->pixel_ratio);
   542 
   543             /* set_canvas_size unsets this */
   544             if (!window_data->external_size && window_data->pixel_ratio != 1.0f) {
   545                 emscripten_set_element_css_size(NULL, w, h);
   546             }
   547 
   548             SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, w, h);
   549         }
   550     }
   551 
   552     return 0;
   553 }
   554 
   555 EM_BOOL
   556 Emscripten_HandleCanvasResize(int eventType, const void *reserved, void *userData)
   557 {
   558     /*this is used during fullscreen changes*/
   559     SDL_WindowData *window_data = userData;
   560 
   561     if(window_data->fullscreen_resize)
   562     {
   563         double css_w, css_h;
   564         emscripten_get_element_css_size(NULL, &css_w, &css_h);
   565         SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, css_w, css_h);
   566     }
   567 
   568     return 0;
   569 }
   570 
   571 EM_BOOL
   572 Emscripten_HandleVisibilityChange(int eventType, const EmscriptenVisibilityChangeEvent *visEvent, void *userData)
   573 {
   574     SDL_WindowData *window_data = userData;
   575     SDL_SendWindowEvent(window_data->window, visEvent->hidden ? SDL_WINDOWEVENT_HIDDEN : SDL_WINDOWEVENT_SHOWN, 0, 0);
   576     return 0;
   577 }
   578 
   579 void
   580 Emscripten_RegisterEventHandlers(SDL_WindowData *data)
   581 {
   582     /* There is only one window and that window is the canvas */
   583     emscripten_set_mousemove_callback("#canvas", data, 0, Emscripten_HandleMouseMove);
   584 
   585     emscripten_set_mousedown_callback("#canvas", data, 0, Emscripten_HandleMouseButton);
   586     emscripten_set_mouseup_callback("#document", data, 0, Emscripten_HandleMouseButton);
   587 
   588     emscripten_set_mouseenter_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
   589     emscripten_set_mouseleave_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
   590 
   591     emscripten_set_wheel_callback("#canvas", data, 0, Emscripten_HandleWheel);
   592 
   593     emscripten_set_focus_callback("#window", data, 0, Emscripten_HandleFocus);
   594     emscripten_set_blur_callback("#window", data, 0, Emscripten_HandleFocus);
   595 
   596     emscripten_set_touchstart_callback("#canvas", data, 0, Emscripten_HandleTouch);
   597     emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch);
   598     emscripten_set_touchmove_callback("#canvas", data, 0, Emscripten_HandleTouch);
   599     emscripten_set_touchcancel_callback("#canvas", data, 0, Emscripten_HandleTouch);
   600 
   601     /* Keyboard events are awkward */
   602     const char *keyElement = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
   603     if (!keyElement) keyElement = "#window";
   604 
   605     emscripten_set_keydown_callback(keyElement, data, 0, Emscripten_HandleKey);
   606     emscripten_set_keyup_callback(keyElement, data, 0, Emscripten_HandleKey);
   607     emscripten_set_keypress_callback(keyElement, data, 0, Emscripten_HandleKeyPress);
   608 
   609     emscripten_set_fullscreenchange_callback("#document", data, 0, Emscripten_HandleFullscreenChange);
   610 
   611     emscripten_set_resize_callback("#window", data, 0, Emscripten_HandleResize);
   612 
   613     emscripten_set_visibilitychange_callback(data, 0, Emscripten_HandleVisibilityChange);
   614 }
   615 
   616 void
   617 Emscripten_UnregisterEventHandlers(SDL_WindowData *data)
   618 {
   619     /* only works due to having one window */
   620     emscripten_set_mousemove_callback("#canvas", NULL, 0, NULL);
   621 
   622     emscripten_set_mousedown_callback("#canvas", NULL, 0, NULL);
   623     emscripten_set_mouseup_callback("#document", NULL, 0, NULL);
   624 
   625     emscripten_set_mouseenter_callback("#canvas", NULL, 0, NULL);
   626     emscripten_set_mouseleave_callback("#canvas", NULL, 0, NULL);
   627 
   628     emscripten_set_wheel_callback("#canvas", NULL, 0, NULL);
   629 
   630     emscripten_set_focus_callback("#window", NULL, 0, NULL);
   631     emscripten_set_blur_callback("#window", NULL, 0, NULL);
   632 
   633     emscripten_set_touchstart_callback("#canvas", NULL, 0, NULL);
   634     emscripten_set_touchend_callback("#canvas", NULL, 0, NULL);
   635     emscripten_set_touchmove_callback("#canvas", NULL, 0, NULL);
   636     emscripten_set_touchcancel_callback("#canvas", NULL, 0, NULL);
   637 
   638     const char *target = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
   639     if (!target) {
   640         target = "#window";
   641     }
   642 
   643     emscripten_set_keydown_callback(target, NULL, 0, NULL);
   644     emscripten_set_keyup_callback(target, NULL, 0, NULL);
   645 
   646     emscripten_set_keypress_callback(target, NULL, 0, NULL);
   647 
   648     emscripten_set_fullscreenchange_callback("#document", NULL, 0, NULL);
   649 
   650     emscripten_set_resize_callback("#window", NULL, 0, NULL);
   651 
   652     emscripten_set_visibilitychange_callback(NULL, 0, NULL);
   653 }
   654 
   655 #endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
   656 
   657 /* vi: set ts=4 sw=4 expandtab: */