src/video/emscripten/SDL_emscriptenevents.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 28 May 2015 12:55:01 -0700
changeset 9679 7fc4a8be47a8
parent 9619 b94b6d0bff0f
child 9725 6bfe2f6069b0
permissions -rw-r--r--
Fixed bug 2054 - SDL_GetError: "Unknown touch device"

Volumetric

The "Unknown touch device" message appears because the initial touch device setup loop uses SDL_GetTouch() as a guard for calling SDL_AddTouch(). SDL_GetTouch() will always report "Unknown touch device" since the device hasn't been added yet. The SDL_GetTouch() call is unnecessary since SDL_AddTouch() calls SDL_GetTouchIndex() to verify that the device hasn't been added yet, and SDL_GetTouchIndex() has the benefit of not reporting an error for a device it can't find.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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 = 0;
   379     if (SDL_AddTouch(deviceId, "") < 0) {
   380          return 0;
   381     }
   382 
   383     for (i = 0; i < touchEvent->numTouches; i++) {
   384         SDL_FingerID id;
   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 
   551             SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, w, h);
   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
   567 Emscripten_RegisterEventHandlers(SDL_WindowData *data)
   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
   604 Emscripten_UnregisterEventHandlers(SDL_WindowData *data)
   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 
   625     const char *target = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
   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: */