src/video/emscripten/SDL_emscriptenevents.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Wed, 06 May 2015 21:10:48 +0200
changeset 9591 ebc2a308211b
parent 9378 71743b696c06
child 9601 4c65108b7ac3
permissions -rw-r--r--
Emscripten: Fixed touch coordinates not being normalized.
     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 .which to scancode
    42 https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Constants
    43 */
    44 static const SDL_Scancode emscripten_scancode_table[] = {
    45     /*  0 */    SDL_SCANCODE_UNKNOWN,
    46     /*  1 */    SDL_SCANCODE_UNKNOWN,
    47     /*  2 */    SDL_SCANCODE_UNKNOWN,
    48     /*  3 */    SDL_SCANCODE_CANCEL,
    49     /*  4 */    SDL_SCANCODE_UNKNOWN,
    50     /*  5 */    SDL_SCANCODE_UNKNOWN,
    51     /*  6 */    SDL_SCANCODE_HELP,
    52     /*  7 */    SDL_SCANCODE_UNKNOWN,
    53     /*  8 */    SDL_SCANCODE_BACKSPACE,
    54     /*  9 */    SDL_SCANCODE_TAB,
    55     /*  10 */   SDL_SCANCODE_UNKNOWN,
    56     /*  11 */   SDL_SCANCODE_UNKNOWN,
    57     /*  12 */   SDL_SCANCODE_UNKNOWN,
    58     /*  13 */   SDL_SCANCODE_RETURN,
    59     /*  14 */   SDL_SCANCODE_UNKNOWN,
    60     /*  15 */   SDL_SCANCODE_UNKNOWN,
    61     /*  16 */   SDL_SCANCODE_LSHIFT,
    62     /*  17 */   SDL_SCANCODE_LCTRL,
    63     /*  18 */   SDL_SCANCODE_LALT,
    64     /*  19 */   SDL_SCANCODE_PAUSE,
    65     /*  20 */   SDL_SCANCODE_CAPSLOCK,
    66     /*  21 */   SDL_SCANCODE_UNKNOWN,
    67     /*  22 */   SDL_SCANCODE_UNKNOWN,
    68     /*  23 */   SDL_SCANCODE_UNKNOWN,
    69     /*  24 */   SDL_SCANCODE_UNKNOWN,
    70     /*  25 */   SDL_SCANCODE_UNKNOWN,
    71     /*  26 */   SDL_SCANCODE_UNKNOWN,
    72     /*  27 */   SDL_SCANCODE_ESCAPE,
    73     /*  28 */   SDL_SCANCODE_UNKNOWN,
    74     /*  29 */   SDL_SCANCODE_UNKNOWN,
    75     /*  30 */   SDL_SCANCODE_UNKNOWN,
    76     /*  31 */   SDL_SCANCODE_UNKNOWN,
    77     /*  32 */   SDL_SCANCODE_SPACE,
    78     /*  33 */   SDL_SCANCODE_PAGEUP,
    79     /*  34 */   SDL_SCANCODE_PAGEDOWN,
    80     /*  35 */   SDL_SCANCODE_END,
    81     /*  36 */   SDL_SCANCODE_HOME,
    82     /*  37 */   SDL_SCANCODE_LEFT,
    83     /*  38 */   SDL_SCANCODE_UP,
    84     /*  39 */   SDL_SCANCODE_RIGHT,
    85     /*  40 */   SDL_SCANCODE_DOWN,
    86     /*  41 */   SDL_SCANCODE_UNKNOWN,
    87     /*  42 */   SDL_SCANCODE_UNKNOWN,
    88     /*  43 */   SDL_SCANCODE_UNKNOWN,
    89     /*  44 */   SDL_SCANCODE_UNKNOWN,
    90     /*  45 */   SDL_SCANCODE_INSERT,
    91     /*  46 */   SDL_SCANCODE_DELETE,
    92     /*  47 */   SDL_SCANCODE_UNKNOWN,
    93     /*  48 */   SDL_SCANCODE_0,
    94     /*  49 */   SDL_SCANCODE_1,
    95     /*  50 */   SDL_SCANCODE_2,
    96     /*  51 */   SDL_SCANCODE_3,
    97     /*  52 */   SDL_SCANCODE_4,
    98     /*  53 */   SDL_SCANCODE_5,
    99     /*  54 */   SDL_SCANCODE_6,
   100     /*  55 */   SDL_SCANCODE_7,
   101     /*  56 */   SDL_SCANCODE_8,
   102     /*  57 */   SDL_SCANCODE_9,
   103     /*  58 */   SDL_SCANCODE_UNKNOWN,
   104     /*  59 */   SDL_SCANCODE_SEMICOLON,
   105     /*  60 */   SDL_SCANCODE_UNKNOWN,
   106     /*  61 */   SDL_SCANCODE_EQUALS,
   107     /*  62 */   SDL_SCANCODE_UNKNOWN,
   108     /*  63 */   SDL_SCANCODE_UNKNOWN,
   109     /*  64 */   SDL_SCANCODE_UNKNOWN,
   110     /*  65 */   SDL_SCANCODE_A,
   111     /*  66 */   SDL_SCANCODE_B,
   112     /*  67 */   SDL_SCANCODE_C,
   113     /*  68 */   SDL_SCANCODE_D,
   114     /*  69 */   SDL_SCANCODE_E,
   115     /*  70 */   SDL_SCANCODE_F,
   116     /*  71 */   SDL_SCANCODE_G,
   117     /*  72 */   SDL_SCANCODE_H,
   118     /*  73 */   SDL_SCANCODE_I,
   119     /*  74 */   SDL_SCANCODE_J,
   120     /*  75 */   SDL_SCANCODE_K,
   121     /*  76 */   SDL_SCANCODE_L,
   122     /*  77 */   SDL_SCANCODE_M,
   123     /*  78 */   SDL_SCANCODE_N,
   124     /*  79 */   SDL_SCANCODE_O,
   125     /*  80 */   SDL_SCANCODE_P,
   126     /*  81 */   SDL_SCANCODE_Q,
   127     /*  82 */   SDL_SCANCODE_R,
   128     /*  83 */   SDL_SCANCODE_S,
   129     /*  84 */   SDL_SCANCODE_T,
   130     /*  85 */   SDL_SCANCODE_U,
   131     /*  86 */   SDL_SCANCODE_V,
   132     /*  87 */   SDL_SCANCODE_W,
   133     /*  88 */   SDL_SCANCODE_X,
   134     /*  89 */   SDL_SCANCODE_Y,
   135     /*  90 */   SDL_SCANCODE_Z,
   136     /*  91 */   SDL_SCANCODE_LGUI,
   137     /*  92 */   SDL_SCANCODE_UNKNOWN,
   138     /*  93 */   SDL_SCANCODE_APPLICATION,
   139     /*  94 */   SDL_SCANCODE_UNKNOWN,
   140     /*  95 */   SDL_SCANCODE_UNKNOWN,
   141     /*  96 */   SDL_SCANCODE_KP_0,
   142     /*  97 */   SDL_SCANCODE_KP_1,
   143     /*  98 */   SDL_SCANCODE_KP_2,
   144     /*  99 */   SDL_SCANCODE_KP_3,
   145     /* 100 */   SDL_SCANCODE_KP_4,
   146     /* 101 */   SDL_SCANCODE_KP_5,
   147     /* 102 */   SDL_SCANCODE_KP_6,
   148     /* 103 */   SDL_SCANCODE_KP_7,
   149     /* 104 */   SDL_SCANCODE_KP_8,
   150     /* 105 */   SDL_SCANCODE_KP_9,
   151     /* 106 */   SDL_SCANCODE_KP_MULTIPLY,
   152     /* 107 */   SDL_SCANCODE_KP_PLUS,
   153     /* 108 */   SDL_SCANCODE_UNKNOWN,
   154     /* 109 */   SDL_SCANCODE_KP_MINUS,
   155     /* 110 */   SDL_SCANCODE_KP_PERIOD,
   156     /* 111 */   SDL_SCANCODE_KP_DIVIDE,
   157     /* 112 */   SDL_SCANCODE_F1,
   158     /* 113 */   SDL_SCANCODE_F2,
   159     /* 114 */   SDL_SCANCODE_F3,
   160     /* 115 */   SDL_SCANCODE_F4,
   161     /* 116 */   SDL_SCANCODE_F5,
   162     /* 117 */   SDL_SCANCODE_F6,
   163     /* 118 */   SDL_SCANCODE_F7,
   164     /* 119 */   SDL_SCANCODE_F8,
   165     /* 120 */   SDL_SCANCODE_F9,
   166     /* 121 */   SDL_SCANCODE_F10,
   167     /* 122 */   SDL_SCANCODE_F11,
   168     /* 123 */   SDL_SCANCODE_F12,
   169     /* 124 */   SDL_SCANCODE_F13,
   170     /* 125 */   SDL_SCANCODE_F14,
   171     /* 126 */   SDL_SCANCODE_F15,
   172     /* 127 */   SDL_SCANCODE_F16,
   173     /* 128 */   SDL_SCANCODE_F17,
   174     /* 129 */   SDL_SCANCODE_F18,
   175     /* 130 */   SDL_SCANCODE_F19,
   176     /* 131 */   SDL_SCANCODE_F20,
   177     /* 132 */   SDL_SCANCODE_F21,
   178     /* 133 */   SDL_SCANCODE_F22,
   179     /* 134 */   SDL_SCANCODE_F23,
   180     /* 135 */   SDL_SCANCODE_F24,
   181     /* 136 */   SDL_SCANCODE_UNKNOWN,
   182     /* 137 */   SDL_SCANCODE_UNKNOWN,
   183     /* 138 */   SDL_SCANCODE_UNKNOWN,
   184     /* 139 */   SDL_SCANCODE_UNKNOWN,
   185     /* 140 */   SDL_SCANCODE_UNKNOWN,
   186     /* 141 */   SDL_SCANCODE_UNKNOWN,
   187     /* 142 */   SDL_SCANCODE_UNKNOWN,
   188     /* 143 */   SDL_SCANCODE_UNKNOWN,
   189     /* 144 */   SDL_SCANCODE_NUMLOCKCLEAR,
   190     /* 145 */   SDL_SCANCODE_SCROLLLOCK,
   191     /* 146 */   SDL_SCANCODE_UNKNOWN,
   192     /* 147 */   SDL_SCANCODE_UNKNOWN,
   193     /* 148 */   SDL_SCANCODE_UNKNOWN,
   194     /* 149 */   SDL_SCANCODE_UNKNOWN,
   195     /* 150 */   SDL_SCANCODE_UNKNOWN,
   196     /* 151 */   SDL_SCANCODE_UNKNOWN,
   197     /* 152 */   SDL_SCANCODE_UNKNOWN,
   198     /* 153 */   SDL_SCANCODE_UNKNOWN,
   199     /* 154 */   SDL_SCANCODE_UNKNOWN,
   200     /* 155 */   SDL_SCANCODE_UNKNOWN,
   201     /* 156 */   SDL_SCANCODE_UNKNOWN,
   202     /* 157 */   SDL_SCANCODE_UNKNOWN,
   203     /* 158 */   SDL_SCANCODE_UNKNOWN,
   204     /* 159 */   SDL_SCANCODE_UNKNOWN,
   205     /* 160 */   SDL_SCANCODE_UNKNOWN,
   206     /* 161 */   SDL_SCANCODE_UNKNOWN,
   207     /* 162 */   SDL_SCANCODE_UNKNOWN,
   208     /* 163 */   SDL_SCANCODE_UNKNOWN,
   209     /* 164 */   SDL_SCANCODE_UNKNOWN,
   210     /* 165 */   SDL_SCANCODE_UNKNOWN,
   211     /* 166 */   SDL_SCANCODE_UNKNOWN,
   212     /* 167 */   SDL_SCANCODE_UNKNOWN,
   213     /* 168 */   SDL_SCANCODE_UNKNOWN,
   214     /* 169 */   SDL_SCANCODE_UNKNOWN,
   215     /* 170 */   SDL_SCANCODE_UNKNOWN,
   216     /* 171 */   SDL_SCANCODE_UNKNOWN,
   217     /* 172 */   SDL_SCANCODE_UNKNOWN,
   218     /* 173 */   SDL_SCANCODE_MINUS, /*FX*/
   219     /* 174 */   SDL_SCANCODE_UNKNOWN,
   220     /* 175 */   SDL_SCANCODE_UNKNOWN,
   221     /* 176 */   SDL_SCANCODE_UNKNOWN,
   222     /* 177 */   SDL_SCANCODE_UNKNOWN,
   223     /* 178 */   SDL_SCANCODE_UNKNOWN,
   224     /* 179 */   SDL_SCANCODE_UNKNOWN,
   225     /* 180 */   SDL_SCANCODE_UNKNOWN,
   226     /* 181 */   SDL_SCANCODE_UNKNOWN,
   227     /* 182 */   SDL_SCANCODE_UNKNOWN,
   228     /* 183 */   SDL_SCANCODE_UNKNOWN,
   229     /* 184 */   SDL_SCANCODE_UNKNOWN,
   230     /* 185 */   SDL_SCANCODE_UNKNOWN,
   231     /* 186 */   SDL_SCANCODE_SEMICOLON, /*IE, Chrome, D3E legacy*/
   232     /* 187 */   SDL_SCANCODE_EQUALS, /*IE, Chrome, D3E legacy*/
   233     /* 188 */   SDL_SCANCODE_COMMA,
   234     /* 189 */   SDL_SCANCODE_MINUS, /*IE, Chrome, D3E legacy*/
   235     /* 190 */   SDL_SCANCODE_PERIOD,
   236     /* 191 */   SDL_SCANCODE_SLASH,
   237     /* 192 */   SDL_SCANCODE_GRAVE, /*FX, D3E legacy (SDL_SCANCODE_APOSTROPHE in IE/Chrome)*/
   238     /* 193 */   SDL_SCANCODE_UNKNOWN,
   239     /* 194 */   SDL_SCANCODE_UNKNOWN,
   240     /* 195 */   SDL_SCANCODE_UNKNOWN,
   241     /* 196 */   SDL_SCANCODE_UNKNOWN,
   242     /* 197 */   SDL_SCANCODE_UNKNOWN,
   243     /* 198 */   SDL_SCANCODE_UNKNOWN,
   244     /* 199 */   SDL_SCANCODE_UNKNOWN,
   245     /* 200 */   SDL_SCANCODE_UNKNOWN,
   246     /* 201 */   SDL_SCANCODE_UNKNOWN,
   247     /* 202 */   SDL_SCANCODE_UNKNOWN,
   248     /* 203 */   SDL_SCANCODE_UNKNOWN,
   249     /* 204 */   SDL_SCANCODE_UNKNOWN,
   250     /* 205 */   SDL_SCANCODE_UNKNOWN,
   251     /* 206 */   SDL_SCANCODE_UNKNOWN,
   252     /* 207 */   SDL_SCANCODE_UNKNOWN,
   253     /* 208 */   SDL_SCANCODE_UNKNOWN,
   254     /* 209 */   SDL_SCANCODE_UNKNOWN,
   255     /* 210 */   SDL_SCANCODE_UNKNOWN,
   256     /* 211 */   SDL_SCANCODE_UNKNOWN,
   257     /* 212 */   SDL_SCANCODE_UNKNOWN,
   258     /* 213 */   SDL_SCANCODE_UNKNOWN,
   259     /* 214 */   SDL_SCANCODE_UNKNOWN,
   260     /* 215 */   SDL_SCANCODE_UNKNOWN,
   261     /* 216 */   SDL_SCANCODE_UNKNOWN,
   262     /* 217 */   SDL_SCANCODE_UNKNOWN,
   263     /* 218 */   SDL_SCANCODE_UNKNOWN,
   264     /* 219 */   SDL_SCANCODE_LEFTBRACKET,
   265     /* 220 */   SDL_SCANCODE_BACKSLASH,
   266     /* 221 */   SDL_SCANCODE_RIGHTBRACKET,
   267     /* 222 */   SDL_SCANCODE_APOSTROPHE, /*FX, D3E legacy*/
   268 };
   269 
   270 
   271 /* "borrowed" from SDL_windowsevents.c */
   272 int
   273 Emscripten_ConvertUTF32toUTF8(Uint32 codepoint, char * text)
   274 {
   275     if (codepoint <= 0x7F) {
   276         text[0] = (char) codepoint;
   277         text[1] = '\0';
   278     } else if (codepoint <= 0x7FF) {
   279         text[0] = 0xC0 | (char) ((codepoint >> 6) & 0x1F);
   280         text[1] = 0x80 | (char) (codepoint & 0x3F);
   281         text[2] = '\0';
   282     } else if (codepoint <= 0xFFFF) {
   283         text[0] = 0xE0 | (char) ((codepoint >> 12) & 0x0F);
   284         text[1] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
   285         text[2] = 0x80 | (char) (codepoint & 0x3F);
   286         text[3] = '\0';
   287     } else if (codepoint <= 0x10FFFF) {
   288         text[0] = 0xF0 | (char) ((codepoint >> 18) & 0x0F);
   289         text[1] = 0x80 | (char) ((codepoint >> 12) & 0x3F);
   290         text[2] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
   291         text[3] = 0x80 | (char) (codepoint & 0x3F);
   292         text[4] = '\0';
   293     } else {
   294         return SDL_FALSE;
   295     }
   296     return SDL_TRUE;
   297 }
   298 
   299 EM_BOOL
   300 Emscripten_HandleMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
   301 {
   302     SDL_WindowData *window_data = userData;
   303     int mx = mouseEvent->canvasX, my = mouseEvent->canvasY;
   304     EmscriptenPointerlockChangeEvent pointerlock_status;
   305 
   306     /* check for pointer lock */
   307     emscripten_get_pointerlock_status(&pointerlock_status);
   308 
   309     if (pointerlock_status.isActive) {
   310         mx = mouseEvent->movementX;
   311         my = mouseEvent->movementY;
   312     }
   313 
   314     /* rescale (in case canvas is being scaled)*/
   315     double client_w, client_h;
   316     emscripten_get_element_css_size(NULL, &client_w, &client_h);
   317 
   318     mx = mx * (window_data->window->w / (client_w * window_data->pixel_ratio));
   319     my = my * (window_data->window->h / (client_h * window_data->pixel_ratio));
   320 
   321     SDL_SendMouseMotion(window_data->window, 0, pointerlock_status.isActive, mx, my);
   322     return 0;
   323 }
   324 
   325 EM_BOOL
   326 Emscripten_HandleMouseButton(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
   327 {
   328     SDL_WindowData *window_data = userData;
   329     uint32_t sdl_button;
   330     switch (mouseEvent->button) {
   331         case 0:
   332             sdl_button = SDL_BUTTON_LEFT;
   333             break;
   334         case 1:
   335             sdl_button = SDL_BUTTON_MIDDLE;
   336             break;
   337         case 2:
   338             sdl_button = SDL_BUTTON_RIGHT;
   339             break;
   340         default:
   341             return 0;
   342     }
   343     SDL_SendMouseButton(window_data->window, 0, eventType == EMSCRIPTEN_EVENT_MOUSEDOWN ? SDL_PRESSED : SDL_RELEASED, sdl_button);
   344     return 1;
   345 }
   346 
   347 EM_BOOL
   348 Emscripten_HandleMouseFocus(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
   349 {
   350     SDL_WindowData *window_data = userData;
   351     SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_MOUSEENTER ? SDL_WINDOWEVENT_ENTER : SDL_WINDOWEVENT_LEAVE, 0, 0);
   352     return 1;
   353 }
   354 
   355 EM_BOOL
   356 Emscripten_HandleWheel(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)
   357 {
   358     SDL_WindowData *window_data = userData;
   359     SDL_SendMouseWheel(window_data->window, 0, wheelEvent->deltaX, -wheelEvent->deltaY, SDL_MOUSEWHEEL_NORMAL);
   360     return 1;
   361 }
   362 
   363 EM_BOOL
   364 Emscripten_HandleFocus(int eventType, const EmscriptenFocusEvent *wheelEvent, void *userData)
   365 {
   366     SDL_WindowData *window_data = userData;
   367     SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_FOCUS ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
   368     return 1;
   369 }
   370 
   371 EM_BOOL
   372 Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
   373 {
   374     SDL_WindowData *window_data = userData;
   375     int i;
   376 
   377     SDL_TouchID deviceId = 0;
   378     if (!SDL_GetTouch(deviceId)) {
   379         if (SDL_AddTouch(deviceId, "") < 0) {
   380              return 0;
   381         }
   382     }
   383 
   384     for (i = 0; i < touchEvent->numTouches; i++) {
   385         SDL_FingerID id;
   386         float x, y;
   387 
   388         if (!touchEvent->touches[i].isChanged)
   389             continue;
   390 
   391         id = touchEvent->touches[i].identifier;
   392         x = touchEvent->touches[i].canvasX / (float)window_data->windowed_width;
   393         y = touchEvent->touches[i].canvasY / (float)window_data->windowed_height;
   394 
   395         if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) {
   396             SDL_SendTouchMotion(deviceId, id, x, y, 1.0f);
   397         } else if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) {
   398             SDL_SendTouch(deviceId, id, SDL_TRUE, x, y, 1.0f);
   399         } else {
   400             SDL_SendTouch(deviceId, id, SDL_FALSE, x, y, 1.0f);
   401         }
   402     }
   403 
   404 
   405     return 1;
   406 }
   407 
   408 EM_BOOL
   409 Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
   410 {
   411     Uint32 scancode;
   412 
   413     /* .keyCode is deprecated, but still the most reliable way to get keys */
   414     if (keyEvent->keyCode < SDL_arraysize(emscripten_scancode_table)) {
   415         scancode = emscripten_scancode_table[keyEvent->keyCode];
   416 
   417         if (scancode != SDL_SCANCODE_UNKNOWN) {
   418 
   419             if (keyEvent->location == DOM_KEY_LOCATION_RIGHT) {
   420                 switch (scancode) {
   421                     case SDL_SCANCODE_LSHIFT:
   422                         scancode = SDL_SCANCODE_RSHIFT;
   423                         break;
   424                     case SDL_SCANCODE_LCTRL:
   425                         scancode = SDL_SCANCODE_RCTRL;
   426                         break;
   427                     case SDL_SCANCODE_LALT:
   428                         scancode = SDL_SCANCODE_RALT;
   429                         break;
   430                     case SDL_SCANCODE_LGUI:
   431                         scancode = SDL_SCANCODE_RGUI;
   432                         break;
   433                 }
   434             }
   435             SDL_SendKeyboardKey(eventType == EMSCRIPTEN_EVENT_KEYDOWN ?
   436                                 SDL_PRESSED : SDL_RELEASED, scancode);
   437         }
   438     }
   439 
   440     /* if we prevent keydown, we won't get keypress
   441      * also we need to ALWAYS prevent backspace and tab otherwise chrome takes action and does bad navigation UX
   442      */
   443     return SDL_GetEventState(SDL_TEXTINPUT) != SDL_ENABLE || eventType != EMSCRIPTEN_EVENT_KEYDOWN
   444             || keyEvent->keyCode == 8 /* backspace */ || keyEvent->keyCode == 9 /* tab */;
   445 }
   446 
   447 EM_BOOL
   448 Emscripten_HandleKeyPress(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
   449 {
   450     char text[5];
   451     if (Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text)) {
   452         SDL_SendKeyboardText(text);
   453     }
   454     return 1;
   455 }
   456 
   457 EM_BOOL
   458 Emscripten_HandleFullscreenChange(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData)
   459 {
   460     /*make sure this is actually our element going fullscreen*/
   461     if(SDL_strcmp(fullscreenChangeEvent->id, "SDLFullscreenElement") != 0)
   462         return 0;
   463 
   464     SDL_WindowData *window_data = userData;
   465     if(fullscreenChangeEvent->isFullscreen)
   466     {
   467         SDL_bool is_desktop_fullscreen;
   468         window_data->window->flags |= window_data->requested_fullscreen_mode;
   469 
   470         if(!window_data->requested_fullscreen_mode)
   471             window_data->window->flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; /*we didn't reqest fullscreen*/
   472 
   473         window_data->requested_fullscreen_mode = 0;
   474 
   475         is_desktop_fullscreen = (window_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
   476 
   477         /*update size*/
   478         if(window_data->window->flags & SDL_WINDOW_RESIZABLE || is_desktop_fullscreen)
   479         {
   480             emscripten_set_canvas_size(fullscreenChangeEvent->screenWidth, fullscreenChangeEvent->screenHeight);
   481             SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, fullscreenChangeEvent->screenWidth, fullscreenChangeEvent->screenHeight);
   482         }
   483         else
   484         {
   485             /*preserve ratio*/
   486             double w = window_data->window->w;
   487             double h = window_data->window->h;
   488             double factor = SDL_min(fullscreenChangeEvent->screenWidth / w, fullscreenChangeEvent->screenHeight / h);
   489             emscripten_set_element_css_size(NULL, w * factor, h * factor);
   490         }
   491     }
   492     else
   493     {
   494         EM_ASM({
   495             //un-reparent canvas (similar to Module.requestFullscreen)
   496             var canvas = Module['canvas'];
   497             if(canvas.parentNode.id == "SDLFullscreenElement") {
   498                 var canvasContainer = canvas.parentNode;
   499                 canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
   500                 canvasContainer.parentNode.removeChild(canvasContainer);
   501             }
   502         });
   503         double unscaled_w = window_data->windowed_width / window_data->pixel_ratio;
   504         double unscaled_h = window_data->windowed_height / window_data->pixel_ratio;
   505         emscripten_set_canvas_size(window_data->windowed_width, window_data->windowed_height);
   506 
   507         if (!window_data->external_size && window_data->pixel_ratio != 1.0f) {
   508             emscripten_set_element_css_size(NULL, unscaled_w, unscaled_h);
   509         }
   510 
   511         SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, unscaled_w, unscaled_h);
   512 
   513         window_data->window->flags &= ~FULLSCREEN_MASK;
   514     }
   515 
   516     return 0;
   517 }
   518 
   519 EM_BOOL
   520 Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)
   521 {
   522     SDL_WindowData *window_data = userData;
   523     if(window_data->window->flags & FULLSCREEN_MASK)
   524     {
   525         SDL_bool is_desktop_fullscreen = (window_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
   526 
   527         if(window_data->window->flags & SDL_WINDOW_RESIZABLE || is_desktop_fullscreen)
   528         {
   529             emscripten_set_canvas_size(uiEvent->windowInnerWidth * window_data->pixel_ratio, uiEvent->windowInnerHeight * window_data->pixel_ratio);
   530             SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, uiEvent->windowInnerWidth, uiEvent->windowInnerHeight);
   531         }
   532     }
   533     else
   534     {
   535         /* this will only work if the canvas size is set through css */
   536         if(window_data->window->flags & SDL_WINDOW_RESIZABLE)
   537         {
   538             double w = window_data->window->w;
   539             double h = window_data->window->h;
   540 
   541             if(window_data->external_size) {
   542                 emscripten_get_element_css_size(NULL, &w, &h);
   543             }
   544 
   545             emscripten_set_canvas_size(w * window_data->pixel_ratio, h * window_data->pixel_ratio);
   546 
   547             /* set_canvas_size unsets this */
   548             if (!window_data->external_size && window_data->pixel_ratio != 1.0f) {
   549                 emscripten_set_element_css_size(NULL, w, h);
   550             }
   551 
   552             SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, w, h);
   553         }
   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("#canvas", 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("#canvas", 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: */