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