src/video/emscripten/SDL_emscriptenevents.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sat, 16 May 2015 21:15:27 +0200
changeset 9601 4c65108b7ac3
parent 9591 ebc2a308211b
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Emscripten: Fixed wrong source comment and updated web link.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_GetTouch(deviceId)) {
   380         if (SDL_AddTouch(deviceId, "") < 0) {
   381              return 0;
   382         }
   383     }
   384 
   385     for (i = 0; i < touchEvent->numTouches; i++) {
   386         SDL_FingerID id;
   387         float x, y;
   388 
   389         if (!touchEvent->touches[i].isChanged)
   390             continue;
   391 
   392         id = touchEvent->touches[i].identifier;
   393         x = touchEvent->touches[i].canvasX / (float)window_data->windowed_width;
   394         y = touchEvent->touches[i].canvasY / (float)window_data->windowed_height;
   395 
   396         if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) {
   397             SDL_SendTouchMotion(deviceId, id, x, y, 1.0f);
   398         } else if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) {
   399             SDL_SendTouch(deviceId, id, SDL_TRUE, x, y, 1.0f);
   400         } else {
   401             SDL_SendTouch(deviceId, id, SDL_FALSE, x, y, 1.0f);
   402         }
   403     }
   404 
   405 
   406     return 1;
   407 }
   408 
   409 EM_BOOL
   410 Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
   411 {
   412     Uint32 scancode;
   413 
   414     /* .keyCode is deprecated, but still the most reliable way to get keys */
   415     if (keyEvent->keyCode < SDL_arraysize(emscripten_scancode_table)) {
   416         scancode = emscripten_scancode_table[keyEvent->keyCode];
   417 
   418         if (scancode != SDL_SCANCODE_UNKNOWN) {
   419 
   420             if (keyEvent->location == DOM_KEY_LOCATION_RIGHT) {
   421                 switch (scancode) {
   422                     case SDL_SCANCODE_LSHIFT:
   423                         scancode = SDL_SCANCODE_RSHIFT;
   424                         break;
   425                     case SDL_SCANCODE_LCTRL:
   426                         scancode = SDL_SCANCODE_RCTRL;
   427                         break;
   428                     case SDL_SCANCODE_LALT:
   429                         scancode = SDL_SCANCODE_RALT;
   430                         break;
   431                     case SDL_SCANCODE_LGUI:
   432                         scancode = SDL_SCANCODE_RGUI;
   433                         break;
   434                 }
   435             }
   436             SDL_SendKeyboardKey(eventType == EMSCRIPTEN_EVENT_KEYDOWN ?
   437                                 SDL_PRESSED : SDL_RELEASED, scancode);
   438         }
   439     }
   440 
   441     /* if we prevent keydown, we won't get keypress
   442      * also we need to ALWAYS prevent backspace and tab otherwise chrome takes action and does bad navigation UX
   443      */
   444     return SDL_GetEventState(SDL_TEXTINPUT) != SDL_ENABLE || eventType != EMSCRIPTEN_EVENT_KEYDOWN
   445             || keyEvent->keyCode == 8 /* backspace */ || keyEvent->keyCode == 9 /* tab */;
   446 }
   447 
   448 EM_BOOL
   449 Emscripten_HandleKeyPress(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
   450 {
   451     char text[5];
   452     if (Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text)) {
   453         SDL_SendKeyboardText(text);
   454     }
   455     return 1;
   456 }
   457 
   458 EM_BOOL
   459 Emscripten_HandleFullscreenChange(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData)
   460 {
   461     /*make sure this is actually our element going fullscreen*/
   462     if(SDL_strcmp(fullscreenChangeEvent->id, "SDLFullscreenElement") != 0)
   463         return 0;
   464 
   465     SDL_WindowData *window_data = userData;
   466     if(fullscreenChangeEvent->isFullscreen)
   467     {
   468         SDL_bool is_desktop_fullscreen;
   469         window_data->window->flags |= window_data->requested_fullscreen_mode;
   470 
   471         if(!window_data->requested_fullscreen_mode)
   472             window_data->window->flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; /*we didn't reqest fullscreen*/
   473 
   474         window_data->requested_fullscreen_mode = 0;
   475 
   476         is_desktop_fullscreen = (window_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
   477 
   478         /*update size*/
   479         if(window_data->window->flags & SDL_WINDOW_RESIZABLE || is_desktop_fullscreen)
   480         {
   481             emscripten_set_canvas_size(fullscreenChangeEvent->screenWidth, fullscreenChangeEvent->screenHeight);
   482             SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, fullscreenChangeEvent->screenWidth, fullscreenChangeEvent->screenHeight);
   483         }
   484         else
   485         {
   486             /*preserve ratio*/
   487             double w = window_data->window->w;
   488             double h = window_data->window->h;
   489             double factor = SDL_min(fullscreenChangeEvent->screenWidth / w, fullscreenChangeEvent->screenHeight / h);
   490             emscripten_set_element_css_size(NULL, w * factor, h * factor);
   491         }
   492     }
   493     else
   494     {
   495         EM_ASM({
   496             //un-reparent canvas (similar to Module.requestFullscreen)
   497             var canvas = Module['canvas'];
   498             if(canvas.parentNode.id == "SDLFullscreenElement") {
   499                 var canvasContainer = canvas.parentNode;
   500                 canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
   501                 canvasContainer.parentNode.removeChild(canvasContainer);
   502             }
   503         });
   504         double unscaled_w = window_data->windowed_width / window_data->pixel_ratio;
   505         double unscaled_h = window_data->windowed_height / window_data->pixel_ratio;
   506         emscripten_set_canvas_size(window_data->windowed_width, window_data->windowed_height);
   507 
   508         if (!window_data->external_size && window_data->pixel_ratio != 1.0f) {
   509             emscripten_set_element_css_size(NULL, unscaled_w, unscaled_h);
   510         }
   511 
   512         SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, unscaled_w, unscaled_h);
   513 
   514         window_data->window->flags &= ~FULLSCREEN_MASK;
   515     }
   516 
   517     return 0;
   518 }
   519 
   520 EM_BOOL
   521 Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)
   522 {
   523     SDL_WindowData *window_data = userData;
   524     if(window_data->window->flags & FULLSCREEN_MASK)
   525     {
   526         SDL_bool is_desktop_fullscreen = (window_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
   527 
   528         if(window_data->window->flags & SDL_WINDOW_RESIZABLE || is_desktop_fullscreen)
   529         {
   530             emscripten_set_canvas_size(uiEvent->windowInnerWidth * window_data->pixel_ratio, uiEvent->windowInnerHeight * window_data->pixel_ratio);
   531             SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, uiEvent->windowInnerWidth, uiEvent->windowInnerHeight);
   532         }
   533     }
   534     else
   535     {
   536         /* this will only work if the canvas size is set through css */
   537         if(window_data->window->flags & SDL_WINDOW_RESIZABLE)
   538         {
   539             double w = window_data->window->w;
   540             double h = window_data->window->h;
   541 
   542             if(window_data->external_size) {
   543                 emscripten_get_element_css_size(NULL, &w, &h);
   544             }
   545 
   546             emscripten_set_canvas_size(w * window_data->pixel_ratio, h * window_data->pixel_ratio);
   547 
   548             /* set_canvas_size unsets this */
   549             if (!window_data->external_size && window_data->pixel_ratio != 1.0f) {
   550                 emscripten_set_element_css_size(NULL, w, h);
   551             }
   552 
   553             SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, w, h);
   554         }
   555     }
   556 
   557     return 0;
   558 }
   559 
   560 EM_BOOL
   561 Emscripten_HandleVisibilityChange(int eventType, const EmscriptenVisibilityChangeEvent *visEvent, void *userData)
   562 {
   563     SDL_WindowData *window_data = userData;
   564     SDL_SendWindowEvent(window_data->window, visEvent->hidden ? SDL_WINDOWEVENT_HIDDEN : SDL_WINDOWEVENT_SHOWN, 0, 0);
   565     return 0;
   566 }
   567 
   568 void
   569 Emscripten_RegisterEventHandlers(SDL_WindowData *data)
   570 {
   571     /* There is only one window and that window is the canvas */
   572     emscripten_set_mousemove_callback("#canvas", data, 0, Emscripten_HandleMouseMove);
   573 
   574     emscripten_set_mousedown_callback("#canvas", data, 0, Emscripten_HandleMouseButton);
   575     emscripten_set_mouseup_callback("#canvas", data, 0, Emscripten_HandleMouseButton);
   576 
   577     emscripten_set_mouseenter_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
   578     emscripten_set_mouseleave_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
   579 
   580     emscripten_set_wheel_callback("#canvas", data, 0, Emscripten_HandleWheel);
   581 
   582     emscripten_set_focus_callback("#canvas", data, 0, Emscripten_HandleFocus);
   583     emscripten_set_blur_callback("#canvas", data, 0, Emscripten_HandleFocus);
   584 
   585     emscripten_set_touchstart_callback("#canvas", data, 0, Emscripten_HandleTouch);
   586     emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch);
   587     emscripten_set_touchmove_callback("#canvas", data, 0, Emscripten_HandleTouch);
   588     emscripten_set_touchcancel_callback("#canvas", data, 0, Emscripten_HandleTouch);
   589 
   590     /* Keyboard events are awkward */
   591     const char *keyElement = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
   592     if (!keyElement) keyElement = "#window";
   593 
   594     emscripten_set_keydown_callback(keyElement, data, 0, Emscripten_HandleKey);
   595     emscripten_set_keyup_callback(keyElement, data, 0, Emscripten_HandleKey);
   596     emscripten_set_keypress_callback(keyElement, data, 0, Emscripten_HandleKeyPress);
   597 
   598     emscripten_set_fullscreenchange_callback("#document", data, 0, Emscripten_HandleFullscreenChange);
   599 
   600     emscripten_set_resize_callback("#window", data, 0, Emscripten_HandleResize);
   601 
   602     emscripten_set_visibilitychange_callback(data, 0, Emscripten_HandleVisibilityChange);
   603 }
   604 
   605 void
   606 Emscripten_UnregisterEventHandlers(SDL_WindowData *data)
   607 {
   608     /* only works due to having one window */
   609     emscripten_set_mousemove_callback("#canvas", NULL, 0, NULL);
   610 
   611     emscripten_set_mousedown_callback("#canvas", NULL, 0, NULL);
   612     emscripten_set_mouseup_callback("#canvas", NULL, 0, NULL);
   613 
   614     emscripten_set_mouseenter_callback("#canvas", NULL, 0, NULL);
   615     emscripten_set_mouseleave_callback("#canvas", NULL, 0, NULL);
   616 
   617     emscripten_set_wheel_callback("#canvas", NULL, 0, NULL);
   618 
   619     emscripten_set_focus_callback("#canvas", NULL, 0, NULL);
   620     emscripten_set_blur_callback("#canvas", NULL, 0, NULL);
   621 
   622     emscripten_set_touchstart_callback("#canvas", NULL, 0, NULL);
   623     emscripten_set_touchend_callback("#canvas", NULL, 0, NULL);
   624     emscripten_set_touchmove_callback("#canvas", NULL, 0, NULL);
   625     emscripten_set_touchcancel_callback("#canvas", NULL, 0, NULL);
   626 
   627     const char *target = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
   628     if (!target) {
   629         target = "#window";
   630     }
   631 
   632     emscripten_set_keydown_callback(target, NULL, 0, NULL);
   633     emscripten_set_keyup_callback(target, NULL, 0, NULL);
   634 
   635     emscripten_set_keypress_callback(target, NULL, 0, NULL);
   636 
   637     emscripten_set_fullscreenchange_callback("#document", NULL, 0, NULL);
   638 
   639     emscripten_set_resize_callback("#window", NULL, 0, NULL);
   640 
   641     emscripten_set_visibilitychange_callback(NULL, 0, NULL);
   642 }
   643 
   644 #endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
   645 
   646 /* vi: set ts=4 sw=4 expandtab: */