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