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