diff options
| author | 3gg <3gg@shellblade.net> | 2025-12-27 12:03:39 -0800 |
|---|---|---|
| committer | 3gg <3gg@shellblade.net> | 2025-12-27 12:03:39 -0800 |
| commit | 5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch) | |
| tree | 8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/video/emscripten/SDL_emscriptenevents.c | |
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/video/emscripten/SDL_emscriptenevents.c')
| -rw-r--r-- | contrib/SDL-3.2.8/src/video/emscripten/SDL_emscriptenevents.c | 1117 |
1 files changed, 1117 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/video/emscripten/SDL_emscriptenevents.c b/contrib/SDL-3.2.8/src/video/emscripten/SDL_emscriptenevents.c new file mode 100644 index 0000000..49a140f --- /dev/null +++ b/contrib/SDL-3.2.8/src/video/emscripten/SDL_emscriptenevents.c | |||
| @@ -0,0 +1,1117 @@ | |||
| 1 | /* | ||
| 2 | Simple DirectMedia Layer | ||
| 3 | Copyright (C) 1997-2025 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 | #include "SDL_internal.h" | ||
| 23 | |||
| 24 | #ifdef SDL_VIDEO_DRIVER_EMSCRIPTEN | ||
| 25 | |||
| 26 | #include <emscripten/html5.h> | ||
| 27 | #include <emscripten/dom_pk_codes.h> | ||
| 28 | |||
| 29 | #include "../../events/SDL_dropevents_c.h" | ||
| 30 | #include "../../events/SDL_events_c.h" | ||
| 31 | #include "../../events/SDL_keyboard_c.h" | ||
| 32 | #include "../../events/SDL_touch_c.h" | ||
| 33 | |||
| 34 | #include "SDL_emscriptenevents.h" | ||
| 35 | #include "SDL_emscriptenvideo.h" | ||
| 36 | |||
| 37 | /* | ||
| 38 | Emscripten PK code to scancode | ||
| 39 | https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent | ||
| 40 | https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code | ||
| 41 | */ | ||
| 42 | static const SDL_Scancode emscripten_scancode_table[] = { | ||
| 43 | /* 0x00 "Unidentified" */ SDL_SCANCODE_UNKNOWN, | ||
| 44 | /* 0x01 "Escape" */ SDL_SCANCODE_ESCAPE, | ||
| 45 | /* 0x02 "Digit0" */ SDL_SCANCODE_0, | ||
| 46 | /* 0x03 "Digit1" */ SDL_SCANCODE_1, | ||
| 47 | /* 0x04 "Digit2" */ SDL_SCANCODE_2, | ||
| 48 | /* 0x05 "Digit3" */ SDL_SCANCODE_3, | ||
| 49 | /* 0x06 "Digit4" */ SDL_SCANCODE_4, | ||
| 50 | /* 0x07 "Digit5" */ SDL_SCANCODE_5, | ||
| 51 | /* 0x08 "Digit6" */ SDL_SCANCODE_6, | ||
| 52 | /* 0x09 "Digit7" */ SDL_SCANCODE_7, | ||
| 53 | /* 0x0A "Digit8" */ SDL_SCANCODE_8, | ||
| 54 | /* 0x0B "Digit9" */ SDL_SCANCODE_9, | ||
| 55 | /* 0x0C "Minus" */ SDL_SCANCODE_MINUS, | ||
| 56 | /* 0x0D "Equal" */ SDL_SCANCODE_EQUALS, | ||
| 57 | /* 0x0E "Backspace" */ SDL_SCANCODE_BACKSPACE, | ||
| 58 | /* 0x0F "Tab" */ SDL_SCANCODE_TAB, | ||
| 59 | /* 0x10 "KeyQ" */ SDL_SCANCODE_Q, | ||
| 60 | /* 0x11 "KeyW" */ SDL_SCANCODE_W, | ||
| 61 | /* 0x12 "KeyE" */ SDL_SCANCODE_E, | ||
| 62 | /* 0x13 "KeyR" */ SDL_SCANCODE_R, | ||
| 63 | /* 0x14 "KeyT" */ SDL_SCANCODE_T, | ||
| 64 | /* 0x15 "KeyY" */ SDL_SCANCODE_Y, | ||
| 65 | /* 0x16 "KeyU" */ SDL_SCANCODE_U, | ||
| 66 | /* 0x17 "KeyI" */ SDL_SCANCODE_I, | ||
| 67 | /* 0x18 "KeyO" */ SDL_SCANCODE_O, | ||
| 68 | /* 0x19 "KeyP" */ SDL_SCANCODE_P, | ||
| 69 | /* 0x1A "BracketLeft" */ SDL_SCANCODE_LEFTBRACKET, | ||
| 70 | /* 0x1B "BracketRight" */ SDL_SCANCODE_RIGHTBRACKET, | ||
| 71 | /* 0x1C "Enter" */ SDL_SCANCODE_RETURN, | ||
| 72 | /* 0x1D "ControlLeft" */ SDL_SCANCODE_LCTRL, | ||
| 73 | /* 0x1E "KeyA" */ SDL_SCANCODE_A, | ||
| 74 | /* 0x1F "KeyS" */ SDL_SCANCODE_S, | ||
| 75 | /* 0x20 "KeyD" */ SDL_SCANCODE_D, | ||
| 76 | /* 0x21 "KeyF" */ SDL_SCANCODE_F, | ||
| 77 | /* 0x22 "KeyG" */ SDL_SCANCODE_G, | ||
| 78 | /* 0x23 "KeyH" */ SDL_SCANCODE_H, | ||
| 79 | /* 0x24 "KeyJ" */ SDL_SCANCODE_J, | ||
| 80 | /* 0x25 "KeyK" */ SDL_SCANCODE_K, | ||
| 81 | /* 0x26 "KeyL" */ SDL_SCANCODE_L, | ||
| 82 | /* 0x27 "Semicolon" */ SDL_SCANCODE_SEMICOLON, | ||
| 83 | /* 0x28 "Quote" */ SDL_SCANCODE_APOSTROPHE, | ||
| 84 | /* 0x29 "Backquote" */ SDL_SCANCODE_GRAVE, | ||
| 85 | /* 0x2A "ShiftLeft" */ SDL_SCANCODE_LSHIFT, | ||
| 86 | /* 0x2B "Backslash" */ SDL_SCANCODE_BACKSLASH, | ||
| 87 | /* 0x2C "KeyZ" */ SDL_SCANCODE_Z, | ||
| 88 | /* 0x2D "KeyX" */ SDL_SCANCODE_X, | ||
| 89 | /* 0x2E "KeyC" */ SDL_SCANCODE_C, | ||
| 90 | /* 0x2F "KeyV" */ SDL_SCANCODE_V, | ||
| 91 | /* 0x30 "KeyB" */ SDL_SCANCODE_B, | ||
| 92 | /* 0x31 "KeyN" */ SDL_SCANCODE_N, | ||
| 93 | /* 0x32 "KeyM" */ SDL_SCANCODE_M, | ||
| 94 | /* 0x33 "Comma" */ SDL_SCANCODE_COMMA, | ||
| 95 | /* 0x34 "Period" */ SDL_SCANCODE_PERIOD, | ||
| 96 | /* 0x35 "Slash" */ SDL_SCANCODE_SLASH, | ||
| 97 | /* 0x36 "ShiftRight" */ SDL_SCANCODE_RSHIFT, | ||
| 98 | /* 0x37 "NumpadMultiply" */ SDL_SCANCODE_KP_MULTIPLY, | ||
| 99 | /* 0x38 "AltLeft" */ SDL_SCANCODE_LALT, | ||
| 100 | /* 0x39 "Space" */ SDL_SCANCODE_SPACE, | ||
| 101 | /* 0x3A "CapsLock" */ SDL_SCANCODE_CAPSLOCK, | ||
| 102 | /* 0x3B "F1" */ SDL_SCANCODE_F1, | ||
| 103 | /* 0x3C "F2" */ SDL_SCANCODE_F2, | ||
| 104 | /* 0x3D "F3" */ SDL_SCANCODE_F3, | ||
| 105 | /* 0x3E "F4" */ SDL_SCANCODE_F4, | ||
| 106 | /* 0x3F "F5" */ SDL_SCANCODE_F5, | ||
| 107 | /* 0x40 "F6" */ SDL_SCANCODE_F6, | ||
| 108 | /* 0x41 "F7" */ SDL_SCANCODE_F7, | ||
| 109 | /* 0x42 "F8" */ SDL_SCANCODE_F8, | ||
| 110 | /* 0x43 "F9" */ SDL_SCANCODE_F9, | ||
| 111 | /* 0x44 "F10" */ SDL_SCANCODE_F10, | ||
| 112 | /* 0x45 "Pause" */ SDL_SCANCODE_PAUSE, | ||
| 113 | /* 0x46 "ScrollLock" */ SDL_SCANCODE_SCROLLLOCK, | ||
| 114 | /* 0x47 "Numpad7" */ SDL_SCANCODE_KP_7, | ||
| 115 | /* 0x48 "Numpad8" */ SDL_SCANCODE_KP_8, | ||
| 116 | /* 0x49 "Numpad9" */ SDL_SCANCODE_KP_9, | ||
| 117 | /* 0x4A "NumpadSubtract" */ SDL_SCANCODE_KP_MINUS, | ||
| 118 | /* 0x4B "Numpad4" */ SDL_SCANCODE_KP_4, | ||
| 119 | /* 0x4C "Numpad5" */ SDL_SCANCODE_KP_5, | ||
| 120 | /* 0x4D "Numpad6" */ SDL_SCANCODE_KP_6, | ||
| 121 | /* 0x4E "NumpadAdd" */ SDL_SCANCODE_KP_PLUS, | ||
| 122 | /* 0x4F "Numpad1" */ SDL_SCANCODE_KP_1, | ||
| 123 | /* 0x50 "Numpad2" */ SDL_SCANCODE_KP_2, | ||
| 124 | /* 0x51 "Numpad3" */ SDL_SCANCODE_KP_3, | ||
| 125 | /* 0x52 "Numpad0" */ SDL_SCANCODE_KP_0, | ||
| 126 | /* 0x53 "NumpadDecimal" */ SDL_SCANCODE_KP_PERIOD, | ||
| 127 | /* 0x54 "PrintScreen" */ SDL_SCANCODE_PRINTSCREEN, | ||
| 128 | /* 0x55 */ SDL_SCANCODE_UNKNOWN, | ||
| 129 | /* 0x56 "IntlBackslash" */ SDL_SCANCODE_NONUSBACKSLASH, | ||
| 130 | /* 0x57 "F11" */ SDL_SCANCODE_F11, | ||
| 131 | /* 0x58 "F12" */ SDL_SCANCODE_F12, | ||
| 132 | /* 0x59 "NumpadEqual" */ SDL_SCANCODE_KP_EQUALS, | ||
| 133 | /* 0x5A */ SDL_SCANCODE_UNKNOWN, | ||
| 134 | /* 0x5B */ SDL_SCANCODE_UNKNOWN, | ||
| 135 | /* 0x5C */ SDL_SCANCODE_UNKNOWN, | ||
| 136 | /* 0x5D */ SDL_SCANCODE_UNKNOWN, | ||
| 137 | /* 0x5E */ SDL_SCANCODE_UNKNOWN, | ||
| 138 | /* 0x5F */ SDL_SCANCODE_UNKNOWN, | ||
| 139 | /* 0x60 */ SDL_SCANCODE_UNKNOWN, | ||
| 140 | /* 0x61 */ SDL_SCANCODE_UNKNOWN, | ||
| 141 | /* 0x62 */ SDL_SCANCODE_UNKNOWN, | ||
| 142 | /* 0x63 */ SDL_SCANCODE_UNKNOWN, | ||
| 143 | /* 0x64 "F13" */ SDL_SCANCODE_F13, | ||
| 144 | /* 0x65 "F14" */ SDL_SCANCODE_F14, | ||
| 145 | /* 0x66 "F15" */ SDL_SCANCODE_F15, | ||
| 146 | /* 0x67 "F16" */ SDL_SCANCODE_F16, | ||
| 147 | /* 0x68 "F17" */ SDL_SCANCODE_F17, | ||
| 148 | /* 0x69 "F18" */ SDL_SCANCODE_F18, | ||
| 149 | /* 0x6A "F19" */ SDL_SCANCODE_F19, | ||
| 150 | /* 0x6B "F20" */ SDL_SCANCODE_F20, | ||
| 151 | /* 0x6C "F21" */ SDL_SCANCODE_F21, | ||
| 152 | /* 0x6D "F22" */ SDL_SCANCODE_F22, | ||
| 153 | /* 0x6E "F23" */ SDL_SCANCODE_F23, | ||
| 154 | /* 0x6F */ SDL_SCANCODE_UNKNOWN, | ||
| 155 | /* 0x70 "KanaMode" */ SDL_SCANCODE_INTERNATIONAL2, | ||
| 156 | /* 0x71 "Lang2" */ SDL_SCANCODE_LANG2, | ||
| 157 | /* 0x72 "Lang1" */ SDL_SCANCODE_LANG1, | ||
| 158 | /* 0x73 "IntlRo" */ SDL_SCANCODE_INTERNATIONAL1, | ||
| 159 | /* 0x74 */ SDL_SCANCODE_UNKNOWN, | ||
| 160 | /* 0x75 */ SDL_SCANCODE_UNKNOWN, | ||
| 161 | /* 0x76 "F24" */ SDL_SCANCODE_F24, | ||
| 162 | /* 0x77 */ SDL_SCANCODE_UNKNOWN, | ||
| 163 | /* 0x78 */ SDL_SCANCODE_UNKNOWN, | ||
| 164 | /* 0x79 "Convert" */ SDL_SCANCODE_INTERNATIONAL4, | ||
| 165 | /* 0x7A */ SDL_SCANCODE_UNKNOWN, | ||
| 166 | /* 0x7B "NonConvert" */ SDL_SCANCODE_INTERNATIONAL5, | ||
| 167 | /* 0x7C */ SDL_SCANCODE_UNKNOWN, | ||
| 168 | /* 0x7D "IntlYen" */ SDL_SCANCODE_INTERNATIONAL3, | ||
| 169 | /* 0x7E "NumpadComma" */ SDL_SCANCODE_KP_COMMA | ||
| 170 | }; | ||
| 171 | |||
| 172 | static SDL_Scancode Emscripten_MapScanCode(const char *code) | ||
| 173 | { | ||
| 174 | const DOM_PK_CODE_TYPE pk_code = emscripten_compute_dom_pk_code(code); | ||
| 175 | if (pk_code < SDL_arraysize(emscripten_scancode_table)) { | ||
| 176 | return emscripten_scancode_table[pk_code]; | ||
| 177 | } | ||
| 178 | |||
| 179 | switch (pk_code) { | ||
| 180 | case DOM_PK_PASTE: | ||
| 181 | return SDL_SCANCODE_PASTE; | ||
| 182 | case DOM_PK_MEDIA_TRACK_PREVIOUS: | ||
| 183 | return SDL_SCANCODE_MEDIA_PREVIOUS_TRACK; | ||
| 184 | case DOM_PK_CUT: | ||
| 185 | return SDL_SCANCODE_CUT; | ||
| 186 | case DOM_PK_COPY: | ||
| 187 | return SDL_SCANCODE_COPY; | ||
| 188 | case DOM_PK_MEDIA_TRACK_NEXT: | ||
| 189 | return SDL_SCANCODE_MEDIA_NEXT_TRACK; | ||
| 190 | case DOM_PK_NUMPAD_ENTER: | ||
| 191 | return SDL_SCANCODE_KP_ENTER; | ||
| 192 | case DOM_PK_CONTROL_RIGHT: | ||
| 193 | return SDL_SCANCODE_RCTRL; | ||
| 194 | case DOM_PK_AUDIO_VOLUME_MUTE: | ||
| 195 | return SDL_SCANCODE_MUTE; | ||
| 196 | case DOM_PK_MEDIA_PLAY_PAUSE: | ||
| 197 | return SDL_SCANCODE_MEDIA_PLAY_PAUSE; | ||
| 198 | case DOM_PK_MEDIA_STOP: | ||
| 199 | return SDL_SCANCODE_MEDIA_STOP; | ||
| 200 | case DOM_PK_EJECT: | ||
| 201 | return SDL_SCANCODE_MEDIA_EJECT; | ||
| 202 | case DOM_PK_AUDIO_VOLUME_DOWN: | ||
| 203 | return SDL_SCANCODE_VOLUMEDOWN; | ||
| 204 | case DOM_PK_AUDIO_VOLUME_UP: | ||
| 205 | return SDL_SCANCODE_VOLUMEUP; | ||
| 206 | case DOM_PK_BROWSER_HOME: | ||
| 207 | return SDL_SCANCODE_AC_HOME; | ||
| 208 | case DOM_PK_NUMPAD_DIVIDE: | ||
| 209 | return SDL_SCANCODE_KP_DIVIDE; | ||
| 210 | case DOM_PK_ALT_RIGHT: | ||
| 211 | return SDL_SCANCODE_RALT; | ||
| 212 | case DOM_PK_HELP: | ||
| 213 | return SDL_SCANCODE_HELP; | ||
| 214 | case DOM_PK_NUM_LOCK: | ||
| 215 | return SDL_SCANCODE_NUMLOCKCLEAR; | ||
| 216 | case DOM_PK_HOME: | ||
| 217 | return SDL_SCANCODE_HOME; | ||
| 218 | case DOM_PK_ARROW_UP: | ||
| 219 | return SDL_SCANCODE_UP; | ||
| 220 | case DOM_PK_PAGE_UP: | ||
| 221 | return SDL_SCANCODE_PAGEUP; | ||
| 222 | case DOM_PK_ARROW_LEFT: | ||
| 223 | return SDL_SCANCODE_LEFT; | ||
| 224 | case DOM_PK_ARROW_RIGHT: | ||
| 225 | return SDL_SCANCODE_RIGHT; | ||
| 226 | case DOM_PK_END: | ||
| 227 | return SDL_SCANCODE_END; | ||
| 228 | case DOM_PK_ARROW_DOWN: | ||
| 229 | return SDL_SCANCODE_DOWN; | ||
| 230 | case DOM_PK_PAGE_DOWN: | ||
| 231 | return SDL_SCANCODE_PAGEDOWN; | ||
| 232 | case DOM_PK_INSERT: | ||
| 233 | return SDL_SCANCODE_INSERT; | ||
| 234 | case DOM_PK_DELETE: | ||
| 235 | return SDL_SCANCODE_DELETE; | ||
| 236 | case DOM_PK_META_LEFT: | ||
| 237 | return SDL_SCANCODE_LGUI; | ||
| 238 | case DOM_PK_META_RIGHT: | ||
| 239 | return SDL_SCANCODE_RGUI; | ||
| 240 | case DOM_PK_CONTEXT_MENU: | ||
| 241 | return SDL_SCANCODE_APPLICATION; | ||
| 242 | case DOM_PK_POWER: | ||
| 243 | return SDL_SCANCODE_POWER; | ||
| 244 | case DOM_PK_BROWSER_SEARCH: | ||
| 245 | return SDL_SCANCODE_AC_SEARCH; | ||
| 246 | case DOM_PK_BROWSER_FAVORITES: | ||
| 247 | return SDL_SCANCODE_AC_BOOKMARKS; | ||
| 248 | case DOM_PK_BROWSER_REFRESH: | ||
| 249 | return SDL_SCANCODE_AC_REFRESH; | ||
| 250 | case DOM_PK_BROWSER_STOP: | ||
| 251 | return SDL_SCANCODE_AC_STOP; | ||
| 252 | case DOM_PK_BROWSER_FORWARD: | ||
| 253 | return SDL_SCANCODE_AC_FORWARD; | ||
| 254 | case DOM_PK_BROWSER_BACK: | ||
| 255 | return SDL_SCANCODE_AC_BACK; | ||
| 256 | case DOM_PK_MEDIA_SELECT: | ||
| 257 | return SDL_SCANCODE_MEDIA_SELECT; | ||
| 258 | } | ||
| 259 | |||
| 260 | return SDL_SCANCODE_UNKNOWN; | ||
| 261 | } | ||
| 262 | |||
| 263 | static EM_BOOL Emscripten_HandlePointerLockChange(int eventType, const EmscriptenPointerlockChangeEvent *changeEvent, void *userData) | ||
| 264 | { | ||
| 265 | SDL_WindowData *window_data = (SDL_WindowData *)userData; | ||
| 266 | // keep track of lock losses, so we can regrab if/when appropriate. | ||
| 267 | window_data->has_pointer_lock = changeEvent->isActive; | ||
| 268 | return 0; | ||
| 269 | } | ||
| 270 | |||
| 271 | static EM_BOOL Emscripten_HandleMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) | ||
| 272 | { | ||
| 273 | SDL_WindowData *window_data = userData; | ||
| 274 | const bool isPointerLocked = window_data->has_pointer_lock; | ||
| 275 | float mx, my; | ||
| 276 | |||
| 277 | // rescale (in case canvas is being scaled) | ||
| 278 | double client_w, client_h, xscale, yscale; | ||
| 279 | emscripten_get_element_css_size(window_data->canvas_id, &client_w, &client_h); | ||
| 280 | xscale = window_data->window->w / client_w; | ||
| 281 | yscale = window_data->window->h / client_h; | ||
| 282 | |||
| 283 | if (isPointerLocked) { | ||
| 284 | mx = (float)(mouseEvent->movementX * xscale); | ||
| 285 | my = (float)(mouseEvent->movementY * yscale); | ||
| 286 | } else { | ||
| 287 | mx = (float)(mouseEvent->targetX * xscale); | ||
| 288 | my = (float)(mouseEvent->targetY * yscale); | ||
| 289 | } | ||
| 290 | |||
| 291 | SDL_SendMouseMotion(0, window_data->window, SDL_DEFAULT_MOUSE_ID, isPointerLocked, mx, my); | ||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | |||
| 295 | static EM_BOOL Emscripten_HandleMouseButton(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) | ||
| 296 | { | ||
| 297 | SDL_WindowData *window_data = userData; | ||
| 298 | Uint8 sdl_button; | ||
| 299 | bool sdl_button_state; | ||
| 300 | double css_w, css_h; | ||
| 301 | bool prevent_default = false; // needed for iframe implementation in Chrome-based browsers. | ||
| 302 | |||
| 303 | switch (mouseEvent->button) { | ||
| 304 | case 0: | ||
| 305 | sdl_button = SDL_BUTTON_LEFT; | ||
| 306 | break; | ||
| 307 | case 1: | ||
| 308 | sdl_button = SDL_BUTTON_MIDDLE; | ||
| 309 | break; | ||
| 310 | case 2: | ||
| 311 | sdl_button = SDL_BUTTON_RIGHT; | ||
| 312 | break; | ||
| 313 | default: | ||
| 314 | return 0; | ||
| 315 | } | ||
| 316 | |||
| 317 | const SDL_Mouse *mouse = SDL_GetMouse(); | ||
| 318 | SDL_assert(mouse != NULL); | ||
| 319 | |||
| 320 | if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) { | ||
| 321 | if (mouse->relative_mode && !window_data->has_pointer_lock) { | ||
| 322 | emscripten_request_pointerlock(window_data->canvas_id, 0); // try to regrab lost pointer lock. | ||
| 323 | } | ||
| 324 | sdl_button_state = true; | ||
| 325 | } else { | ||
| 326 | sdl_button_state = false; | ||
| 327 | prevent_default = SDL_EventEnabled(SDL_EVENT_MOUSE_BUTTON_UP); | ||
| 328 | } | ||
| 329 | |||
| 330 | SDL_SendMouseButton(0, window_data->window, SDL_DEFAULT_MOUSE_ID, sdl_button, sdl_button_state); | ||
| 331 | |||
| 332 | // We have an imaginary mouse capture, because we need SDL to not drop our imaginary mouse focus when we leave the canvas. | ||
| 333 | if (mouse->auto_capture) { | ||
| 334 | if (SDL_GetMouseState(NULL, NULL) != 0) { | ||
| 335 | window_data->window->flags |= SDL_WINDOW_MOUSE_CAPTURE; | ||
| 336 | } else { | ||
| 337 | window_data->window->flags &= ~SDL_WINDOW_MOUSE_CAPTURE; | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | if ((eventType == EMSCRIPTEN_EVENT_MOUSEUP) && window_data->mouse_focus_loss_pending) { | ||
| 342 | window_data->mouse_focus_loss_pending = (window_data->window->flags & SDL_WINDOW_MOUSE_CAPTURE) != 0; | ||
| 343 | if (!window_data->mouse_focus_loss_pending) { | ||
| 344 | SDL_SetMouseFocus(NULL); | ||
| 345 | } | ||
| 346 | } else { | ||
| 347 | // Do not consume the event if the mouse is outside of the canvas. | ||
| 348 | emscripten_get_element_css_size(window_data->canvas_id, &css_w, &css_h); | ||
| 349 | if (mouseEvent->targetX < 0 || mouseEvent->targetX >= css_w || | ||
| 350 | mouseEvent->targetY < 0 || mouseEvent->targetY >= css_h) { | ||
| 351 | return 0; | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 355 | return prevent_default; | ||
| 356 | } | ||
| 357 | |||
| 358 | static EM_BOOL Emscripten_HandleMouseFocus(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) | ||
| 359 | { | ||
| 360 | SDL_WindowData *window_data = userData; | ||
| 361 | |||
| 362 | const bool isPointerLocked = window_data->has_pointer_lock; | ||
| 363 | |||
| 364 | if (!isPointerLocked) { | ||
| 365 | // rescale (in case canvas is being scaled) | ||
| 366 | float mx, my; | ||
| 367 | double client_w, client_h; | ||
| 368 | emscripten_get_element_css_size(window_data->canvas_id, &client_w, &client_h); | ||
| 369 | |||
| 370 | mx = (float)(mouseEvent->targetX * (window_data->window->w / client_w)); | ||
| 371 | my = (float)(mouseEvent->targetY * (window_data->window->h / client_h)); | ||
| 372 | SDL_SendMouseMotion(0, window_data->window, SDL_GLOBAL_MOUSE_ID, isPointerLocked, mx, my); | ||
| 373 | } | ||
| 374 | |||
| 375 | const bool isenter = (eventType == EMSCRIPTEN_EVENT_MOUSEENTER); | ||
| 376 | if (isenter && window_data->mouse_focus_loss_pending) { | ||
| 377 | window_data->mouse_focus_loss_pending = false; // just drop the state, but don't send the enter event. | ||
| 378 | } else if (!isenter && (window_data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) { | ||
| 379 | window_data->mouse_focus_loss_pending = true; // waiting on a mouse button to let go before we send the mouse focus update. | ||
| 380 | } else { | ||
| 381 | SDL_SetMouseFocus(isenter ? window_data->window : NULL); | ||
| 382 | } | ||
| 383 | |||
| 384 | return SDL_EventEnabled(SDL_EVENT_MOUSE_MOTION); // !!! FIXME: should this be MOUSE_MOTION or something else? | ||
| 385 | } | ||
| 386 | |||
| 387 | static EM_BOOL Emscripten_HandleWheel(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData) | ||
| 388 | { | ||
| 389 | SDL_WindowData *window_data = userData; | ||
| 390 | |||
| 391 | float deltaY = wheelEvent->deltaY; | ||
| 392 | float deltaX = wheelEvent->deltaX; | ||
| 393 | |||
| 394 | switch (wheelEvent->deltaMode) { | ||
| 395 | case DOM_DELTA_PIXEL: | ||
| 396 | deltaX /= 100; // 100 pixels make up a step | ||
| 397 | deltaY /= 100; // 100 pixels make up a step | ||
| 398 | break; | ||
| 399 | case DOM_DELTA_LINE: | ||
| 400 | deltaX /= 3; // 3 lines make up a step | ||
| 401 | deltaY /= 3; // 3 lines make up a step | ||
| 402 | break; | ||
| 403 | case DOM_DELTA_PAGE: | ||
| 404 | deltaX *= 80; // A page makes up 80 steps | ||
| 405 | deltaY *= 80; // A page makes up 80 steps | ||
| 406 | break; | ||
| 407 | } | ||
| 408 | |||
| 409 | SDL_SendMouseWheel(0, window_data->window, SDL_DEFAULT_MOUSE_ID, deltaX, -deltaY, SDL_MOUSEWHEEL_NORMAL); | ||
| 410 | return SDL_EventEnabled(SDL_EVENT_MOUSE_WHEEL); | ||
| 411 | } | ||
| 412 | |||
| 413 | static EM_BOOL Emscripten_HandleFocus(int eventType, const EmscriptenFocusEvent *wheelEvent, void *userData) | ||
| 414 | { | ||
| 415 | SDL_WindowData *window_data = userData; | ||
| 416 | SDL_EventType sdl_event_type; | ||
| 417 | |||
| 418 | /* If the user switches away while keys are pressed (such as | ||
| 419 | * via Alt+Tab), key release events won't be received. */ | ||
| 420 | if (eventType == EMSCRIPTEN_EVENT_BLUR) { | ||
| 421 | SDL_ResetKeyboard(); | ||
| 422 | } | ||
| 423 | |||
| 424 | sdl_event_type = (eventType == EMSCRIPTEN_EVENT_FOCUS) ? SDL_EVENT_WINDOW_FOCUS_GAINED : SDL_EVENT_WINDOW_FOCUS_LOST; | ||
| 425 | SDL_SetKeyboardFocus(sdl_event_type == SDL_EVENT_WINDOW_FOCUS_GAINED ? window_data->window : NULL); | ||
| 426 | return SDL_EventEnabled(sdl_event_type); | ||
| 427 | } | ||
| 428 | |||
| 429 | static EM_BOOL Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) | ||
| 430 | { | ||
| 431 | SDL_WindowData *window_data = (SDL_WindowData *)userData; | ||
| 432 | int i; | ||
| 433 | double client_w, client_h; | ||
| 434 | int preventDefault = 0; | ||
| 435 | |||
| 436 | const SDL_TouchID deviceId = 1; | ||
| 437 | if (SDL_AddTouch(deviceId, SDL_TOUCH_DEVICE_DIRECT, "") < 0) { | ||
| 438 | return 0; | ||
| 439 | } | ||
| 440 | |||
| 441 | emscripten_get_element_css_size(window_data->canvas_id, &client_w, &client_h); | ||
| 442 | |||
| 443 | for (i = 0; i < touchEvent->numTouches; i++) { | ||
| 444 | SDL_FingerID id; | ||
| 445 | float x, y; | ||
| 446 | |||
| 447 | if (!touchEvent->touches[i].isChanged) { | ||
| 448 | continue; | ||
| 449 | } | ||
| 450 | |||
| 451 | id = touchEvent->touches[i].identifier + 1; | ||
| 452 | if (client_w <= 1) { | ||
| 453 | x = 0.5f; | ||
| 454 | } else { | ||
| 455 | x = touchEvent->touches[i].targetX / (client_w - 1); | ||
| 456 | } | ||
| 457 | if (client_h <= 1) { | ||
| 458 | y = 0.5f; | ||
| 459 | } else { | ||
| 460 | y = touchEvent->touches[i].targetY / (client_h - 1); | ||
| 461 | } | ||
| 462 | |||
| 463 | if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) { | ||
| 464 | SDL_SendTouch(0, deviceId, id, window_data->window, SDL_EVENT_FINGER_DOWN, x, y, 1.0f); | ||
| 465 | |||
| 466 | // disable browser scrolling/pinch-to-zoom if app handles touch events | ||
| 467 | if (!preventDefault && SDL_EventEnabled(SDL_EVENT_FINGER_DOWN)) { | ||
| 468 | preventDefault = 1; | ||
| 469 | } | ||
| 470 | } else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) { | ||
| 471 | SDL_SendTouchMotion(0, deviceId, id, window_data->window, x, y, 1.0f); | ||
| 472 | } else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) { | ||
| 473 | SDL_SendTouch(0, deviceId, id, window_data->window, SDL_EVENT_FINGER_UP, x, y, 1.0f); | ||
| 474 | |||
| 475 | // block browser's simulated mousedown/mouseup on touchscreen devices | ||
| 476 | preventDefault = 1; | ||
| 477 | } else if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL) { | ||
| 478 | SDL_SendTouch(0, deviceId, id, window_data->window, SDL_EVENT_FINGER_CANCELED, x, y, 1.0f); | ||
| 479 | } | ||
| 480 | } | ||
| 481 | |||
| 482 | return preventDefault; | ||
| 483 | } | ||
| 484 | |||
| 485 | static bool IsFunctionKey(SDL_Scancode scancode) | ||
| 486 | { | ||
| 487 | if (scancode >= SDL_SCANCODE_F1 && scancode <= SDL_SCANCODE_F12) { | ||
| 488 | return true; | ||
| 489 | } | ||
| 490 | if (scancode >= SDL_SCANCODE_F13 && scancode <= SDL_SCANCODE_F24) { | ||
| 491 | return true; | ||
| 492 | } | ||
| 493 | return false; | ||
| 494 | } | ||
| 495 | |||
| 496 | /* This is a great tool to see web keyboard events live: | ||
| 497 | * https://w3c.github.io/uievents/tools/key-event-viewer.html | ||
| 498 | */ | ||
| 499 | static EM_BOOL Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) | ||
| 500 | { | ||
| 501 | SDL_WindowData *window_data = (SDL_WindowData *)userData; | ||
| 502 | SDL_Scancode scancode = Emscripten_MapScanCode(keyEvent->code); | ||
| 503 | SDL_Keycode keycode = SDLK_UNKNOWN; | ||
| 504 | bool prevent_default = false; | ||
| 505 | bool is_nav_key = false; | ||
| 506 | |||
| 507 | if (scancode == SDL_SCANCODE_UNKNOWN) { | ||
| 508 | if (SDL_strcmp(keyEvent->key, "Sleep") == 0) { | ||
| 509 | scancode = SDL_SCANCODE_SLEEP; | ||
| 510 | } else if (SDL_strcmp(keyEvent->key, "ChannelUp") == 0) { | ||
| 511 | scancode = SDL_SCANCODE_CHANNEL_INCREMENT; | ||
| 512 | } else if (SDL_strcmp(keyEvent->key, "ChannelDown") == 0) { | ||
| 513 | scancode = SDL_SCANCODE_CHANNEL_DECREMENT; | ||
| 514 | } else if (SDL_strcmp(keyEvent->key, "MediaPlay") == 0) { | ||
| 515 | scancode = SDL_SCANCODE_MEDIA_PLAY; | ||
| 516 | } else if (SDL_strcmp(keyEvent->key, "MediaPause") == 0) { | ||
| 517 | scancode = SDL_SCANCODE_MEDIA_PAUSE; | ||
| 518 | } else if (SDL_strcmp(keyEvent->key, "MediaRecord") == 0) { | ||
| 519 | scancode = SDL_SCANCODE_MEDIA_RECORD; | ||
| 520 | } else if (SDL_strcmp(keyEvent->key, "MediaFastForward") == 0) { | ||
| 521 | scancode = SDL_SCANCODE_MEDIA_FAST_FORWARD; | ||
| 522 | } else if (SDL_strcmp(keyEvent->key, "MediaRewind") == 0) { | ||
| 523 | scancode = SDL_SCANCODE_MEDIA_REWIND; | ||
| 524 | } else if (SDL_strcmp(keyEvent->key, "Close") == 0) { | ||
| 525 | scancode = SDL_SCANCODE_AC_CLOSE; | ||
| 526 | } else if (SDL_strcmp(keyEvent->key, "New") == 0) { | ||
| 527 | scancode = SDL_SCANCODE_AC_NEW; | ||
| 528 | } else if (SDL_strcmp(keyEvent->key, "Open") == 0) { | ||
| 529 | scancode = SDL_SCANCODE_AC_OPEN; | ||
| 530 | } else if (SDL_strcmp(keyEvent->key, "Print") == 0) { | ||
| 531 | scancode = SDL_SCANCODE_AC_PRINT; | ||
| 532 | } else if (SDL_strcmp(keyEvent->key, "Save") == 0) { | ||
| 533 | scancode = SDL_SCANCODE_AC_SAVE; | ||
| 534 | } else if (SDL_strcmp(keyEvent->key, "Props") == 0) { | ||
| 535 | scancode = SDL_SCANCODE_AC_PROPERTIES; | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
| 539 | if (scancode == SDL_SCANCODE_UNKNOWN) { | ||
| 540 | // KaiOS Left Soft Key and Right Soft Key, they act as OK/Next/Menu and Cancel/Back/Clear | ||
| 541 | if (SDL_strcmp(keyEvent->key, "SoftLeft") == 0) { | ||
| 542 | scancode = SDL_SCANCODE_AC_FORWARD; | ||
| 543 | } else if (SDL_strcmp(keyEvent->key, "SoftRight") == 0) { | ||
| 544 | scancode = SDL_SCANCODE_AC_BACK; | ||
| 545 | } | ||
| 546 | } | ||
| 547 | |||
| 548 | if (keyEvent->location == 0 && SDL_utf8strlen(keyEvent->key) == 1) { | ||
| 549 | const char *key = keyEvent->key; | ||
| 550 | keycode = SDL_StepUTF8(&key, NULL); | ||
| 551 | if (keycode == SDL_INVALID_UNICODE_CODEPOINT) { | ||
| 552 | keycode = SDLK_UNKNOWN; | ||
| 553 | } | ||
| 554 | } | ||
| 555 | |||
| 556 | if (keycode != SDLK_UNKNOWN) { | ||
| 557 | prevent_default = SDL_SendKeyboardKeyAndKeycode(0, SDL_DEFAULT_KEYBOARD_ID, 0, scancode, keycode, (eventType == EMSCRIPTEN_EVENT_KEYDOWN)); | ||
| 558 | } else { | ||
| 559 | prevent_default = SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, 0, scancode, (eventType == EMSCRIPTEN_EVENT_KEYDOWN)); | ||
| 560 | } | ||
| 561 | |||
| 562 | /* if TEXTINPUT events are enabled we can't prevent keydown or we won't get keypress | ||
| 563 | * we need to ALWAYS prevent backspace and tab otherwise chrome takes action and does bad navigation UX | ||
| 564 | */ | ||
| 565 | if ((scancode == SDL_SCANCODE_BACKSPACE) || | ||
| 566 | (scancode == SDL_SCANCODE_TAB) || | ||
| 567 | (scancode == SDL_SCANCODE_LEFT) || | ||
| 568 | (scancode == SDL_SCANCODE_UP) || | ||
| 569 | (scancode == SDL_SCANCODE_RIGHT) || | ||
| 570 | (scancode == SDL_SCANCODE_DOWN) || | ||
| 571 | IsFunctionKey(scancode) || | ||
| 572 | keyEvent->ctrlKey) { | ||
| 573 | is_nav_key = true; | ||
| 574 | } | ||
| 575 | |||
| 576 | if ((eventType == EMSCRIPTEN_EVENT_KEYDOWN) && SDL_TextInputActive(window_data->window) && !is_nav_key) { | ||
| 577 | prevent_default = false; | ||
| 578 | } | ||
| 579 | |||
| 580 | return prevent_default; | ||
| 581 | } | ||
| 582 | |||
| 583 | static EM_BOOL Emscripten_HandleKeyPress(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) | ||
| 584 | { | ||
| 585 | SDL_WindowData *window_data = (SDL_WindowData *)userData; | ||
| 586 | |||
| 587 | if (SDL_TextInputActive(window_data->window)) { | ||
| 588 | char text[5]; | ||
| 589 | char *end = SDL_UCS4ToUTF8(keyEvent->charCode, text); | ||
| 590 | *end = '\0'; | ||
| 591 | SDL_SendKeyboardText(text); | ||
| 592 | return EM_TRUE; | ||
| 593 | } | ||
| 594 | return EM_FALSE; | ||
| 595 | } | ||
| 596 | |||
| 597 | static EM_BOOL Emscripten_HandleFullscreenChange(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData) | ||
| 598 | { | ||
| 599 | SDL_WindowData *window_data = userData; | ||
| 600 | |||
| 601 | if (fullscreenChangeEvent->isFullscreen) { | ||
| 602 | SDL_SendWindowEvent(window_data->window, SDL_EVENT_WINDOW_ENTER_FULLSCREEN, 0, 0); | ||
| 603 | window_data->fullscreen_mode_flags = 0; | ||
| 604 | } else { | ||
| 605 | SDL_SendWindowEvent(window_data->window, SDL_EVENT_WINDOW_LEAVE_FULLSCREEN, 0, 0); | ||
| 606 | } | ||
| 607 | |||
| 608 | SDL_UpdateFullscreenMode(window_data->window, fullscreenChangeEvent->isFullscreen, false); | ||
| 609 | |||
| 610 | return 0; | ||
| 611 | } | ||
| 612 | |||
| 613 | static EM_BOOL Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData) | ||
| 614 | { | ||
| 615 | SDL_WindowData *window_data = userData; | ||
| 616 | bool force = false; | ||
| 617 | |||
| 618 | // update pixel ratio | ||
| 619 | if (window_data->window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) { | ||
| 620 | if (window_data->pixel_ratio != emscripten_get_device_pixel_ratio()) { | ||
| 621 | window_data->pixel_ratio = emscripten_get_device_pixel_ratio(); | ||
| 622 | force = true; | ||
| 623 | } | ||
| 624 | } | ||
| 625 | |||
| 626 | if (!(window_data->window->flags & SDL_WINDOW_FULLSCREEN)) { | ||
| 627 | // this will only work if the canvas size is set through css | ||
| 628 | if (window_data->window->flags & SDL_WINDOW_RESIZABLE) { | ||
| 629 | double w = window_data->window->w; | ||
| 630 | double h = window_data->window->h; | ||
| 631 | |||
| 632 | if (window_data->external_size) { | ||
| 633 | emscripten_get_element_css_size(window_data->canvas_id, &w, &h); | ||
| 634 | } | ||
| 635 | |||
| 636 | emscripten_set_canvas_element_size(window_data->canvas_id, SDL_lroundf(w * window_data->pixel_ratio), SDL_lroundf(h * window_data->pixel_ratio)); | ||
| 637 | |||
| 638 | // set_canvas_size unsets this | ||
| 639 | if (!window_data->external_size && window_data->pixel_ratio != 1.0f) { | ||
| 640 | emscripten_set_element_css_size(window_data->canvas_id, w, h); | ||
| 641 | } | ||
| 642 | |||
| 643 | if (force) { | ||
| 644 | // force the event to trigger, so pixel ratio changes can be handled | ||
| 645 | window_data->window->w = 0; | ||
| 646 | window_data->window->h = 0; | ||
| 647 | } | ||
| 648 | |||
| 649 | SDL_SendWindowEvent(window_data->window, SDL_EVENT_WINDOW_RESIZED, SDL_lroundf(w), SDL_lroundf(h)); | ||
| 650 | } | ||
| 651 | } | ||
| 652 | |||
| 653 | return 0; | ||
| 654 | } | ||
| 655 | |||
| 656 | EM_BOOL | ||
| 657 | Emscripten_HandleCanvasResize(int eventType, const void *reserved, void *userData) | ||
| 658 | { | ||
| 659 | // this is used during fullscreen changes | ||
| 660 | SDL_WindowData *window_data = userData; | ||
| 661 | |||
| 662 | if (window_data->fullscreen_resize) { | ||
| 663 | double css_w, css_h; | ||
| 664 | emscripten_get_element_css_size(window_data->canvas_id, &css_w, &css_h); | ||
| 665 | SDL_SendWindowEvent(window_data->window, SDL_EVENT_WINDOW_RESIZED, SDL_lroundf(css_w), SDL_lroundf(css_h)); | ||
| 666 | } | ||
| 667 | |||
| 668 | return 0; | ||
| 669 | } | ||
| 670 | |||
| 671 | static EM_BOOL Emscripten_HandleVisibilityChange(int eventType, const EmscriptenVisibilityChangeEvent *visEvent, void *userData) | ||
| 672 | { | ||
| 673 | SDL_WindowData *window_data = userData; | ||
| 674 | SDL_SendWindowEvent(window_data->window, visEvent->hidden ? SDL_EVENT_WINDOW_HIDDEN : SDL_EVENT_WINDOW_SHOWN, 0, 0); | ||
| 675 | return 0; | ||
| 676 | } | ||
| 677 | |||
| 678 | static const char *Emscripten_HandleBeforeUnload(int eventType, const void *reserved, void *userData) | ||
| 679 | { | ||
| 680 | /* This event will need to be handled synchronously, e.g. using | ||
| 681 | SDL_AddEventWatch, as the page is being closed *now*. */ | ||
| 682 | // No need to send a SDL_EVENT_QUIT, the app won't get control again. | ||
| 683 | SDL_SendAppEvent(SDL_EVENT_TERMINATING); | ||
| 684 | return ""; // don't trigger confirmation dialog | ||
| 685 | } | ||
| 686 | |||
| 687 | static EM_BOOL Emscripten_HandleOrientationChange(int eventType, const EmscriptenOrientationChangeEvent *orientationChangeEvent, void *userData) | ||
| 688 | { | ||
| 689 | SDL_DisplayOrientation orientation; | ||
| 690 | switch (orientationChangeEvent->orientationIndex) { | ||
| 691 | #define CHECK_ORIENTATION(emsdk, sdl) case EMSCRIPTEN_ORIENTATION_##emsdk: orientation = SDL_ORIENTATION_##sdl; break | ||
| 692 | CHECK_ORIENTATION(LANDSCAPE_PRIMARY, LANDSCAPE); | ||
| 693 | CHECK_ORIENTATION(LANDSCAPE_SECONDARY, LANDSCAPE_FLIPPED); | ||
| 694 | CHECK_ORIENTATION(PORTRAIT_PRIMARY, PORTRAIT); | ||
| 695 | CHECK_ORIENTATION(PORTRAIT_SECONDARY, PORTRAIT_FLIPPED); | ||
| 696 | #undef CHECK_ORIENTATION | ||
| 697 | default: orientation = SDL_ORIENTATION_UNKNOWN; break; | ||
| 698 | } | ||
| 699 | |||
| 700 | SDL_WindowData *window_data = (SDL_WindowData *) userData; | ||
| 701 | SDL_SendDisplayEvent(SDL_GetVideoDisplayForWindow(window_data->window), SDL_EVENT_DISPLAY_ORIENTATION, orientation, 0); | ||
| 702 | |||
| 703 | return 0; | ||
| 704 | } | ||
| 705 | |||
| 706 | // IF YOU CHANGE THIS STRUCTURE, YOU NEED TO UPDATE THE JAVASCRIPT THAT FILLS IT IN: makePointerEventCStruct, below. | ||
| 707 | typedef struct Emscripten_PointerEvent | ||
| 708 | { | ||
| 709 | int pointerid; | ||
| 710 | int button; | ||
| 711 | int buttons; | ||
| 712 | float movementX; | ||
| 713 | float movementY; | ||
| 714 | float targetX; | ||
| 715 | float targetY; | ||
| 716 | float pressure; | ||
| 717 | float tangential_pressure; | ||
| 718 | float tiltx; | ||
| 719 | float tilty; | ||
| 720 | float rotation; | ||
| 721 | } Emscripten_PointerEvent; | ||
| 722 | |||
| 723 | static void Emscripten_UpdatePointerFromEvent(SDL_WindowData *window_data, const Emscripten_PointerEvent *event) | ||
| 724 | { | ||
| 725 | const SDL_PenID pen = SDL_FindPenByHandle((void *) (size_t) event->pointerid); | ||
| 726 | if (pen) { | ||
| 727 | // rescale (in case canvas is being scaled) | ||
| 728 | double client_w, client_h; | ||
| 729 | emscripten_get_element_css_size(window_data->canvas_id, &client_w, &client_h); | ||
| 730 | const double xscale = window_data->window->w / client_w; | ||
| 731 | const double yscale = window_data->window->h / client_h; | ||
| 732 | |||
| 733 | const bool isPointerLocked = window_data->has_pointer_lock; | ||
| 734 | float mx, my; | ||
| 735 | if (isPointerLocked) { | ||
| 736 | mx = (float)(event->movementX * xscale); | ||
| 737 | my = (float)(event->movementY * yscale); | ||
| 738 | } else { | ||
| 739 | mx = (float)(event->targetX * xscale); | ||
| 740 | my = (float)(event->targetY * yscale); | ||
| 741 | } | ||
| 742 | |||
| 743 | SDL_SendPenMotion(0, pen, window_data->window, mx, my); | ||
| 744 | |||
| 745 | if (event->button == 0) { // pen touch | ||
| 746 | bool down = ((event->buttons & 1) != 0); | ||
| 747 | SDL_SendPenTouch(0, pen, window_data->window, false, down); | ||
| 748 | } else if (event->button == 5) { // eraser touch...? Not sure if this is right... | ||
| 749 | bool down = ((event->buttons & 32) != 0); | ||
| 750 | SDL_SendPenTouch(0, pen, window_data->window, true, down); | ||
| 751 | } else if (event->button == 1) { | ||
| 752 | bool down = ((event->buttons & 4) != 0); | ||
| 753 | SDL_SendPenButton(0, pen, window_data->window, 2, down); | ||
| 754 | } else if (event->button == 2) { | ||
| 755 | bool down = ((event->buttons & 2) != 0); | ||
| 756 | SDL_SendPenButton(0, pen, window_data->window, 1, down); | ||
| 757 | } | ||
| 758 | |||
| 759 | SDL_SendPenAxis(0, pen, window_data->window, SDL_PEN_AXIS_PRESSURE, event->pressure); | ||
| 760 | SDL_SendPenAxis(0, pen, window_data->window, SDL_PEN_AXIS_TANGENTIAL_PRESSURE, event->tangential_pressure); | ||
| 761 | SDL_SendPenAxis(0, pen, window_data->window, SDL_PEN_AXIS_XTILT, event->tiltx); | ||
| 762 | SDL_SendPenAxis(0, pen, window_data->window, SDL_PEN_AXIS_YTILT, event->tilty); | ||
| 763 | SDL_SendPenAxis(0, pen, window_data->window, SDL_PEN_AXIS_ROTATION, event->rotation); | ||
| 764 | } | ||
| 765 | } | ||
| 766 | |||
| 767 | EMSCRIPTEN_KEEPALIVE void Emscripten_HandlePointerEnter(SDL_WindowData *window_data, const Emscripten_PointerEvent *event) | ||
| 768 | { | ||
| 769 | // Web browsers offer almost none of this information as specifics, but can without warning offer any of these specific things. | ||
| 770 | SDL_PenInfo peninfo; | ||
| 771 | SDL_zero(peninfo); | ||
| 772 | peninfo.capabilities = SDL_PEN_CAPABILITY_PRESSURE | SDL_PEN_CAPABILITY_ROTATION | SDL_PEN_CAPABILITY_XTILT | SDL_PEN_CAPABILITY_YTILT | SDL_PEN_CAPABILITY_TANGENTIAL_PRESSURE | SDL_PEN_CAPABILITY_ERASER; | ||
| 773 | peninfo.max_tilt = 90.0f; | ||
| 774 | peninfo.num_buttons = 2; | ||
| 775 | peninfo.subtype = SDL_PEN_TYPE_PEN; | ||
| 776 | SDL_AddPenDevice(0, NULL, &peninfo, (void *) (size_t) event->pointerid); | ||
| 777 | Emscripten_UpdatePointerFromEvent(window_data, event); | ||
| 778 | } | ||
| 779 | |||
| 780 | EMSCRIPTEN_KEEPALIVE void Emscripten_HandlePointerLeave(SDL_WindowData *window_data, const Emscripten_PointerEvent *event) | ||
| 781 | { | ||
| 782 | const SDL_PenID pen = SDL_FindPenByHandle((void *) (size_t) event->pointerid); | ||
| 783 | if (pen) { | ||
| 784 | Emscripten_UpdatePointerFromEvent(window_data, event); // last data updates? | ||
| 785 | SDL_RemovePenDevice(0, pen); | ||
| 786 | } | ||
| 787 | } | ||
| 788 | |||
| 789 | EMSCRIPTEN_KEEPALIVE void Emscripten_HandlePointerGeneric(SDL_WindowData *window_data, const Emscripten_PointerEvent *event) | ||
| 790 | { | ||
| 791 | Emscripten_UpdatePointerFromEvent(window_data, event); | ||
| 792 | } | ||
| 793 | |||
| 794 | static void Emscripten_set_pointer_event_callbacks(SDL_WindowData *data) | ||
| 795 | { | ||
| 796 | MAIN_THREAD_EM_ASM({ | ||
| 797 | var target = document.querySelector(UTF8ToString($1)); | ||
| 798 | if (target) { | ||
| 799 | var data = $0; | ||
| 800 | |||
| 801 | if (typeof(Module['SDL3']) === 'undefined') { | ||
| 802 | Module['SDL3'] = {}; | ||
| 803 | } | ||
| 804 | var SDL3 = Module['SDL3']; | ||
| 805 | |||
| 806 | var makePointerEventCStruct = function(event) { | ||
| 807 | var ptr = 0; | ||
| 808 | if (event.pointerType == "pen") { | ||
| 809 | ptr = _SDL_malloc($2); | ||
| 810 | if (ptr != 0) { | ||
| 811 | var rect = target.getBoundingClientRect(); | ||
| 812 | var idx = ptr >> 2; | ||
| 813 | HEAP32[idx++] = event.pointerId; | ||
| 814 | HEAP32[idx++] = (typeof(event.button) !== "undefined") ? event.button : -1; | ||
| 815 | HEAP32[idx++] = event.buttons; | ||
| 816 | HEAPF32[idx++] = event.movementX; | ||
| 817 | HEAPF32[idx++] = event.movementY; | ||
| 818 | HEAPF32[idx++] = event.clientX - rect.left; | ||
| 819 | HEAPF32[idx++] = event.clientY - rect.top; | ||
| 820 | HEAPF32[idx++] = event.pressure; | ||
| 821 | HEAPF32[idx++] = event.tangentialPressure; | ||
| 822 | HEAPF32[idx++] = event.tiltX; | ||
| 823 | HEAPF32[idx++] = event.tiltY; | ||
| 824 | HEAPF32[idx++] = event.twist; | ||
| 825 | } | ||
| 826 | } | ||
| 827 | return ptr; | ||
| 828 | }; | ||
| 829 | |||
| 830 | SDL3.eventHandlerPointerEnter = function(event) { | ||
| 831 | var d = makePointerEventCStruct(event); if (d != 0) { _Emscripten_HandlePointerEnter(data, d); _SDL_free(d); } | ||
| 832 | }; | ||
| 833 | target.addEventListener("pointerenter", SDL3.eventHandlerPointerEnter); | ||
| 834 | |||
| 835 | SDL3.eventHandlerPointerLeave = function(event) { | ||
| 836 | var d = makePointerEventCStruct(event); if (d != 0) { _Emscripten_HandlePointerLeave(data, d); _SDL_free(d); } | ||
| 837 | }; | ||
| 838 | target.addEventListener("pointerleave", SDL3.eventHandlerPointerLeave); | ||
| 839 | target.addEventListener("pointercancel", SDL3.eventHandlerPointerLeave); // catch this, just in case. | ||
| 840 | |||
| 841 | SDL3.eventHandlerPointerGeneric = function(event) { | ||
| 842 | var d = makePointerEventCStruct(event); if (d != 0) { _Emscripten_HandlePointerGeneric(data, d); _SDL_free(d); } | ||
| 843 | }; | ||
| 844 | target.addEventListener("pointerdown", SDL3.eventHandlerPointerGeneric); | ||
| 845 | target.addEventListener("pointerup", SDL3.eventHandlerPointerGeneric); | ||
| 846 | target.addEventListener("pointermove", SDL3.eventHandlerPointerGeneric); | ||
| 847 | } | ||
| 848 | }, data, data->canvas_id, sizeof (Emscripten_PointerEvent)); | ||
| 849 | } | ||
| 850 | |||
| 851 | static void Emscripten_unset_pointer_event_callbacks(SDL_WindowData *data) | ||
| 852 | { | ||
| 853 | MAIN_THREAD_EM_ASM({ | ||
| 854 | var target = document.querySelector(UTF8ToString($0)); | ||
| 855 | if (target) { | ||
| 856 | var SDL3 = Module['SDL3']; | ||
| 857 | target.removeEventListener("pointerenter", SDL3.eventHandlerPointerEnter); | ||
| 858 | target.removeEventListener("pointerleave", SDL3.eventHandlerPointerLeave); | ||
| 859 | target.removeEventListener("pointercancel", SDL3.eventHandlerPointerLeave); | ||
| 860 | target.removeEventListener("pointerdown", SDL3.eventHandlerPointerGeneric); | ||
| 861 | target.removeEventListener("pointerup", SDL3.eventHandlerPointerGeneric); | ||
| 862 | target.removeEventListener("pointermove", SDL3.eventHandlerPointerGeneric); | ||
| 863 | SDL3.eventHandlerPointerEnter = undefined; | ||
| 864 | SDL3.eventHandlerPointerLeave = undefined; | ||
| 865 | SDL3.eventHandlerPointerGeneric = undefined; | ||
| 866 | } | ||
| 867 | }, data->canvas_id); | ||
| 868 | } | ||
| 869 | |||
| 870 | // IF YOU CHANGE THIS STRUCTURE, YOU NEED TO UPDATE THE JAVASCRIPT THAT FILLS IT IN: makeDropEventCStruct, below. | ||
| 871 | typedef struct Emscripten_DropEvent | ||
| 872 | { | ||
| 873 | int x; | ||
| 874 | int y; | ||
| 875 | } Emscripten_DropEvent; | ||
| 876 | |||
| 877 | EMSCRIPTEN_KEEPALIVE void Emscripten_SendDragEvent(SDL_WindowData *window_data, const Emscripten_DropEvent *event) | ||
| 878 | { | ||
| 879 | SDL_SendDropPosition(window_data->window, event->x, event->y); | ||
| 880 | } | ||
| 881 | |||
| 882 | EMSCRIPTEN_KEEPALIVE void Emscripten_SendDragCompleteEvent(SDL_WindowData *window_data) | ||
| 883 | { | ||
| 884 | SDL_SendDropComplete(window_data->window); | ||
| 885 | } | ||
| 886 | |||
| 887 | EMSCRIPTEN_KEEPALIVE void Emscripten_SendDragTextEvent(SDL_WindowData *window_data, char *text) | ||
| 888 | { | ||
| 889 | SDL_SendDropText(window_data->window, text); | ||
| 890 | } | ||
| 891 | |||
| 892 | EMSCRIPTEN_KEEPALIVE void Emscripten_SendDragFileEvent(SDL_WindowData *window_data, char *filename) | ||
| 893 | { | ||
| 894 | SDL_SendDropFile(window_data->window, NULL, filename); | ||
| 895 | } | ||
| 896 | |||
| 897 | EM_JS_DEPS(dragndrop, "$writeArrayToMemory"); | ||
| 898 | |||
| 899 | static void Emscripten_set_drag_event_callbacks(SDL_WindowData *data) | ||
| 900 | { | ||
| 901 | MAIN_THREAD_EM_ASM({ | ||
| 902 | var target = document.querySelector(UTF8ToString($1)); | ||
| 903 | if (target) { | ||
| 904 | var data = $0; | ||
| 905 | |||
| 906 | if (typeof(Module['SDL3']) === 'undefined') { | ||
| 907 | Module['SDL3'] = {}; | ||
| 908 | } | ||
| 909 | var SDL3 = Module['SDL3']; | ||
| 910 | |||
| 911 | var makeDropEventCStruct = function(event) { | ||
| 912 | var ptr = 0; | ||
| 913 | ptr = _SDL_malloc($2); | ||
| 914 | if (ptr != 0) { | ||
| 915 | var idx = ptr >> 2; | ||
| 916 | var rect = target.getBoundingClientRect(); | ||
| 917 | HEAP32[idx++] = event.clientX - rect.left; | ||
| 918 | HEAP32[idx++] = event.clientY - rect.top; | ||
| 919 | } | ||
| 920 | return ptr; | ||
| 921 | }; | ||
| 922 | |||
| 923 | SDL3.eventHandlerDropDragover = function(event) { | ||
| 924 | event.preventDefault(); | ||
| 925 | var d = makeDropEventCStruct(event); if (d != 0) { _Emscripten_SendDragEvent(data, d); _SDL_free(d); } | ||
| 926 | }; | ||
| 927 | target.addEventListener("dragover", SDL3.eventHandlerDropDragover); | ||
| 928 | |||
| 929 | SDL3.drop_count = 0; | ||
| 930 | FS.mkdir("/tmp/filedrop"); | ||
| 931 | SDL3.eventHandlerDropDrop = function(event) { | ||
| 932 | event.preventDefault(); | ||
| 933 | if (event.dataTransfer.types.includes("text/plain")) { | ||
| 934 | let plain_text = stringToNewUTF8(event.dataTransfer.getData("text/plain")); | ||
| 935 | _Emscripten_SendDragTextEvent(data, plain_text); | ||
| 936 | _free(plain_text); | ||
| 937 | } else if (event.dataTransfer.types.includes("Files")) { | ||
| 938 | for (let i = 0; i < event.dataTransfer.files.length; i++) { | ||
| 939 | const file = event.dataTransfer.files.item(i); | ||
| 940 | const file_reader = new FileReader(); | ||
| 941 | file_reader.readAsArrayBuffer(file); | ||
| 942 | file_reader.onload = function(event) { | ||
| 943 | const fs_dropdir = `/tmp/filedrop/${SDL3.drop_count}`; | ||
| 944 | SDL3.drop_count += 1; | ||
| 945 | |||
| 946 | const fs_filepath = `${fs_dropdir}/${file.name}`; | ||
| 947 | const c_fs_filepath = stringToNewUTF8(fs_filepath); | ||
| 948 | const contents_array8 = new Uint8Array(event.target.result); | ||
| 949 | |||
| 950 | FS.mkdir(fs_dropdir); | ||
| 951 | var stream = FS.open(fs_filepath, "w"); | ||
| 952 | FS.write(stream, contents_array8, 0, contents_array8.length, 0); | ||
| 953 | FS.close(stream); | ||
| 954 | |||
| 955 | _Emscripten_SendDragFileEvent(data, c_fs_filepath); | ||
| 956 | _free(c_fs_filepath); | ||
| 957 | _Emscripten_SendDragCompleteEvent(data); | ||
| 958 | }; | ||
| 959 | } | ||
| 960 | } | ||
| 961 | _Emscripten_SendDragCompleteEvent(data); | ||
| 962 | }; | ||
| 963 | target.addEventListener("drop", SDL3.eventHandlerDropDrop); | ||
| 964 | |||
| 965 | SDL3.eventHandlerDropDragend = function(event) { | ||
| 966 | event.preventDefault(); | ||
| 967 | _Emscripten_SendDragCompleteEvent(data); | ||
| 968 | }; | ||
| 969 | target.addEventListener("dragend", SDL3.eventHandlerDropDragend); | ||
| 970 | target.addEventListener("dragleave", SDL3.eventHandlerDropDragend); | ||
| 971 | } | ||
| 972 | }, data, data->canvas_id, sizeof (Emscripten_DropEvent)); | ||
| 973 | } | ||
| 974 | |||
| 975 | static void Emscripten_unset_drag_event_callbacks(SDL_WindowData *data) | ||
| 976 | { | ||
| 977 | MAIN_THREAD_EM_ASM({ | ||
| 978 | var target = document.querySelector(UTF8ToString($0)); | ||
| 979 | if (target) { | ||
| 980 | var SDL3 = Module['SDL3']; | ||
| 981 | target.removeEventListener("dragleave", SDL3.eventHandlerDropDragend); | ||
| 982 | target.removeEventListener("dragend", SDL3.eventHandlerDropDragend); | ||
| 983 | target.removeEventListener("drop", SDL3.eventHandlerDropDrop); | ||
| 984 | SDL3.drop_count = undefined; | ||
| 985 | |||
| 986 | function recursive_remove(dirpath) { | ||
| 987 | FS.readdir(dirpath).forEach((filename) => { | ||
| 988 | const p = `${dirpath}/${filename}`; | ||
| 989 | const p_s = FS.stat(p); | ||
| 990 | if (FS.isFile(p_s.mode)) { | ||
| 991 | FS.unlink(p); | ||
| 992 | } else if (FS.isDir(p)) { | ||
| 993 | recursive_remove(p); | ||
| 994 | } | ||
| 995 | }); | ||
| 996 | FS.rmdir(dirpath); | ||
| 997 | }("/tmp/filedrop"); | ||
| 998 | |||
| 999 | FS.rmdir("/tmp/filedrop"); | ||
| 1000 | target.removeEventListener("dragover", SDL3.eventHandlerDropDragover); | ||
| 1001 | SDL3.eventHandlerDropDragover = undefined; | ||
| 1002 | SDL3.eventHandlerDropDrop = undefined; | ||
| 1003 | SDL3.eventHandlerDropDragend = undefined; | ||
| 1004 | } | ||
| 1005 | }, data->canvas_id); | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | void Emscripten_RegisterEventHandlers(SDL_WindowData *data) | ||
| 1009 | { | ||
| 1010 | const char *keyElement; | ||
| 1011 | |||
| 1012 | // There is only one window and that window is the canvas | ||
| 1013 | emscripten_set_mousemove_callback(data->canvas_id, data, 0, Emscripten_HandleMouseMove); | ||
| 1014 | |||
| 1015 | emscripten_set_mousedown_callback(data->canvas_id, data, 0, Emscripten_HandleMouseButton); | ||
| 1016 | emscripten_set_mouseup_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, data, 0, Emscripten_HandleMouseButton); | ||
| 1017 | |||
| 1018 | emscripten_set_mouseenter_callback(data->canvas_id, data, 0, Emscripten_HandleMouseFocus); | ||
| 1019 | emscripten_set_mouseleave_callback(data->canvas_id, data, 0, Emscripten_HandleMouseFocus); | ||
| 1020 | |||
| 1021 | emscripten_set_wheel_callback(data->canvas_id, data, 0, Emscripten_HandleWheel); | ||
| 1022 | |||
| 1023 | emscripten_set_focus_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, data, 0, Emscripten_HandleFocus); | ||
| 1024 | emscripten_set_blur_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, data, 0, Emscripten_HandleFocus); | ||
| 1025 | |||
| 1026 | emscripten_set_orientationchange_callback(data, 0, Emscripten_HandleOrientationChange); | ||
| 1027 | |||
| 1028 | emscripten_set_touchstart_callback(data->canvas_id, data, 0, Emscripten_HandleTouch); | ||
| 1029 | emscripten_set_touchend_callback(data->canvas_id, data, 0, Emscripten_HandleTouch); | ||
| 1030 | emscripten_set_touchmove_callback(data->canvas_id, data, 0, Emscripten_HandleTouch); | ||
| 1031 | emscripten_set_touchcancel_callback(data->canvas_id, data, 0, Emscripten_HandleTouch); | ||
| 1032 | |||
| 1033 | emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, data, 0, Emscripten_HandlePointerLockChange); | ||
| 1034 | |||
| 1035 | // Keyboard events are awkward | ||
| 1036 | keyElement = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT); | ||
| 1037 | if (!keyElement || !*keyElement) { | ||
| 1038 | keyElement = EMSCRIPTEN_EVENT_TARGET_WINDOW; | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | if (SDL_strcmp(keyElement, "#none") != 0) { | ||
| 1042 | emscripten_set_keydown_callback(keyElement, data, 0, Emscripten_HandleKey); | ||
| 1043 | emscripten_set_keyup_callback(keyElement, data, 0, Emscripten_HandleKey); | ||
| 1044 | emscripten_set_keypress_callback(keyElement, data, 0, Emscripten_HandleKeyPress); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, data, 0, Emscripten_HandleFullscreenChange); | ||
| 1048 | |||
| 1049 | emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, data, 0, Emscripten_HandleResize); | ||
| 1050 | |||
| 1051 | emscripten_set_visibilitychange_callback(data, 0, Emscripten_HandleVisibilityChange); | ||
| 1052 | |||
| 1053 | emscripten_set_beforeunload_callback(data, Emscripten_HandleBeforeUnload); | ||
| 1054 | |||
| 1055 | // !!! FIXME: currently Emscripten doesn't have a Pointer Events functions like emscripten_set_*_callback, but we should use those when they do: | ||
| 1056 | // !!! FIXME: https://github.com/emscripten-core/emscripten/issues/7278#issuecomment-2280024621 | ||
| 1057 | Emscripten_set_pointer_event_callbacks(data); | ||
| 1058 | |||
| 1059 | // !!! FIXME: currently Emscripten doesn't have a Drop Events functions like emscripten_set_*_callback, but we should use those when they do: | ||
| 1060 | Emscripten_set_drag_event_callbacks(data); | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | void Emscripten_UnregisterEventHandlers(SDL_WindowData *data) | ||
| 1064 | { | ||
| 1065 | const char *target; | ||
| 1066 | |||
| 1067 | // !!! FIXME: currently Emscripten doesn't have a Drop Events functions like emscripten_set_*_callback, but we should use those when they do: | ||
| 1068 | Emscripten_unset_drag_event_callbacks(data); | ||
| 1069 | |||
| 1070 | // !!! FIXME: currently Emscripten doesn't have a Pointer Events functions like emscripten_set_*_callback, but we should use those when they do: | ||
| 1071 | // !!! FIXME: https://github.com/emscripten-core/emscripten/issues/7278#issuecomment-2280024621 | ||
| 1072 | Emscripten_unset_pointer_event_callbacks(data); | ||
| 1073 | |||
| 1074 | // only works due to having one window | ||
| 1075 | emscripten_set_mousemove_callback(data->canvas_id, NULL, 0, NULL); | ||
| 1076 | |||
| 1077 | emscripten_set_mousedown_callback(data->canvas_id, NULL, 0, NULL); | ||
| 1078 | emscripten_set_mouseup_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, 0, NULL); | ||
| 1079 | |||
| 1080 | emscripten_set_mouseenter_callback(data->canvas_id, NULL, 0, NULL); | ||
| 1081 | emscripten_set_mouseleave_callback(data->canvas_id, NULL, 0, NULL); | ||
| 1082 | |||
| 1083 | emscripten_set_wheel_callback(data->canvas_id, NULL, 0, NULL); | ||
| 1084 | |||
| 1085 | emscripten_set_focus_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 0, NULL); | ||
| 1086 | emscripten_set_blur_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 0, NULL); | ||
| 1087 | |||
| 1088 | emscripten_set_orientationchange_callback(NULL, 0, NULL); | ||
| 1089 | |||
| 1090 | emscripten_set_touchstart_callback(data->canvas_id, NULL, 0, NULL); | ||
| 1091 | emscripten_set_touchend_callback(data->canvas_id, NULL, 0, NULL); | ||
| 1092 | emscripten_set_touchmove_callback(data->canvas_id, NULL, 0, NULL); | ||
| 1093 | emscripten_set_touchcancel_callback(data->canvas_id, NULL, 0, NULL); | ||
| 1094 | |||
| 1095 | emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, 0, NULL); | ||
| 1096 | |||
| 1097 | target = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT); | ||
| 1098 | if (!target || !*target) { | ||
| 1099 | target = EMSCRIPTEN_EVENT_TARGET_WINDOW; | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | if (SDL_strcmp(target, "#none") != 0) { | ||
| 1103 | emscripten_set_keydown_callback(target, NULL, 0, NULL); | ||
| 1104 | emscripten_set_keyup_callback(target, NULL, 0, NULL); | ||
| 1105 | emscripten_set_keypress_callback(target, NULL, 0, NULL); | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, 0, NULL); | ||
| 1109 | |||
| 1110 | emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 0, NULL); | ||
| 1111 | |||
| 1112 | emscripten_set_visibilitychange_callback(NULL, 0, NULL); | ||
| 1113 | |||
| 1114 | emscripten_set_beforeunload_callback(NULL, NULL); | ||
| 1115 | } | ||
| 1116 | |||
| 1117 | #endif // SDL_VIDEO_DRIVER_EMSCRIPTEN | ||
