From 5a079a2d114f96d4847d1ee305d5b7c16eeec50e Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 27 Dec 2025 12:03:39 -0800 Subject: Initial commit --- contrib/SDL-3.2.8/src/events/SDL_categories.c | 249 +++ contrib/SDL-3.2.8/src/events/SDL_categories_c.h | 70 + contrib/SDL-3.2.8/src/events/SDL_clipboardevents.c | 57 + .../SDL-3.2.8/src/events/SDL_clipboardevents_c.h | 28 + contrib/SDL-3.2.8/src/events/SDL_displayevents.c | 64 + contrib/SDL-3.2.8/src/events/SDL_displayevents_c.h | 28 + contrib/SDL-3.2.8/src/events/SDL_dropevents.c | 115 ++ contrib/SDL-3.2.8/src/events/SDL_dropevents_c.h | 31 + contrib/SDL-3.2.8/src/events/SDL_events.c | 1987 ++++++++++++++++++++ contrib/SDL-3.2.8/src/events/SDL_events_c.h | 66 + contrib/SDL-3.2.8/src/events/SDL_eventwatch.c | 143 ++ contrib/SDL-3.2.8/src/events/SDL_eventwatch_c.h | 45 + contrib/SDL-3.2.8/src/events/SDL_keyboard.c | 922 +++++++++ contrib/SDL-3.2.8/src/events/SDL_keyboard_c.h | 87 + contrib/SDL-3.2.8/src/events/SDL_keymap.c | 1153 ++++++++++++ contrib/SDL-3.2.8/src/events/SDL_keymap_c.h | 35 + .../SDL-3.2.8/src/events/SDL_keysym_to_keycode.c | 68 + .../SDL-3.2.8/src/events/SDL_keysym_to_keycode_c.h | 28 + .../SDL-3.2.8/src/events/SDL_keysym_to_scancode.c | 439 +++++ .../src/events/SDL_keysym_to_scancode_c.h | 28 + contrib/SDL-3.2.8/src/events/SDL_mouse.c | 1673 ++++++++++++++++ contrib/SDL-3.2.8/src/events/SDL_mouse_c.h | 208 ++ contrib/SDL-3.2.8/src/events/SDL_pen.c | 577 ++++++ contrib/SDL-3.2.8/src/events/SDL_pen_c.h | 99 + contrib/SDL-3.2.8/src/events/SDL_quit.c | 194 ++ contrib/SDL-3.2.8/src/events/SDL_scancode_tables.c | 71 + .../SDL-3.2.8/src/events/SDL_scancode_tables_c.h | 33 + contrib/SDL-3.2.8/src/events/SDL_touch.c | 500 +++++ contrib/SDL-3.2.8/src/events/SDL_touch_c.h | 60 + contrib/SDL-3.2.8/src/events/SDL_windowevents.c | 300 +++ contrib/SDL-3.2.8/src/events/SDL_windowevents_c.h | 39 + contrib/SDL-3.2.8/src/events/blank_cursor.h | 31 + contrib/SDL-3.2.8/src/events/default_cursor.h | 113 ++ contrib/SDL-3.2.8/src/events/imKStoUCS.c | 349 ++++ contrib/SDL-3.2.8/src/events/imKStoUCS.h | 32 + contrib/SDL-3.2.8/src/events/scancodes_darwin.h | 159 ++ contrib/SDL-3.2.8/src/events/scancodes_linux.h | 848 +++++++++ contrib/SDL-3.2.8/src/events/scancodes_windows.h | 286 +++ contrib/SDL-3.2.8/src/events/scancodes_xfree86.h | 520 +++++ 39 files changed, 11735 insertions(+) create mode 100644 contrib/SDL-3.2.8/src/events/SDL_categories.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_categories_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_clipboardevents.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_clipboardevents_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_displayevents.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_displayevents_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_dropevents.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_dropevents_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_events.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_events_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_eventwatch.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_eventwatch_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_keyboard.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_keyboard_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_keymap.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_keymap_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_keysym_to_keycode.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_keysym_to_keycode_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_keysym_to_scancode.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_keysym_to_scancode_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_mouse.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_mouse_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_pen.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_pen_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_quit.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_scancode_tables.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_scancode_tables_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_touch.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_touch_c.h create mode 100644 contrib/SDL-3.2.8/src/events/SDL_windowevents.c create mode 100644 contrib/SDL-3.2.8/src/events/SDL_windowevents_c.h create mode 100644 contrib/SDL-3.2.8/src/events/blank_cursor.h create mode 100644 contrib/SDL-3.2.8/src/events/default_cursor.h create mode 100644 contrib/SDL-3.2.8/src/events/imKStoUCS.c create mode 100644 contrib/SDL-3.2.8/src/events/imKStoUCS.h create mode 100644 contrib/SDL-3.2.8/src/events/scancodes_darwin.h create mode 100644 contrib/SDL-3.2.8/src/events/scancodes_linux.h create mode 100644 contrib/SDL-3.2.8/src/events/scancodes_windows.h create mode 100644 contrib/SDL-3.2.8/src/events/scancodes_xfree86.h (limited to 'contrib/SDL-3.2.8/src/events') diff --git a/contrib/SDL-3.2.8/src/events/SDL_categories.c b/contrib/SDL-3.2.8/src/events/SDL_categories.c new file mode 100644 index 0000000..cb41f6f --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_categories.c @@ -0,0 +1,249 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// SDL event categories + +#include "SDL_events_c.h" +#include "SDL_categories_c.h" + +SDL_EventCategory SDL_GetEventCategory(Uint32 type) +{ + if (type >= SDL_EVENT_USER && type <= SDL_EVENT_LAST) { + return SDL_EVENTCATEGORY_USER; + } + else if (type >= SDL_EVENT_DISPLAY_FIRST && type <= SDL_EVENT_DISPLAY_LAST) { + return SDL_EVENTCATEGORY_DISPLAY; + } + else if (type >= SDL_EVENT_WINDOW_FIRST && type <= SDL_EVENT_WINDOW_LAST) { + return SDL_EVENTCATEGORY_WINDOW; + } + switch (type) { + default: + SDL_SetError("Unknown event type"); + return SDL_EVENTCATEGORY_UNKNOWN; + + case SDL_EVENT_KEYMAP_CHANGED: + case SDL_EVENT_TERMINATING: + case SDL_EVENT_LOW_MEMORY: + case SDL_EVENT_WILL_ENTER_BACKGROUND: + case SDL_EVENT_DID_ENTER_BACKGROUND: + case SDL_EVENT_WILL_ENTER_FOREGROUND: + case SDL_EVENT_DID_ENTER_FOREGROUND: + case SDL_EVENT_LOCALE_CHANGED: + case SDL_EVENT_SYSTEM_THEME_CHANGED: + return SDL_EVENTCATEGORY_SYSTEM; + + case SDL_EVENT_RENDER_TARGETS_RESET: + case SDL_EVENT_RENDER_DEVICE_RESET: + case SDL_EVENT_RENDER_DEVICE_LOST: + return SDL_EVENTCATEGORY_RENDER; + + case SDL_EVENT_QUIT: + return SDL_EVENTCATEGORY_QUIT; + + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: + return SDL_EVENTCATEGORY_KEY; + + case SDL_EVENT_TEXT_EDITING: + return SDL_EVENTCATEGORY_EDIT; + + case SDL_EVENT_TEXT_INPUT: + return SDL_EVENTCATEGORY_TEXT; + + case SDL_EVENT_KEYBOARD_ADDED: + case SDL_EVENT_KEYBOARD_REMOVED: + return SDL_EVENTCATEGORY_KDEVICE; + + case SDL_EVENT_TEXT_EDITING_CANDIDATES: + return SDL_EVENTCATEGORY_EDIT_CANDIDATES; + + case SDL_EVENT_MOUSE_MOTION: + return SDL_EVENTCATEGORY_MOTION; + + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: + return SDL_EVENTCATEGORY_BUTTON; + + case SDL_EVENT_MOUSE_WHEEL: + return SDL_EVENTCATEGORY_WHEEL; + + case SDL_EVENT_MOUSE_ADDED: + case SDL_EVENT_MOUSE_REMOVED: + return SDL_EVENTCATEGORY_MDEVICE; + + case SDL_EVENT_JOYSTICK_AXIS_MOTION: + return SDL_EVENTCATEGORY_JAXIS; + + case SDL_EVENT_JOYSTICK_BALL_MOTION: + return SDL_EVENTCATEGORY_JBALL; + + case SDL_EVENT_JOYSTICK_HAT_MOTION: + return SDL_EVENTCATEGORY_JHAT; + + case SDL_EVENT_JOYSTICK_BUTTON_DOWN: + case SDL_EVENT_JOYSTICK_BUTTON_UP: + return SDL_EVENTCATEGORY_JBUTTON; + + case SDL_EVENT_JOYSTICK_ADDED: + case SDL_EVENT_JOYSTICK_REMOVED: + case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE: + return SDL_EVENTCATEGORY_JDEVICE; + + case SDL_EVENT_JOYSTICK_BATTERY_UPDATED: + return SDL_EVENTCATEGORY_JBATTERY; + + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + return SDL_EVENTCATEGORY_GAXIS; + + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: + return SDL_EVENTCATEGORY_GBUTTON; + + case SDL_EVENT_GAMEPAD_ADDED: + case SDL_EVENT_GAMEPAD_REMOVED: + case SDL_EVENT_GAMEPAD_REMAPPED: + case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE: + case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED: + return SDL_EVENTCATEGORY_GDEVICE; + + case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: + case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: + case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: + return SDL_EVENTCATEGORY_GTOUCHPAD; + + case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: + return SDL_EVENTCATEGORY_GSENSOR; + + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: + case SDL_EVENT_FINGER_CANCELED: + case SDL_EVENT_FINGER_MOTION: + return SDL_EVENTCATEGORY_TFINGER; + + case SDL_EVENT_CLIPBOARD_UPDATE: + return SDL_EVENTCATEGORY_CLIPBOARD; + + case SDL_EVENT_DROP_FILE: + case SDL_EVENT_DROP_TEXT: + case SDL_EVENT_DROP_BEGIN: + case SDL_EVENT_DROP_COMPLETE: + case SDL_EVENT_DROP_POSITION: + return SDL_EVENTCATEGORY_DROP; + + case SDL_EVENT_AUDIO_DEVICE_ADDED: + case SDL_EVENT_AUDIO_DEVICE_REMOVED: + case SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED: + return SDL_EVENTCATEGORY_ADEVICE; + + case SDL_EVENT_SENSOR_UPDATE: + return SDL_EVENTCATEGORY_SENSOR; + + case SDL_EVENT_PEN_PROXIMITY_IN: + case SDL_EVENT_PEN_PROXIMITY_OUT: + return SDL_EVENTCATEGORY_PPROXIMITY; + + case SDL_EVENT_PEN_DOWN: + case SDL_EVENT_PEN_UP: + return SDL_EVENTCATEGORY_PTOUCH; + + case SDL_EVENT_PEN_BUTTON_DOWN: + case SDL_EVENT_PEN_BUTTON_UP: + return SDL_EVENTCATEGORY_PBUTTON; + + case SDL_EVENT_PEN_MOTION: + return SDL_EVENTCATEGORY_PMOTION; + + case SDL_EVENT_PEN_AXIS: + return SDL_EVENTCATEGORY_PAXIS; + + case SDL_EVENT_CAMERA_DEVICE_ADDED: + case SDL_EVENT_CAMERA_DEVICE_REMOVED: + case SDL_EVENT_CAMERA_DEVICE_APPROVED: + case SDL_EVENT_CAMERA_DEVICE_DENIED: + return SDL_EVENTCATEGORY_CDEVICE; + } +} + +SDL_Window *SDL_GetWindowFromEvent(const SDL_Event *event) +{ + SDL_WindowID windowID; + + switch (SDL_GetEventCategory(event->type)) { + case SDL_EVENTCATEGORY_USER: + windowID = event->user.windowID; + break; + case SDL_EVENTCATEGORY_WINDOW: + windowID = event->window.windowID; + break; + case SDL_EVENTCATEGORY_KEY: + windowID = event->key.windowID; + break; + case SDL_EVENTCATEGORY_EDIT: + windowID = event->edit.windowID; + break; + case SDL_EVENTCATEGORY_TEXT: + windowID = event->text.windowID; + break; + case SDL_EVENTCATEGORY_EDIT_CANDIDATES: + windowID = event->edit_candidates.windowID; + break; + case SDL_EVENTCATEGORY_MOTION: + windowID = event->motion.windowID; + break; + case SDL_EVENTCATEGORY_BUTTON: + windowID = event->button.windowID; + break; + case SDL_EVENTCATEGORY_WHEEL: + windowID = event->wheel.windowID; + break; + case SDL_EVENTCATEGORY_TFINGER: + windowID = event->tfinger.windowID; + break; + case SDL_EVENTCATEGORY_PPROXIMITY: + windowID = event->pproximity.windowID; + break; + case SDL_EVENTCATEGORY_PTOUCH: + windowID = event->ptouch.windowID; + break; + case SDL_EVENTCATEGORY_PBUTTON: + windowID = event->pbutton.windowID; + break; + case SDL_EVENTCATEGORY_PMOTION: + windowID = event->pmotion.windowID; + break; + case SDL_EVENTCATEGORY_PAXIS: + windowID = event->paxis.windowID; + break; + case SDL_EVENTCATEGORY_DROP: + windowID = event->drop.windowID; + break; + case SDL_EVENTCATEGORY_RENDER: + windowID = event->render.windowID; + break; + default: + // < 0 -> invalid event type (error is set by SDL_GetEventCategory) + // else -> event has no associated window (not an error) + return NULL; + } + return SDL_GetWindowFromID(windowID); +} diff --git a/contrib/SDL-3.2.8/src/events/SDL_categories_c.h b/contrib/SDL-3.2.8/src/events/SDL_categories_c.h new file mode 100644 index 0000000..31d926a --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_categories_c.h @@ -0,0 +1,70 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_categories_c_h_ +#define SDL_categories_c_h_ + +typedef enum SDL_EventCategory +{ + SDL_EVENTCATEGORY_UNKNOWN, + SDL_EVENTCATEGORY_SYSTEM, + SDL_EVENTCATEGORY_DISPLAY, + SDL_EVENTCATEGORY_WINDOW, + SDL_EVENTCATEGORY_KDEVICE, + SDL_EVENTCATEGORY_KEY, + SDL_EVENTCATEGORY_EDIT, + SDL_EVENTCATEGORY_EDIT_CANDIDATES, + SDL_EVENTCATEGORY_TEXT, + SDL_EVENTCATEGORY_MDEVICE, + SDL_EVENTCATEGORY_MOTION, + SDL_EVENTCATEGORY_BUTTON, + SDL_EVENTCATEGORY_WHEEL, + SDL_EVENTCATEGORY_JDEVICE, + SDL_EVENTCATEGORY_JAXIS, + SDL_EVENTCATEGORY_JBALL, + SDL_EVENTCATEGORY_JHAT, + SDL_EVENTCATEGORY_JBUTTON, + SDL_EVENTCATEGORY_JBATTERY, + SDL_EVENTCATEGORY_GDEVICE, + SDL_EVENTCATEGORY_GAXIS, + SDL_EVENTCATEGORY_GBUTTON, + SDL_EVENTCATEGORY_GTOUCHPAD, + SDL_EVENTCATEGORY_GSENSOR, + SDL_EVENTCATEGORY_ADEVICE, + SDL_EVENTCATEGORY_CDEVICE, + SDL_EVENTCATEGORY_SENSOR, + SDL_EVENTCATEGORY_QUIT, + SDL_EVENTCATEGORY_USER, + SDL_EVENTCATEGORY_TFINGER, + SDL_EVENTCATEGORY_PPROXIMITY, + SDL_EVENTCATEGORY_PTOUCH, + SDL_EVENTCATEGORY_PMOTION, + SDL_EVENTCATEGORY_PBUTTON, + SDL_EVENTCATEGORY_PAXIS, + SDL_EVENTCATEGORY_DROP, + SDL_EVENTCATEGORY_CLIPBOARD, + SDL_EVENTCATEGORY_RENDER, +} SDL_EventCategory; + +extern SDL_EventCategory SDL_GetEventCategory(Uint32 type); + +#endif // SDL_categories_c_h_ diff --git a/contrib/SDL-3.2.8/src/events/SDL_clipboardevents.c b/contrib/SDL-3.2.8/src/events/SDL_clipboardevents.c new file mode 100644 index 0000000..d5cf8ad --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_clipboardevents.c @@ -0,0 +1,57 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// Clipboard event handling code for SDL + +#include "SDL_events_c.h" +#include "SDL_clipboardevents_c.h" +#include "../video/SDL_clipboard_c.h" + +void SDL_SendClipboardUpdate(bool owner, char **mime_types, size_t num_mime_types) +{ + if (!owner) { + /* Clear our internal clipboard contents when external clipboard is set. + * + * Wayland recursively sends a data offer to the client from which the clipboard data originated, + * and as the client can't determine the origin of the offer, the clipboard must not be cleared, + * or the original data may be destroyed. Cleanup will be done in the backend when an offer + * cancellation event arrives. + */ + if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") != 0) { + SDL_CancelClipboardData(0); + } + + SDL_SaveClipboardMimeTypes((const char **)mime_types, num_mime_types); + } + + if (SDL_EventEnabled(SDL_EVENT_CLIPBOARD_UPDATE)) { + SDL_Event event; + event.type = SDL_EVENT_CLIPBOARD_UPDATE; + + SDL_ClipboardEvent *cevent = &event.clipboard; + cevent->timestamp = 0; + cevent->owner = owner; + cevent->mime_types = (const char **)mime_types; + cevent->num_mime_types = (Uint32)num_mime_types; + SDL_PushEvent(&event); + } +} diff --git a/contrib/SDL-3.2.8/src/events/SDL_clipboardevents_c.h b/contrib/SDL-3.2.8/src/events/SDL_clipboardevents_c.h new file mode 100644 index 0000000..0b0f628 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_clipboardevents_c.h @@ -0,0 +1,28 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_clipboardevents_c_h_ +#define SDL_clipboardevents_c_h_ + +extern void SDL_SendClipboardUpdate(bool owner, char **mime_types, size_t num_mime_types); + +#endif // SDL_clipboardevents_c_h_ diff --git a/contrib/SDL-3.2.8/src/events/SDL_displayevents.c b/contrib/SDL-3.2.8/src/events/SDL_displayevents.c new file mode 100644 index 0000000..e41f75c --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_displayevents.c @@ -0,0 +1,64 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// Display event handling code for SDL + +#include "SDL_events_c.h" + +void SDL_SendDisplayEvent(SDL_VideoDisplay *display, SDL_EventType displayevent, int data1, int data2) +{ + if (!display || display->id == 0) { + return; + } + switch (displayevent) { + case SDL_EVENT_DISPLAY_ORIENTATION: + if (data1 == SDL_ORIENTATION_UNKNOWN || data1 == display->current_orientation) { + return; + } + display->current_orientation = (SDL_DisplayOrientation)data1; + break; + default: + break; + } + + // Post the event, if desired + if (SDL_EventEnabled(displayevent)) { + SDL_Event event; + event.type = displayevent; + event.common.timestamp = 0; + event.display.displayID = display->id; + event.display.data1 = data1; + event.display.data2 = data2; + SDL_PushEvent(&event); + } + + switch (displayevent) { + case SDL_EVENT_DISPLAY_ADDED: + SDL_OnDisplayAdded(display); + break; + case SDL_EVENT_DISPLAY_MOVED: + SDL_OnDisplayMoved(display); + break; + default: + break; + } +} diff --git a/contrib/SDL-3.2.8/src/events/SDL_displayevents_c.h b/contrib/SDL-3.2.8/src/events/SDL_displayevents_c.h new file mode 100644 index 0000000..ae0730c --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_displayevents_c.h @@ -0,0 +1,28 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_displayevents_c_h_ +#define SDL_displayevents_c_h_ + +extern void SDL_SendDisplayEvent(SDL_VideoDisplay *display, SDL_EventType displayevent, int data1, int data2); + +#endif // SDL_displayevents_c_h_ diff --git a/contrib/SDL-3.2.8/src/events/SDL_dropevents.c b/contrib/SDL-3.2.8/src/events/SDL_dropevents.c new file mode 100644 index 0000000..661f4f3 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_dropevents.c @@ -0,0 +1,115 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// Drag and drop event handling code for SDL + +#include "SDL_events_c.h" +#include "SDL_dropevents_c.h" + +#include "../video/SDL_sysvideo.h" // for SDL_Window internals. + +static bool SDL_SendDrop(SDL_Window *window, const SDL_EventType evtype, const char *source, const char *data, float x, float y) +{ + static bool app_is_dropping = false; + static float last_drop_x = 0; + static float last_drop_y = 0; + bool posted = false; + + // Post the event, if desired + if (SDL_EventEnabled(evtype)) { + const bool need_begin = window ? !window->is_dropping : !app_is_dropping; + SDL_Event event; + + if (need_begin) { + SDL_zero(event); + event.type = SDL_EVENT_DROP_BEGIN; + event.common.timestamp = 0; + event.drop.windowID = window ? window->id : 0; + posted = SDL_PushEvent(&event); + if (!posted) { + return false; + } + if (window) { + window->is_dropping = true; + } else { + app_is_dropping = true; + } + } + + SDL_zero(event); + event.type = evtype; + event.common.timestamp = 0; + if (source) { + event.drop.source = SDL_CreateTemporaryString(source); + if (!event.drop.source) { + return false; + } + } + if (data) { + event.drop.data = SDL_CreateTemporaryString(data); + if (!event.drop.data) { + return false; + } + } + event.drop.windowID = window ? window->id : 0; + + if (evtype == SDL_EVENT_DROP_POSITION) { + last_drop_x = x; + last_drop_y = y; + } + event.drop.x = last_drop_x; + event.drop.y = last_drop_y; + posted = SDL_PushEvent(&event); + + if (posted && (evtype == SDL_EVENT_DROP_COMPLETE)) { + if (window) { + window->is_dropping = false; + } else { + app_is_dropping = false; + } + + last_drop_x = 0; + last_drop_y = 0; + } + } + return posted; +} + +bool SDL_SendDropFile(SDL_Window *window, const char *source, const char *file) +{ + return SDL_SendDrop(window, SDL_EVENT_DROP_FILE, source, file, 0, 0); +} + +bool SDL_SendDropPosition(SDL_Window *window, float x, float y) +{ + return SDL_SendDrop(window, SDL_EVENT_DROP_POSITION, NULL, NULL, x, y); +} + +bool SDL_SendDropText(SDL_Window *window, const char *text) +{ + return SDL_SendDrop(window, SDL_EVENT_DROP_TEXT, NULL, text, 0, 0); +} + +bool SDL_SendDropComplete(SDL_Window *window) +{ + return SDL_SendDrop(window, SDL_EVENT_DROP_COMPLETE, NULL, NULL, 0, 0); +} diff --git a/contrib/SDL-3.2.8/src/events/SDL_dropevents_c.h b/contrib/SDL-3.2.8/src/events/SDL_dropevents_c.h new file mode 100644 index 0000000..efce0ac --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_dropevents_c.h @@ -0,0 +1,31 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_dropevents_c_h_ +#define SDL_dropevents_c_h_ + +extern bool SDL_SendDropFile(SDL_Window *window, const char *source, const char *file); +extern bool SDL_SendDropPosition(SDL_Window *window, float x, float y); +extern bool SDL_SendDropText(SDL_Window *window, const char *text); +extern bool SDL_SendDropComplete(SDL_Window *window); + +#endif // SDL_dropevents_c_h_ diff --git a/contrib/SDL-3.2.8/src/events/SDL_events.c b/contrib/SDL-3.2.8/src/events/SDL_events.c new file mode 100644 index 0000000..349d575 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_events.c @@ -0,0 +1,1987 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// General event handling code for SDL + +#include "SDL_events_c.h" +#include "SDL_eventwatch_c.h" +#include "SDL_windowevents_c.h" +#include "../SDL_hints_c.h" +#include "../audio/SDL_audio_c.h" +#include "../camera/SDL_camera_c.h" +#include "../timer/SDL_timer_c.h" +#ifndef SDL_JOYSTICK_DISABLED +#include "../joystick/SDL_joystick_c.h" +#endif +#ifndef SDL_SENSOR_DISABLED +#include "../sensor/SDL_sensor_c.h" +#endif +#include "../video/SDL_sysvideo.h" + +#ifdef SDL_PLATFORM_ANDROID +#include "../core/android/SDL_android.h" +#include "../video/android/SDL_androidevents.h" +#endif + +// An arbitrary limit so we don't have unbounded growth +#define SDL_MAX_QUEUED_EVENTS 65535 + +// Determines how often we pump events if joystick or sensor subsystems are active +#define ENUMERATION_POLL_INTERVAL_NS (3 * SDL_NS_PER_SECOND) + +// Determines how often to pump events if joysticks or sensors are actively being read +#define EVENT_POLL_INTERVAL_NS SDL_MS_TO_NS(1) + +// Make sure the type in the SDL_Event aligns properly across the union +SDL_COMPILE_TIME_ASSERT(SDL_Event_type, sizeof(Uint32) == sizeof(SDL_EventType)); + +#define SDL2_SYSWMEVENT 0x201 + +#ifdef SDL_VIDEO_DRIVER_WINDOWS +#include "../core/windows/SDL_windows.h" +#endif + +#ifdef SDL_VIDEO_DRIVER_X11 +#include +#endif + +typedef struct SDL2_version +{ + Uint8 major; + Uint8 minor; + Uint8 patch; +} SDL2_version; + +typedef enum +{ + SDL2_SYSWM_UNKNOWN +} SDL2_SYSWM_TYPE; + +typedef struct SDL2_SysWMmsg +{ + SDL2_version version; + SDL2_SYSWM_TYPE subsystem; + union + { +#ifdef SDL_VIDEO_DRIVER_WINDOWS + struct { + HWND hwnd; /**< The window for the message */ + UINT msg; /**< The type of message */ + WPARAM wParam; /**< WORD message parameter */ + LPARAM lParam; /**< LONG message parameter */ + } win; +#endif +#ifdef SDL_VIDEO_DRIVER_X11 + struct { + XEvent event; + } x11; +#endif + /* Can't have an empty union */ + int dummy; + } msg; +} SDL2_SysWMmsg; + +static SDL_EventWatchList SDL_event_watchers; +static SDL_AtomicInt SDL_sentinel_pending; +static Uint32 SDL_last_event_id = 0; + +typedef struct +{ + Uint32 bits[8]; +} SDL_DisabledEventBlock; + +static SDL_DisabledEventBlock *SDL_disabled_events[256]; +static SDL_AtomicInt SDL_userevents; + +typedef struct SDL_TemporaryMemory +{ + void *memory; + struct SDL_TemporaryMemory *prev; + struct SDL_TemporaryMemory *next; +} SDL_TemporaryMemory; + +typedef struct SDL_TemporaryMemoryState +{ + SDL_TemporaryMemory *head; + SDL_TemporaryMemory *tail; +} SDL_TemporaryMemoryState; + +static SDL_TLSID SDL_temporary_memory; + +typedef struct SDL_EventEntry +{ + SDL_Event event; + SDL_TemporaryMemory *memory; + struct SDL_EventEntry *prev; + struct SDL_EventEntry *next; +} SDL_EventEntry; + +static struct +{ + SDL_Mutex *lock; + bool active; + SDL_AtomicInt count; + int max_events_seen; + SDL_EventEntry *head; + SDL_EventEntry *tail; + SDL_EventEntry *free; +} SDL_EventQ = { NULL, false, { 0 }, 0, NULL, NULL, NULL }; + + +static void SDL_CleanupTemporaryMemory(void *data) +{ + SDL_TemporaryMemoryState *state = (SDL_TemporaryMemoryState *)data; + + SDL_FreeTemporaryMemory(); + SDL_free(state); +} + +static SDL_TemporaryMemoryState *SDL_GetTemporaryMemoryState(bool create) +{ + SDL_TemporaryMemoryState *state; + + state = (SDL_TemporaryMemoryState *)SDL_GetTLS(&SDL_temporary_memory); + if (!state) { + if (!create) { + return NULL; + } + + state = (SDL_TemporaryMemoryState *)SDL_calloc(1, sizeof(*state)); + if (!state) { + return NULL; + } + + if (!SDL_SetTLS(&SDL_temporary_memory, state, SDL_CleanupTemporaryMemory)) { + SDL_free(state); + return NULL; + } + } + return state; +} + +static SDL_TemporaryMemory *SDL_GetTemporaryMemoryEntry(SDL_TemporaryMemoryState *state, const void *mem) +{ + SDL_TemporaryMemory *entry; + + // Start from the end, it's likely to have been recently allocated + for (entry = state->tail; entry; entry = entry->prev) { + if (mem == entry->memory) { + return entry; + } + } + return NULL; +} + +static void SDL_LinkTemporaryMemoryEntry(SDL_TemporaryMemoryState *state, SDL_TemporaryMemory *entry) +{ + entry->prev = state->tail; + entry->next = NULL; + + if (state->tail) { + state->tail->next = entry; + } else { + state->head = entry; + } + state->tail = entry; +} + +static void SDL_UnlinkTemporaryMemoryEntry(SDL_TemporaryMemoryState *state, SDL_TemporaryMemory *entry) +{ + if (state->head == entry) { + state->head = entry->next; + } + if (state->tail == entry) { + state->tail = entry->prev; + } + + if (entry->prev) { + entry->prev->next = entry->next; + } + if (entry->next) { + entry->next->prev = entry->prev; + } + + entry->prev = NULL; + entry->next = NULL; +} + +static void SDL_FreeTemporaryMemoryEntry(SDL_TemporaryMemoryState *state, SDL_TemporaryMemory *entry, bool free_data) +{ + if (free_data) { + SDL_free(entry->memory); + } + SDL_free(entry); +} + +static void SDL_LinkTemporaryMemoryToEvent(SDL_EventEntry *event, const void *mem) +{ + SDL_TemporaryMemoryState *state; + SDL_TemporaryMemory *entry; + + state = SDL_GetTemporaryMemoryState(false); + if (!state) { + return; + } + + entry = SDL_GetTemporaryMemoryEntry(state, mem); + if (entry) { + SDL_UnlinkTemporaryMemoryEntry(state, entry); + entry->next = event->memory; + event->memory = entry; + } +} + +static void SDL_TransferSysWMMemoryToEvent(SDL_EventEntry *event) +{ + SDL2_SysWMmsg **wmmsg = (SDL2_SysWMmsg **)((&event->event.common)+1); + SDL2_SysWMmsg *mem = SDL_AllocateTemporaryMemory(sizeof(*mem)); + if (mem) { + SDL_copyp(mem, *wmmsg); + *wmmsg = mem; + SDL_LinkTemporaryMemoryToEvent(event, mem); + } +} + +// Transfer the event memory from the thread-local event memory list to the event +static void SDL_TransferTemporaryMemoryToEvent(SDL_EventEntry *event) +{ + switch (event->event.type) { + case SDL_EVENT_TEXT_EDITING: + SDL_LinkTemporaryMemoryToEvent(event, event->event.edit.text); + break; + case SDL_EVENT_TEXT_EDITING_CANDIDATES: + SDL_LinkTemporaryMemoryToEvent(event, event->event.edit_candidates.candidates); + break; + case SDL_EVENT_TEXT_INPUT: + SDL_LinkTemporaryMemoryToEvent(event, event->event.text.text); + break; + case SDL_EVENT_DROP_BEGIN: + case SDL_EVENT_DROP_FILE: + case SDL_EVENT_DROP_TEXT: + case SDL_EVENT_DROP_COMPLETE: + case SDL_EVENT_DROP_POSITION: + SDL_LinkTemporaryMemoryToEvent(event, event->event.drop.source); + SDL_LinkTemporaryMemoryToEvent(event, event->event.drop.data); + break; + case SDL_EVENT_CLIPBOARD_UPDATE: + SDL_LinkTemporaryMemoryToEvent(event, event->event.clipboard.mime_types); + break; + case SDL2_SYSWMEVENT: + // We need to copy the stack pointer into temporary memory + SDL_TransferSysWMMemoryToEvent(event); + break; + default: + break; + } +} + +// Transfer the event memory from the event to the thread-local event memory list +static void SDL_TransferTemporaryMemoryFromEvent(SDL_EventEntry *event) +{ + SDL_TemporaryMemoryState *state; + SDL_TemporaryMemory *entry, *next; + + if (!event->memory) { + return; + } + + state = SDL_GetTemporaryMemoryState(true); + if (!state) { + return; // this is now a leak, but you probably have bigger problems if malloc failed. + } + + for (entry = event->memory; entry; entry = next) { + next = entry->next; + SDL_LinkTemporaryMemoryEntry(state, entry); + } + event->memory = NULL; +} + +static void *SDL_FreeLater(void *memory) +{ + SDL_TemporaryMemoryState *state; + + if (memory == NULL) { + return NULL; + } + + // Make sure we're not adding this to the list twice + //SDL_assert(!SDL_ClaimTemporaryMemory(memory)); + + state = SDL_GetTemporaryMemoryState(true); + if (!state) { + return memory; // this is now a leak, but you probably have bigger problems if malloc failed. + } + + SDL_TemporaryMemory *entry = (SDL_TemporaryMemory *)SDL_malloc(sizeof(*entry)); + if (!entry) { + return memory; // this is now a leak, but you probably have bigger problems if malloc failed. We could probably pool up and reuse entries, though. + } + + entry->memory = memory; + + SDL_LinkTemporaryMemoryEntry(state, entry); + + return memory; +} + +void *SDL_AllocateTemporaryMemory(size_t size) +{ + return SDL_FreeLater(SDL_malloc(size)); +} + +const char *SDL_CreateTemporaryString(const char *string) +{ + if (string) { + return (const char *)SDL_FreeLater(SDL_strdup(string)); + } + return NULL; +} + +void *SDL_ClaimTemporaryMemory(const void *mem) +{ + SDL_TemporaryMemoryState *state; + + state = SDL_GetTemporaryMemoryState(false); + if (state && mem) { + SDL_TemporaryMemory *entry = SDL_GetTemporaryMemoryEntry(state, mem); + if (entry) { + SDL_UnlinkTemporaryMemoryEntry(state, entry); + SDL_FreeTemporaryMemoryEntry(state, entry, false); + return (void *)mem; + } + } + return NULL; +} + +void SDL_FreeTemporaryMemory(void) +{ + SDL_TemporaryMemoryState *state; + + state = SDL_GetTemporaryMemoryState(false); + if (!state) { + return; + } + + while (state->head) { + SDL_TemporaryMemory *entry = state->head; + + SDL_UnlinkTemporaryMemoryEntry(state, entry); + SDL_FreeTemporaryMemoryEntry(state, entry, true); + } +} + +#ifndef SDL_JOYSTICK_DISABLED + +static bool SDL_update_joysticks = true; + +static void SDLCALL SDL_AutoUpdateJoysticksChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_update_joysticks = SDL_GetStringBoolean(hint, true); +} + +#endif // !SDL_JOYSTICK_DISABLED + +#ifndef SDL_SENSOR_DISABLED + +static bool SDL_update_sensors = true; + +static void SDLCALL SDL_AutoUpdateSensorsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_update_sensors = SDL_GetStringBoolean(hint, true); +} + +#endif // !SDL_SENSOR_DISABLED + +static void SDLCALL SDL_PollSentinelChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_SetEventEnabled(SDL_EVENT_POLL_SENTINEL, SDL_GetStringBoolean(hint, true)); +} + +/** + * Verbosity of logged events as defined in SDL_HINT_EVENT_LOGGING: + * - 0: (default) no logging + * - 1: logging of most events + * - 2: as above, plus mouse, pen, and finger motion + */ +static int SDL_EventLoggingVerbosity = 0; + +static void SDLCALL SDL_EventLoggingChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_EventLoggingVerbosity = (hint && *hint) ? SDL_clamp(SDL_atoi(hint), 0, 3) : 0; +} + +static void SDL_LogEvent(const SDL_Event *event) +{ + static const char *pen_axisnames[] = { "PRESSURE", "XTILT", "YTILT", "DISTANCE", "ROTATION", "SLIDER", "TANGENTIAL_PRESSURE" }; + SDL_COMPILE_TIME_ASSERT(pen_axisnames_array_matches, SDL_arraysize(pen_axisnames) == SDL_PEN_AXIS_COUNT); + + char name[64]; + char details[128]; + + // sensor/mouse/pen/finger motion are spammy, ignore these if they aren't demanded. + if ((SDL_EventLoggingVerbosity < 2) && + ((event->type == SDL_EVENT_MOUSE_MOTION) || + (event->type == SDL_EVENT_FINGER_MOTION) || + (event->type == SDL_EVENT_PEN_AXIS) || + (event->type == SDL_EVENT_PEN_MOTION) || + (event->type == SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION) || + (event->type == SDL_EVENT_GAMEPAD_SENSOR_UPDATE) || + (event->type == SDL_EVENT_SENSOR_UPDATE))) { + return; + } + +// this is to make (void)SDL_snprintf() calls cleaner. +#define uint unsigned int + + name[0] = '\0'; + details[0] = '\0'; + + // !!! FIXME: This code is kinda ugly, sorry. + + if ((event->type >= SDL_EVENT_USER) && (event->type <= SDL_EVENT_LAST)) { + char plusstr[16]; + SDL_strlcpy(name, "SDL_EVENT_USER", sizeof(name)); + if (event->type > SDL_EVENT_USER) { + (void)SDL_snprintf(plusstr, sizeof(plusstr), "+%u", ((uint)event->type) - SDL_EVENT_USER); + } else { + plusstr[0] = '\0'; + } + (void)SDL_snprintf(details, sizeof(details), "%s (timestamp=%u windowid=%u code=%d data1=%p data2=%p)", + plusstr, (uint)event->user.timestamp, (uint)event->user.windowID, + (int)event->user.code, event->user.data1, event->user.data2); + } + + switch (event->type) { +#define SDL_EVENT_CASE(x) \ + case x: \ + SDL_strlcpy(name, #x, sizeof(name)); + SDL_EVENT_CASE(SDL_EVENT_FIRST) + SDL_strlcpy(details, " (THIS IS PROBABLY A BUG!)", sizeof(details)); + break; + SDL_EVENT_CASE(SDL_EVENT_QUIT) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u)", (uint)event->quit.timestamp); + break; + SDL_EVENT_CASE(SDL_EVENT_TERMINATING) + break; + SDL_EVENT_CASE(SDL_EVENT_LOW_MEMORY) + break; + SDL_EVENT_CASE(SDL_EVENT_WILL_ENTER_BACKGROUND) + break; + SDL_EVENT_CASE(SDL_EVENT_DID_ENTER_BACKGROUND) + break; + SDL_EVENT_CASE(SDL_EVENT_WILL_ENTER_FOREGROUND) + break; + SDL_EVENT_CASE(SDL_EVENT_DID_ENTER_FOREGROUND) + break; + SDL_EVENT_CASE(SDL_EVENT_LOCALE_CHANGED) + break; + SDL_EVENT_CASE(SDL_EVENT_SYSTEM_THEME_CHANGED) + break; + SDL_EVENT_CASE(SDL_EVENT_KEYMAP_CHANGED) + break; + SDL_EVENT_CASE(SDL_EVENT_CLIPBOARD_UPDATE) + break; + +#define SDL_RENDEREVENT_CASE(x) \ + case x: \ + SDL_strlcpy(name, #x, sizeof(name)); \ + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u event=%s windowid=%u)", \ + (uint)event->display.timestamp, name, (uint)event->render.windowID); \ + break + SDL_RENDEREVENT_CASE(SDL_EVENT_RENDER_TARGETS_RESET); + SDL_RENDEREVENT_CASE(SDL_EVENT_RENDER_DEVICE_RESET); + SDL_RENDEREVENT_CASE(SDL_EVENT_RENDER_DEVICE_LOST); + +#define SDL_DISPLAYEVENT_CASE(x) \ + case x: \ + SDL_strlcpy(name, #x, sizeof(name)); \ + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u display=%u event=%s data1=%d, data2=%d)", \ + (uint)event->display.timestamp, (uint)event->display.displayID, name, (int)event->display.data1, (int)event->display.data2); \ + break + SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_ORIENTATION); + SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_ADDED); + SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_REMOVED); + SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_MOVED); + SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED); + SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED); + SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED); +#undef SDL_DISPLAYEVENT_CASE + +#define SDL_WINDOWEVENT_CASE(x) \ + case x: \ + SDL_strlcpy(name, #x, sizeof(name)); \ + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u event=%s data1=%d data2=%d)", \ + (uint)event->window.timestamp, (uint)event->window.windowID, name, (int)event->window.data1, (int)event->window.data2); \ + break + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_SHOWN); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_HIDDEN); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_EXPOSED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_MOVED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_RESIZED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_METAL_VIEW_RESIZED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_SAFE_AREA_CHANGED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_MINIMIZED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_MAXIMIZED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_RESTORED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_MOUSE_ENTER); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_MOUSE_LEAVE); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_FOCUS_GAINED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_FOCUS_LOST); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_CLOSE_REQUESTED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_HIT_TEST); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_ICCPROF_CHANGED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_DISPLAY_CHANGED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_OCCLUDED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_ENTER_FULLSCREEN); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_LEAVE_FULLSCREEN); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_DESTROYED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_HDR_STATE_CHANGED); +#undef SDL_WINDOWEVENT_CASE + +#define PRINT_KEYDEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u)", (uint)event->kdevice.timestamp, (uint)event->kdevice.which) + SDL_EVENT_CASE(SDL_EVENT_KEYBOARD_ADDED) + PRINT_KEYDEV_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_KEYBOARD_REMOVED) + PRINT_KEYDEV_EVENT(event); + break; +#undef PRINT_KEYDEV_EVENT + +#define PRINT_KEY_EVENT(event) \ + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u state=%s repeat=%s scancode=%u keycode=%u mod=0x%x)", \ + (uint)event->key.timestamp, (uint)event->key.windowID, (uint)event->key.which, \ + event->key.down ? "pressed" : "released", \ + event->key.repeat ? "true" : "false", \ + (uint)event->key.scancode, \ + (uint)event->key.key, \ + (uint)event->key.mod) + SDL_EVENT_CASE(SDL_EVENT_KEY_DOWN) + PRINT_KEY_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_KEY_UP) + PRINT_KEY_EVENT(event); + break; +#undef PRINT_KEY_EVENT + + SDL_EVENT_CASE(SDL_EVENT_TEXT_EDITING) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u text='%s' start=%d length=%d)", + (uint)event->edit.timestamp, (uint)event->edit.windowID, + event->edit.text, (int)event->edit.start, (int)event->edit.length); + break; + + SDL_EVENT_CASE(SDL_EVENT_TEXT_EDITING_CANDIDATES) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u num_candidates=%d selected_candidate=%d)", + (uint)event->edit_candidates.timestamp, (uint)event->edit_candidates.windowID, + (int)event->edit_candidates.num_candidates, (int)event->edit_candidates.selected_candidate); + break; + + SDL_EVENT_CASE(SDL_EVENT_TEXT_INPUT) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u text='%s')", (uint)event->text.timestamp, (uint)event->text.windowID, event->text.text); + break; + +#define PRINT_MOUSEDEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u)", (uint)event->mdevice.timestamp, (uint)event->mdevice.which) + SDL_EVENT_CASE(SDL_EVENT_MOUSE_ADDED) + PRINT_MOUSEDEV_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_MOUSE_REMOVED) + PRINT_MOUSEDEV_EVENT(event); + break; +#undef PRINT_MOUSEDEV_EVENT + + SDL_EVENT_CASE(SDL_EVENT_MOUSE_MOTION) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u state=%u x=%g y=%g xrel=%g yrel=%g)", + (uint)event->motion.timestamp, (uint)event->motion.windowID, + (uint)event->motion.which, (uint)event->motion.state, + event->motion.x, event->motion.y, + event->motion.xrel, event->motion.yrel); + break; + +#define PRINT_MBUTTON_EVENT(event) \ + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u button=%u state=%s clicks=%u x=%g y=%g)", \ + (uint)event->button.timestamp, (uint)event->button.windowID, \ + (uint)event->button.which, (uint)event->button.button, \ + event->button.down ? "pressed" : "released", \ + (uint)event->button.clicks, event->button.x, event->button.y) + SDL_EVENT_CASE(SDL_EVENT_MOUSE_BUTTON_DOWN) + PRINT_MBUTTON_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_MOUSE_BUTTON_UP) + PRINT_MBUTTON_EVENT(event); + break; +#undef PRINT_MBUTTON_EVENT + + SDL_EVENT_CASE(SDL_EVENT_MOUSE_WHEEL) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u x=%g y=%g direction=%s)", + (uint)event->wheel.timestamp, (uint)event->wheel.windowID, + (uint)event->wheel.which, event->wheel.x, event->wheel.y, + event->wheel.direction == SDL_MOUSEWHEEL_NORMAL ? "normal" : "flipped"); + break; + + SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_AXIS_MOTION) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d axis=%u value=%d)", + (uint)event->jaxis.timestamp, (int)event->jaxis.which, + (uint)event->jaxis.axis, (int)event->jaxis.value); + break; + + SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_BALL_MOTION) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d ball=%u xrel=%d yrel=%d)", + (uint)event->jball.timestamp, (int)event->jball.which, + (uint)event->jball.ball, (int)event->jball.xrel, (int)event->jball.yrel); + break; + + SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_HAT_MOTION) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d hat=%u value=%u)", + (uint)event->jhat.timestamp, (int)event->jhat.which, + (uint)event->jhat.hat, (uint)event->jhat.value); + break; + +#define PRINT_JBUTTON_EVENT(event) \ + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d button=%u state=%s)", \ + (uint)event->jbutton.timestamp, (int)event->jbutton.which, \ + (uint)event->jbutton.button, event->jbutton.down ? "pressed" : "released") + SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_BUTTON_DOWN) + PRINT_JBUTTON_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_BUTTON_UP) + PRINT_JBUTTON_EVENT(event); + break; +#undef PRINT_JBUTTON_EVENT + + SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_BATTERY_UPDATED) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d state=%u percent=%d)", + (uint)event->jbattery.timestamp, (int)event->jbattery.which, + event->jbattery.state, event->jbattery.percent); + break; + +#define PRINT_JOYDEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d)", (uint)event->jdevice.timestamp, (int)event->jdevice.which) + SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_ADDED) + PRINT_JOYDEV_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_REMOVED) + PRINT_JOYDEV_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_UPDATE_COMPLETE) + PRINT_JOYDEV_EVENT(event); + break; +#undef PRINT_JOYDEV_EVENT + + SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_AXIS_MOTION) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d axis=%u value=%d)", + (uint)event->gaxis.timestamp, (int)event->gaxis.which, + (uint)event->gaxis.axis, (int)event->gaxis.value); + break; + +#define PRINT_CBUTTON_EVENT(event) \ + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d button=%u state=%s)", \ + (uint)event->gbutton.timestamp, (int)event->gbutton.which, \ + (uint)event->gbutton.button, event->gbutton.down ? "pressed" : "released") + SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_BUTTON_DOWN) + PRINT_CBUTTON_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_BUTTON_UP) + PRINT_CBUTTON_EVENT(event); + break; +#undef PRINT_CBUTTON_EVENT + +#define PRINT_GAMEPADDEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d)", (uint)event->gdevice.timestamp, (int)event->gdevice.which) + SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_ADDED) + PRINT_GAMEPADDEV_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_REMOVED) + PRINT_GAMEPADDEV_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_REMAPPED) + PRINT_GAMEPADDEV_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_UPDATE_COMPLETE) + PRINT_GAMEPADDEV_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED) + PRINT_GAMEPADDEV_EVENT(event); + break; +#undef PRINT_GAMEPADDEV_EVENT + +#define PRINT_CTOUCHPAD_EVENT(event) \ + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d touchpad=%d finger=%d x=%f y=%f pressure=%f)", \ + (uint)event->gtouchpad.timestamp, (int)event->gtouchpad.which, \ + (int)event->gtouchpad.touchpad, (int)event->gtouchpad.finger, \ + event->gtouchpad.x, event->gtouchpad.y, event->gtouchpad.pressure) + SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN) + PRINT_CTOUCHPAD_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_TOUCHPAD_UP) + PRINT_CTOUCHPAD_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION) + PRINT_CTOUCHPAD_EVENT(event); + break; +#undef PRINT_CTOUCHPAD_EVENT + + SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_SENSOR_UPDATE) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d sensor=%d data[0]=%f data[1]=%f data[2]=%f)", + (uint)event->gsensor.timestamp, (int)event->gsensor.which, (int)event->gsensor.sensor, + event->gsensor.data[0], event->gsensor.data[1], event->gsensor.data[2]); + break; + +#define PRINT_FINGER_EVENT(event) \ + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u touchid=%" SDL_PRIu64 " fingerid=%" SDL_PRIu64 " x=%f y=%f dx=%f dy=%f pressure=%f)", \ + (uint)event->tfinger.timestamp, event->tfinger.touchID, \ + event->tfinger.fingerID, event->tfinger.x, event->tfinger.y, \ + event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure) + SDL_EVENT_CASE(SDL_EVENT_FINGER_DOWN) + PRINT_FINGER_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_FINGER_UP) + PRINT_FINGER_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_FINGER_CANCELED) + PRINT_FINGER_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_FINGER_MOTION) + PRINT_FINGER_EVENT(event); + break; +#undef PRINT_FINGER_EVENT + +#define PRINT_PTOUCH_EVENT(event) \ + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u pen_state=%u x=%g y=%g eraser=%s state=%s)", \ + (uint)event->ptouch.timestamp, (uint)event->ptouch.windowID, (uint)event->ptouch.which, (uint)event->ptouch.pen_state, event->ptouch.x, event->ptouch.y, \ + event->ptouch.eraser ? "yes" : "no", event->ptouch.down ? "down" : "up"); + SDL_EVENT_CASE(SDL_EVENT_PEN_DOWN) + PRINT_PTOUCH_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_PEN_UP) + PRINT_PTOUCH_EVENT(event); + break; +#undef PRINT_PTOUCH_EVENT + +#define PRINT_PPROXIMITY_EVENT(event) \ + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u)", \ + (uint)event->pproximity.timestamp, (uint)event->pproximity.windowID, (uint)event->pproximity.which); + SDL_EVENT_CASE(SDL_EVENT_PEN_PROXIMITY_IN) + PRINT_PPROXIMITY_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_PEN_PROXIMITY_OUT) + PRINT_PPROXIMITY_EVENT(event); + break; +#undef PRINT_PPROXIMITY_EVENT + + SDL_EVENT_CASE(SDL_EVENT_PEN_AXIS) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u pen_state=%u x=%g y=%g axis=%s value=%g)", + (uint)event->paxis.timestamp, (uint)event->paxis.windowID, (uint)event->paxis.which, (uint)event->paxis.pen_state, event->paxis.x, event->paxis.y, + ((((int) event->paxis.axis) >= 0) && (event->paxis.axis < SDL_arraysize(pen_axisnames))) ? pen_axisnames[event->paxis.axis] : "[UNKNOWN]", event->paxis.value); + break; + + SDL_EVENT_CASE(SDL_EVENT_PEN_MOTION) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u pen_state=%u x=%g y=%g)", + (uint)event->pmotion.timestamp, (uint)event->pmotion.windowID, (uint)event->pmotion.which, (uint)event->pmotion.pen_state, event->pmotion.x, event->pmotion.y); + break; + +#define PRINT_PBUTTON_EVENT(event) \ + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u pen_state=%u x=%g y=%g button=%u state=%s)", \ + (uint)event->pbutton.timestamp, (uint)event->pbutton.windowID, (uint)event->pbutton.which, (uint)event->pbutton.pen_state, event->pbutton.x, event->pbutton.y, \ + (uint)event->pbutton.button, event->pbutton.down ? "down" : "up"); + SDL_EVENT_CASE(SDL_EVENT_PEN_BUTTON_DOWN) + PRINT_PBUTTON_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_PEN_BUTTON_UP) + PRINT_PBUTTON_EVENT(event); + break; +#undef PRINT_PBUTTON_EVENT + +#define PRINT_DROP_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (data='%s' timestamp=%u windowid=%u x=%f y=%f)", event->drop.data, (uint)event->drop.timestamp, (uint)event->drop.windowID, event->drop.x, event->drop.y) + SDL_EVENT_CASE(SDL_EVENT_DROP_FILE) + PRINT_DROP_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_DROP_TEXT) + PRINT_DROP_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_DROP_BEGIN) + PRINT_DROP_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_DROP_COMPLETE) + PRINT_DROP_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_DROP_POSITION) + PRINT_DROP_EVENT(event); + break; +#undef PRINT_DROP_EVENT + +#define PRINT_AUDIODEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u recording=%s)", (uint)event->adevice.timestamp, (uint)event->adevice.which, event->adevice.recording ? "true" : "false") + SDL_EVENT_CASE(SDL_EVENT_AUDIO_DEVICE_ADDED) + PRINT_AUDIODEV_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_AUDIO_DEVICE_REMOVED) + PRINT_AUDIODEV_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED) + PRINT_AUDIODEV_EVENT(event); + break; +#undef PRINT_AUDIODEV_EVENT + +#define PRINT_CAMERADEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u)", (uint)event->cdevice.timestamp, (uint)event->cdevice.which) + SDL_EVENT_CASE(SDL_EVENT_CAMERA_DEVICE_ADDED) + PRINT_CAMERADEV_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_CAMERA_DEVICE_REMOVED) + PRINT_CAMERADEV_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_CAMERA_DEVICE_APPROVED) + PRINT_CAMERADEV_EVENT(event); + break; + SDL_EVENT_CASE(SDL_EVENT_CAMERA_DEVICE_DENIED) + PRINT_CAMERADEV_EVENT(event); + break; +#undef PRINT_CAMERADEV_EVENT + + SDL_EVENT_CASE(SDL_EVENT_SENSOR_UPDATE) + (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d data[0]=%f data[1]=%f data[2]=%f data[3]=%f data[4]=%f data[5]=%f)", + (uint)event->sensor.timestamp, (int)event->sensor.which, + event->sensor.data[0], event->sensor.data[1], event->sensor.data[2], + event->sensor.data[3], event->sensor.data[4], event->sensor.data[5]); + break; + +#undef SDL_EVENT_CASE + + case SDL_EVENT_POLL_SENTINEL: + // No logging necessary for this one + break; + + default: + if (!name[0]) { + if (event->type >= SDL_EVENT_USER) { + SDL_strlcpy(name, "USER", sizeof(name)); + } else { + SDL_strlcpy(name, "UNKNOWN", sizeof(name)); + } + (void)SDL_snprintf(details, sizeof(details), " 0x%x", (uint)event->type); + } + break; + } + + if (name[0]) { + SDL_Log("SDL EVENT: %s%s", name, details); + } + +#undef uint +} + +void SDL_StopEventLoop(void) +{ + const char *report = SDL_GetHint("SDL_EVENT_QUEUE_STATISTICS"); + int i; + SDL_EventEntry *entry; + + SDL_LockMutex(SDL_EventQ.lock); + + SDL_EventQ.active = false; + + if (report && SDL_atoi(report)) { + SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d", + SDL_EventQ.max_events_seen); + } + + // Clean out EventQ + for (entry = SDL_EventQ.head; entry;) { + SDL_EventEntry *next = entry->next; + SDL_TransferTemporaryMemoryFromEvent(entry); + SDL_free(entry); + entry = next; + } + for (entry = SDL_EventQ.free; entry;) { + SDL_EventEntry *next = entry->next; + SDL_free(entry); + entry = next; + } + + SDL_SetAtomicInt(&SDL_EventQ.count, 0); + SDL_EventQ.max_events_seen = 0; + SDL_EventQ.head = NULL; + SDL_EventQ.tail = NULL; + SDL_EventQ.free = NULL; + SDL_SetAtomicInt(&SDL_sentinel_pending, 0); + + // Clear disabled event state + for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) { + SDL_free(SDL_disabled_events[i]); + SDL_disabled_events[i] = NULL; + } + + SDL_QuitEventWatchList(&SDL_event_watchers); + SDL_QuitWindowEventWatch(); + + SDL_Mutex *lock = NULL; + if (SDL_EventQ.lock) { + lock = SDL_EventQ.lock; + SDL_EventQ.lock = NULL; + } + + SDL_UnlockMutex(lock); + + if (lock) { + SDL_DestroyMutex(lock); + } +} + +// This function (and associated calls) may be called more than once +bool SDL_StartEventLoop(void) +{ + /* We'll leave the event queue alone, since we might have gotten + some important events at launch (like SDL_EVENT_DROP_FILE) + + FIXME: Does this introduce any other bugs with events at startup? + */ + + // Create the lock and set ourselves active +#ifndef SDL_THREADS_DISABLED + if (!SDL_EventQ.lock) { + SDL_EventQ.lock = SDL_CreateMutex(); + if (SDL_EventQ.lock == NULL) { + return false; + } + } + SDL_LockMutex(SDL_EventQ.lock); + + if (!SDL_InitEventWatchList(&SDL_event_watchers)) { + SDL_UnlockMutex(SDL_EventQ.lock); + return false; + } +#endif // !SDL_THREADS_DISABLED + + SDL_InitWindowEventWatch(); + + SDL_EventQ.active = true; + +#ifndef SDL_THREADS_DISABLED + SDL_UnlockMutex(SDL_EventQ.lock); +#endif + return true; +} + +// Add an event to the event queue -- called with the queue locked +static int SDL_AddEvent(SDL_Event *event) +{ + SDL_EventEntry *entry; + const int initial_count = SDL_GetAtomicInt(&SDL_EventQ.count); + int final_count; + + if (initial_count >= SDL_MAX_QUEUED_EVENTS) { + SDL_SetError("Event queue is full (%d events)", initial_count); + return 0; + } + + if (SDL_EventQ.free == NULL) { + entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry)); + if (entry == NULL) { + return 0; + } + } else { + entry = SDL_EventQ.free; + SDL_EventQ.free = entry->next; + } + + if (SDL_EventLoggingVerbosity > 0) { + SDL_LogEvent(event); + } + + SDL_copyp(&entry->event, event); + if (event->type == SDL_EVENT_POLL_SENTINEL) { + SDL_AddAtomicInt(&SDL_sentinel_pending, 1); + } + entry->memory = NULL; + SDL_TransferTemporaryMemoryToEvent(entry); + + if (SDL_EventQ.tail) { + SDL_EventQ.tail->next = entry; + entry->prev = SDL_EventQ.tail; + SDL_EventQ.tail = entry; + entry->next = NULL; + } else { + SDL_assert(!SDL_EventQ.head); + SDL_EventQ.head = entry; + SDL_EventQ.tail = entry; + entry->prev = NULL; + entry->next = NULL; + } + + final_count = SDL_AddAtomicInt(&SDL_EventQ.count, 1) + 1; + if (final_count > SDL_EventQ.max_events_seen) { + SDL_EventQ.max_events_seen = final_count; + } + + ++SDL_last_event_id; + + return 1; +} + +// Remove an event from the queue -- called with the queue locked +static void SDL_CutEvent(SDL_EventEntry *entry) +{ + SDL_TransferTemporaryMemoryFromEvent(entry); + + if (entry->prev) { + entry->prev->next = entry->next; + } + if (entry->next) { + entry->next->prev = entry->prev; + } + + if (entry == SDL_EventQ.head) { + SDL_assert(entry->prev == NULL); + SDL_EventQ.head = entry->next; + } + if (entry == SDL_EventQ.tail) { + SDL_assert(entry->next == NULL); + SDL_EventQ.tail = entry->prev; + } + + if (entry->event.type == SDL_EVENT_POLL_SENTINEL) { + SDL_AddAtomicInt(&SDL_sentinel_pending, -1); + } + + entry->next = SDL_EventQ.free; + SDL_EventQ.free = entry; + SDL_assert(SDL_GetAtomicInt(&SDL_EventQ.count) > 0); + SDL_AddAtomicInt(&SDL_EventQ.count, -1); +} + +static void SDL_SendWakeupEvent(void) +{ +#ifdef SDL_PLATFORM_ANDROID + Android_SendLifecycleEvent(SDL_ANDROID_LIFECYCLE_WAKE); +#else + SDL_VideoDevice *_this = SDL_GetVideoDevice(); + if (_this == NULL || !_this->SendWakeupEvent) { + return; + } + + SDL_LockMutex(_this->wakeup_lock); + { + if (_this->wakeup_window) { + _this->SendWakeupEvent(_this, _this->wakeup_window); + + // No more wakeup events needed until we enter a new wait + _this->wakeup_window = NULL; + } + } + SDL_UnlockMutex(_this->wakeup_lock); +#endif +} + +// Lock the event queue, take a peep at it, and unlock it +static int SDL_PeepEventsInternal(SDL_Event *events, int numevents, SDL_EventAction action, + Uint32 minType, Uint32 maxType, bool include_sentinel) +{ + int i, used, sentinels_expected = 0; + + // Lock the event queue + used = 0; + + SDL_LockMutex(SDL_EventQ.lock); + { + // Don't look after we've quit + if (!SDL_EventQ.active) { + // We get a few spurious events at shutdown, so don't warn then + if (action == SDL_GETEVENT) { + SDL_SetError("The event system has been shut down"); + } + SDL_UnlockMutex(SDL_EventQ.lock); + return -1; + } + if (action == SDL_ADDEVENT) { + if (!events) { + SDL_UnlockMutex(SDL_EventQ.lock); + return SDL_InvalidParamError("events"); + } + for (i = 0; i < numevents; ++i) { + used += SDL_AddEvent(&events[i]); + } + } else { + SDL_EventEntry *entry, *next; + Uint32 type; + + for (entry = SDL_EventQ.head; entry && (events == NULL || used < numevents); entry = next) { + next = entry->next; + type = entry->event.type; + if (minType <= type && type <= maxType) { + if (events) { + SDL_copyp(&events[used], &entry->event); + + if (action == SDL_GETEVENT) { + SDL_CutEvent(entry); + } + } + if (type == SDL_EVENT_POLL_SENTINEL) { + // Special handling for the sentinel event + if (!include_sentinel) { + // Skip it, we don't want to include it + continue; + } + if (events == NULL || action != SDL_GETEVENT) { + ++sentinels_expected; + } + if (SDL_GetAtomicInt(&SDL_sentinel_pending) > sentinels_expected) { + // Skip it, there's another one pending + continue; + } + } + ++used; + } + } + } + } + SDL_UnlockMutex(SDL_EventQ.lock); + + if (used > 0 && action == SDL_ADDEVENT) { + SDL_SendWakeupEvent(); + } + + return used; +} +int SDL_PeepEvents(SDL_Event *events, int numevents, SDL_EventAction action, + Uint32 minType, Uint32 maxType) +{ + return SDL_PeepEventsInternal(events, numevents, action, minType, maxType, false); +} + +bool SDL_HasEvent(Uint32 type) +{ + return SDL_HasEvents(type, type); +} + +bool SDL_HasEvents(Uint32 minType, Uint32 maxType) +{ + bool found = false; + + SDL_LockMutex(SDL_EventQ.lock); + { + if (SDL_EventQ.active) { + for (SDL_EventEntry *entry = SDL_EventQ.head; entry; entry = entry->next) { + const Uint32 type = entry->event.type; + if (minType <= type && type <= maxType) { + found = true; + break; + } + } + } + } + SDL_UnlockMutex(SDL_EventQ.lock); + + return found; +} + +void SDL_FlushEvent(Uint32 type) +{ + SDL_FlushEvents(type, type); +} + +void SDL_FlushEvents(Uint32 minType, Uint32 maxType) +{ + SDL_EventEntry *entry, *next; + Uint32 type; + + // Make sure the events are current +#if 0 + /* Actually, we can't do this since we might be flushing while processing + a resize event, and calling this might trigger further resize events. + */ + SDL_PumpEvents(); +#endif + + // Lock the event queue + SDL_LockMutex(SDL_EventQ.lock); + { + // Don't look after we've quit + if (!SDL_EventQ.active) { + SDL_UnlockMutex(SDL_EventQ.lock); + return; + } + for (entry = SDL_EventQ.head; entry; entry = next) { + next = entry->next; + type = entry->event.type; + if (minType <= type && type <= maxType) { + SDL_CutEvent(entry); + } + } + } + SDL_UnlockMutex(SDL_EventQ.lock); +} + +typedef enum +{ + SDL_MAIN_CALLBACK_WAITING, + SDL_MAIN_CALLBACK_COMPLETE, + SDL_MAIN_CALLBACK_CANCELED, +} SDL_MainThreadCallbackState; + +typedef struct SDL_MainThreadCallbackEntry +{ + SDL_MainThreadCallback callback; + void *userdata; + SDL_AtomicInt state; + SDL_Semaphore *semaphore; + struct SDL_MainThreadCallbackEntry *next; +} SDL_MainThreadCallbackEntry; + +static SDL_Mutex *SDL_main_callbacks_lock; +static SDL_MainThreadCallbackEntry *SDL_main_callbacks_head; +static SDL_MainThreadCallbackEntry *SDL_main_callbacks_tail; + +static SDL_MainThreadCallbackEntry *SDL_CreateMainThreadCallback(SDL_MainThreadCallback callback, void *userdata, bool wait_complete) +{ + SDL_MainThreadCallbackEntry *entry = (SDL_MainThreadCallbackEntry *)SDL_malloc(sizeof(*entry)); + if (!entry) { + return NULL; + } + + entry->callback = callback; + entry->userdata = userdata; + SDL_SetAtomicInt(&entry->state, SDL_MAIN_CALLBACK_WAITING); + if (wait_complete) { + entry->semaphore = SDL_CreateSemaphore(0); + if (!entry->semaphore) { + SDL_free(entry); + return NULL; + } + } else { + entry->semaphore = NULL; + } + entry->next = NULL; + + return entry; +} + +static void SDL_DestroyMainThreadCallback(SDL_MainThreadCallbackEntry *entry) +{ + if (entry->semaphore) { + SDL_DestroySemaphore(entry->semaphore); + } + SDL_free(entry); +} + +static void SDL_InitMainThreadCallbacks(void) +{ + SDL_main_callbacks_lock = SDL_CreateMutex(); + SDL_assert(SDL_main_callbacks_head == NULL && + SDL_main_callbacks_tail == NULL); +} + +static void SDL_QuitMainThreadCallbacks(void) +{ + SDL_MainThreadCallbackEntry *entry; + + SDL_LockMutex(SDL_main_callbacks_lock); + { + entry = SDL_main_callbacks_head; + SDL_main_callbacks_head = NULL; + SDL_main_callbacks_tail = NULL; + } + SDL_UnlockMutex(SDL_main_callbacks_lock); + + while (entry) { + SDL_MainThreadCallbackEntry *next = entry->next; + + if (entry->semaphore) { + // Let the waiting thread know this is canceled + SDL_SetAtomicInt(&entry->state, SDL_MAIN_CALLBACK_CANCELED); + SDL_SignalSemaphore(entry->semaphore); + } else { + // Nobody's waiting for this, clean it up + SDL_DestroyMainThreadCallback(entry); + } + entry = next; + } + + SDL_DestroyMutex(SDL_main_callbacks_lock); + SDL_main_callbacks_lock = NULL; +} + +static void SDL_RunMainThreadCallbacks(void) +{ + SDL_MainThreadCallbackEntry *entry; + + SDL_LockMutex(SDL_main_callbacks_lock); + { + entry = SDL_main_callbacks_head; + SDL_main_callbacks_head = NULL; + SDL_main_callbacks_tail = NULL; + } + SDL_UnlockMutex(SDL_main_callbacks_lock); + + while (entry) { + SDL_MainThreadCallbackEntry *next = entry->next; + + entry->callback(entry->userdata); + + if (entry->semaphore) { + // Let the waiting thread know this is done + SDL_SetAtomicInt(&entry->state, SDL_MAIN_CALLBACK_COMPLETE); + SDL_SignalSemaphore(entry->semaphore); + } else { + // Nobody's waiting for this, clean it up + SDL_DestroyMainThreadCallback(entry); + } + entry = next; + } +} + +bool SDL_RunOnMainThread(SDL_MainThreadCallback callback, void *userdata, bool wait_complete) +{ + if (SDL_IsMainThread() || !SDL_WasInit(SDL_INIT_EVENTS)) { + // No need to queue the callback + callback(userdata); + return true; + } + + SDL_MainThreadCallbackEntry *entry = SDL_CreateMainThreadCallback(callback, userdata, wait_complete); + if (!entry) { + return false; + } + + SDL_LockMutex(SDL_main_callbacks_lock); + { + if (SDL_main_callbacks_tail) { + SDL_main_callbacks_tail->next = entry; + SDL_main_callbacks_tail = entry; + } else { + SDL_main_callbacks_head = entry; + SDL_main_callbacks_tail = entry; + } + } + SDL_UnlockMutex(SDL_main_callbacks_lock); + + // If the main thread is waiting for events, wake it up + SDL_SendWakeupEvent(); + + if (!wait_complete) { + // Queued for execution, wait not requested + return true; + } + + // Maximum wait of 30 seconds to prevent deadlocking forever + const Sint32 MAX_CALLBACK_WAIT = 30 * 1000; + SDL_WaitSemaphoreTimeout(entry->semaphore, MAX_CALLBACK_WAIT); + + switch (SDL_GetAtomicInt(&entry->state)) { + case SDL_MAIN_CALLBACK_COMPLETE: + // Execution complete! + SDL_DestroyMainThreadCallback(entry); + return true; + + case SDL_MAIN_CALLBACK_CANCELED: + // The callback was canceled on the main thread + SDL_DestroyMainThreadCallback(entry); + return SDL_SetError("Callback canceled"); + + default: + // Probably hit a deadlock in the callback + // We can't destroy the entry as the semaphore will be signaled + // if it ever comes back, just leak it here. + return SDL_SetError("Callback timed out"); + } +} + +void SDL_PumpEventMaintenance(void) +{ +#ifndef SDL_AUDIO_DISABLED + SDL_UpdateAudio(); +#endif + +#ifndef SDL_CAMERA_DISABLED + SDL_UpdateCamera(); +#endif + +#ifndef SDL_SENSOR_DISABLED + // Check for sensor state change + if (SDL_update_sensors) { + SDL_UpdateSensors(); + } +#endif + +#ifndef SDL_JOYSTICK_DISABLED + // Check for joystick state change + if (SDL_update_joysticks) { + SDL_UpdateJoysticks(); + } +#endif + + SDL_UpdateTrays(); + + SDL_SendPendingSignalEvents(); // in case we had a signal handler fire, etc. +} + +// Run the system dependent event loops +static void SDL_PumpEventsInternal(bool push_sentinel) +{ + // Free any temporary memory from old events + SDL_FreeTemporaryMemory(); + + // Release any keys held down from last frame + SDL_ReleaseAutoReleaseKeys(); + + // Run any pending main thread callbacks + SDL_RunMainThreadCallbacks(); + +#ifdef SDL_PLATFORM_ANDROID + // Android event processing is independent of the video subsystem + Android_PumpEvents(0); +#else + // Get events from the video subsystem + SDL_VideoDevice *_this = SDL_GetVideoDevice(); + if (_this) { + _this->PumpEvents(_this); + } +#endif + + SDL_PumpEventMaintenance(); + + if (push_sentinel && SDL_EventEnabled(SDL_EVENT_POLL_SENTINEL)) { + SDL_Event sentinel; + + // Make sure we don't already have a sentinel in the queue, and add one to the end + if (SDL_GetAtomicInt(&SDL_sentinel_pending) > 0) { + SDL_PeepEventsInternal(&sentinel, 1, SDL_GETEVENT, SDL_EVENT_POLL_SENTINEL, SDL_EVENT_POLL_SENTINEL, true); + } + + sentinel.type = SDL_EVENT_POLL_SENTINEL; + sentinel.common.timestamp = 0; + SDL_PushEvent(&sentinel); + } +} + +void SDL_PumpEvents(void) +{ + SDL_PumpEventsInternal(false); +} + +// Public functions + +bool SDL_PollEvent(SDL_Event *event) +{ + return SDL_WaitEventTimeoutNS(event, 0); +} + +#ifndef SDL_PLATFORM_ANDROID + +static Sint64 SDL_events_get_polling_interval(void) +{ + Sint64 poll_intervalNS = SDL_MAX_SINT64; + +#ifndef SDL_JOYSTICK_DISABLED + if (SDL_WasInit(SDL_INIT_JOYSTICK) && SDL_update_joysticks) { + if (SDL_JoysticksOpened()) { + // If we have joysticks open, we need to poll rapidly for events + poll_intervalNS = SDL_min(poll_intervalNS, EVENT_POLL_INTERVAL_NS); + } else { + // If not, just poll every few seconds to enumerate new joysticks + poll_intervalNS = SDL_min(poll_intervalNS, ENUMERATION_POLL_INTERVAL_NS); + } + } +#endif + +#ifndef SDL_SENSOR_DISABLED + if (SDL_WasInit(SDL_INIT_SENSOR) && SDL_update_sensors && SDL_SensorsOpened()) { + // If we have sensors open, we need to poll rapidly for events + poll_intervalNS = SDL_min(poll_intervalNS, EVENT_POLL_INTERVAL_NS); + } +#endif + + return poll_intervalNS; +} + +static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeup_window, SDL_Event *event, Uint64 start, Sint64 timeoutNS) +{ + Sint64 loop_timeoutNS = timeoutNS; + Sint64 poll_intervalNS = SDL_events_get_polling_interval(); + + for (;;) { + int status; + /* Pump events on entry and each time we wake to ensure: + a) All pending events are batch processed after waking up from a wait + b) Waiting can be completely skipped if events are already available to be pumped + c) Periodic processing that takes place in some platform PumpEvents() functions happens + d) Signals received in WaitEventTimeout() are turned into SDL events + */ + SDL_PumpEventsInternal(true); + + SDL_LockMutex(_this->wakeup_lock); + { + status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST); + // If status == 0 we are going to block so wakeup will be needed. + if (status == 0) { + _this->wakeup_window = wakeup_window; + } else { + _this->wakeup_window = NULL; + } + } + SDL_UnlockMutex(_this->wakeup_lock); + + if (status < 0) { + // Got an error: return + break; + } + if (status > 0) { + // There is an event, we can return. + return 1; + } + // No events found in the queue, call WaitEventTimeout to wait for an event. + if (timeoutNS > 0) { + Sint64 elapsed = SDL_GetTicksNS() - start; + if (elapsed >= timeoutNS) { + // Set wakeup_window to NULL without holding the lock. + _this->wakeup_window = NULL; + return 0; + } + loop_timeoutNS = (timeoutNS - elapsed); + } + // Adjust the timeout for any polling requirements we currently have. + if (poll_intervalNS != SDL_MAX_SINT64) { + if (loop_timeoutNS >= 0) { + loop_timeoutNS = SDL_min(loop_timeoutNS, poll_intervalNS); + } else { + loop_timeoutNS = poll_intervalNS; + } + } + status = _this->WaitEventTimeout(_this, loop_timeoutNS); + // Set wakeup_window to NULL without holding the lock. + _this->wakeup_window = NULL; + if (status == 0 && poll_intervalNS != SDL_MAX_SINT64 && loop_timeoutNS == poll_intervalNS) { + // We may have woken up to poll. Try again + continue; + } else if (status <= 0) { + // There is either an error or the timeout is elapsed: return + return status; + } + /* An event was found and pumped into the SDL events queue. Continue the loop + to let SDL_PeepEvents pick it up .*/ + } + return 0; +} + +static SDL_Window *SDL_find_active_window(SDL_VideoDevice *_this) +{ + SDL_Window *window; + for (window = _this->windows; window; window = window->next) { + if (!window->is_destroying) { + return window; + } + } + return NULL; +} + +#endif // !SDL_PLATFORM_ANDROID + +bool SDL_WaitEvent(SDL_Event *event) +{ + return SDL_WaitEventTimeoutNS(event, -1); +} + +bool SDL_WaitEventTimeout(SDL_Event *event, Sint32 timeoutMS) +{ + Sint64 timeoutNS; + + if (timeoutMS > 0) { + timeoutNS = SDL_MS_TO_NS(timeoutMS); + } else { + timeoutNS = timeoutMS; + } + return SDL_WaitEventTimeoutNS(event, timeoutNS); +} + +bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS) +{ + Uint64 start, expiration; + bool include_sentinel = (timeoutNS == 0); + int result; + + if (timeoutNS > 0) { + start = SDL_GetTicksNS(); + expiration = start + timeoutNS; + } else { + start = 0; + expiration = 0; + } + + // If there isn't a poll sentinel event pending, pump events and add one + if (SDL_GetAtomicInt(&SDL_sentinel_pending) == 0) { + SDL_PumpEventsInternal(true); + } + + // First check for existing events + result = SDL_PeepEventsInternal(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST, include_sentinel); + if (result < 0) { + return false; + } + if (include_sentinel) { + if (event) { + if (event->type == SDL_EVENT_POLL_SENTINEL) { + // Reached the end of a poll cycle, and not willing to wait + return false; + } + } else { + // Need to peek the next event to check for sentinel + SDL_Event dummy; + + if (SDL_PeepEventsInternal(&dummy, 1, SDL_PEEKEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST, true) && + dummy.type == SDL_EVENT_POLL_SENTINEL) { + SDL_PeepEventsInternal(&dummy, 1, SDL_GETEVENT, SDL_EVENT_POLL_SENTINEL, SDL_EVENT_POLL_SENTINEL, true); + // Reached the end of a poll cycle, and not willing to wait + return false; + } + } + } + if (result == 0) { + if (timeoutNS == 0) { + // No events available, and not willing to wait + return false; + } + } else { + // Has existing events + return true; + } + // We should have completely handled timeoutNS == 0 above + SDL_assert(timeoutNS != 0); + +#ifdef SDL_PLATFORM_ANDROID + for (;;) { + if (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) > 0) { + return true; + } + + Uint64 delay = -1; + if (timeoutNS > 0) { + Uint64 now = SDL_GetTicksNS(); + if (now >= expiration) { + // Timeout expired and no events + return false; + } + delay = (expiration - now); + } + Android_PumpEvents(delay); + } +#else + SDL_VideoDevice *_this = SDL_GetVideoDevice(); + if (_this && _this->WaitEventTimeout && _this->SendWakeupEvent) { + // Look if a shown window is available to send the wakeup event. + SDL_Window *wakeup_window = SDL_find_active_window(_this); + if (wakeup_window) { + result = SDL_WaitEventTimeout_Device(_this, wakeup_window, event, start, timeoutNS); + if (result > 0) { + return true; + } else if (result == 0) { + return false; + } else { + /* There may be implementation-defined conditions where the backend cannot + * reliably wait for the next event. If that happens, fall back to polling. + */ + } + } + } + + for (;;) { + SDL_PumpEventsInternal(true); + + if (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) > 0) { + return true; + } + + Uint64 delay = EVENT_POLL_INTERVAL_NS; + if (timeoutNS > 0) { + Uint64 now = SDL_GetTicksNS(); + if (now >= expiration) { + // Timeout expired and no events + return false; + } + delay = SDL_min((expiration - now), delay); + } + SDL_DelayNS(delay); + } +#endif // SDL_PLATFORM_ANDROID +} + +static bool SDL_CallEventWatchers(SDL_Event *event) +{ + if (event->common.type == SDL_EVENT_POLL_SENTINEL) { + return true; + } + + return SDL_DispatchEventWatchList(&SDL_event_watchers, event); +} + +bool SDL_PushEvent(SDL_Event *event) +{ + if (!event->common.timestamp) { + event->common.timestamp = SDL_GetTicksNS(); + } + + if (!SDL_CallEventWatchers(event)) { + SDL_ClearError(); + return false; + } + + if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) { + return false; + } + + return true; +} + +void SDL_SetEventFilter(SDL_EventFilter filter, void *userdata) +{ + SDL_EventEntry *event, *next; + SDL_LockMutex(SDL_event_watchers.lock); + { + // Set filter and discard pending events + SDL_event_watchers.filter.callback = filter; + SDL_event_watchers.filter.userdata = userdata; + if (filter) { + // Cut all events not accepted by the filter + SDL_LockMutex(SDL_EventQ.lock); + { + for (event = SDL_EventQ.head; event; event = next) { + next = event->next; + if (!filter(userdata, &event->event)) { + SDL_CutEvent(event); + } + } + } + SDL_UnlockMutex(SDL_EventQ.lock); + } + } + SDL_UnlockMutex(SDL_event_watchers.lock); +} + +bool SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata) +{ + SDL_EventWatcher event_ok; + + SDL_LockMutex(SDL_event_watchers.lock); + { + event_ok = SDL_event_watchers.filter; + } + SDL_UnlockMutex(SDL_event_watchers.lock); + + if (filter) { + *filter = event_ok.callback; + } + if (userdata) { + *userdata = event_ok.userdata; + } + return event_ok.callback ? true : false; +} + +bool SDL_AddEventWatch(SDL_EventFilter filter, void *userdata) +{ + return SDL_AddEventWatchList(&SDL_event_watchers, filter, userdata); +} + +void SDL_RemoveEventWatch(SDL_EventFilter filter, void *userdata) +{ + SDL_RemoveEventWatchList(&SDL_event_watchers, filter, userdata); +} + +void SDL_FilterEvents(SDL_EventFilter filter, void *userdata) +{ + SDL_LockMutex(SDL_EventQ.lock); + { + SDL_EventEntry *entry, *next; + for (entry = SDL_EventQ.head; entry; entry = next) { + next = entry->next; + if (!filter(userdata, &entry->event)) { + SDL_CutEvent(entry); + } + } + } + SDL_UnlockMutex(SDL_EventQ.lock); +} + +void SDL_SetEventEnabled(Uint32 type, bool enabled) +{ + bool current_state; + Uint8 hi = ((type >> 8) & 0xff); + Uint8 lo = (type & 0xff); + + if (SDL_disabled_events[hi] && + (SDL_disabled_events[hi]->bits[lo / 32] & (1 << (lo & 31)))) { + current_state = false; + } else { + current_state = true; + } + + if ((enabled != false) != current_state) { + if (enabled) { + SDL_assert(SDL_disabled_events[hi] != NULL); + SDL_disabled_events[hi]->bits[lo / 32] &= ~(1 << (lo & 31)); + + // Gamepad events depend on joystick events + switch (type) { + case SDL_EVENT_GAMEPAD_ADDED: + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_ADDED, true); + break; + case SDL_EVENT_GAMEPAD_REMOVED: + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_REMOVED, true); + break; + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_AXIS_MOTION, true); + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_HAT_MOTION, true); + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_BUTTON_DOWN, true); + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_BUTTON_UP, true); + break; + case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE: + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_UPDATE_COMPLETE, true); + break; + default: + break; + } + } else { + // Disable this event type and discard pending events + if (!SDL_disabled_events[hi]) { + SDL_disabled_events[hi] = (SDL_DisabledEventBlock *)SDL_calloc(1, sizeof(SDL_DisabledEventBlock)); + } + // Out of memory, nothing we can do... + if (SDL_disabled_events[hi]) { + SDL_disabled_events[hi]->bits[lo / 32] |= (1 << (lo & 31)); + SDL_FlushEvent(type); + } + } + + /* turn off drag'n'drop support if we've disabled the events. + This might change some UI details at the OS level. */ + if (type == SDL_EVENT_DROP_FILE || type == SDL_EVENT_DROP_TEXT) { + SDL_ToggleDragAndDropSupport(); + } + } +} + +bool SDL_EventEnabled(Uint32 type) +{ + Uint8 hi = ((type >> 8) & 0xff); + Uint8 lo = (type & 0xff); + + if (SDL_disabled_events[hi] && + (SDL_disabled_events[hi]->bits[lo / 32] & (1 << (lo & 31)))) { + return false; + } else { + return true; + } +} + +Uint32 SDL_RegisterEvents(int numevents) +{ + Uint32 event_base = 0; + + if (numevents > 0) { + int value = SDL_AddAtomicInt(&SDL_userevents, numevents); + if (value >= 0 && value <= (SDL_EVENT_LAST - SDL_EVENT_USER)) { + event_base = (Uint32)(SDL_EVENT_USER + value); + } + } + return event_base; +} + +void SDL_SendAppEvent(SDL_EventType eventType) +{ + if (SDL_EventEnabled(eventType)) { + SDL_Event event; + event.type = eventType; + event.common.timestamp = 0; + + switch (eventType) { + case SDL_EVENT_TERMINATING: + case SDL_EVENT_LOW_MEMORY: + case SDL_EVENT_WILL_ENTER_BACKGROUND: + case SDL_EVENT_DID_ENTER_BACKGROUND: + case SDL_EVENT_WILL_ENTER_FOREGROUND: + case SDL_EVENT_DID_ENTER_FOREGROUND: + // We won't actually queue this event, it needs to be handled in this call stack by an event watcher + if (SDL_EventLoggingVerbosity > 0) { + SDL_LogEvent(&event); + } + SDL_CallEventWatchers(&event); + break; + default: + SDL_PushEvent(&event); + break; + } + } +} + +void SDL_SendKeymapChangedEvent(void) +{ + SDL_SendAppEvent(SDL_EVENT_KEYMAP_CHANGED); +} + +void SDL_SendLocaleChangedEvent(void) +{ + SDL_SendAppEvent(SDL_EVENT_LOCALE_CHANGED); +} + +void SDL_SendSystemThemeChangedEvent(void) +{ + SDL_SendAppEvent(SDL_EVENT_SYSTEM_THEME_CHANGED); +} + +bool SDL_InitEvents(void) +{ +#ifdef SDL_PLATFORM_ANDROID + Android_InitEvents(); +#endif +#ifndef SDL_JOYSTICK_DISABLED + SDL_AddHintCallback(SDL_HINT_AUTO_UPDATE_JOYSTICKS, SDL_AutoUpdateJoysticksChanged, NULL); +#endif +#ifndef SDL_SENSOR_DISABLED + SDL_AddHintCallback(SDL_HINT_AUTO_UPDATE_SENSORS, SDL_AutoUpdateSensorsChanged, NULL); +#endif + SDL_AddHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL); + SDL_AddHintCallback(SDL_HINT_POLL_SENTINEL, SDL_PollSentinelChanged, NULL); + SDL_InitMainThreadCallbacks(); + if (!SDL_StartEventLoop()) { + SDL_RemoveHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL); + return false; + } + + SDL_InitQuit(); + + return true; +} + +void SDL_QuitEvents(void) +{ + SDL_QuitQuit(); + SDL_StopEventLoop(); + SDL_QuitMainThreadCallbacks(); + SDL_RemoveHintCallback(SDL_HINT_POLL_SENTINEL, SDL_PollSentinelChanged, NULL); + SDL_RemoveHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL); +#ifndef SDL_JOYSTICK_DISABLED + SDL_RemoveHintCallback(SDL_HINT_AUTO_UPDATE_JOYSTICKS, SDL_AutoUpdateJoysticksChanged, NULL); +#endif +#ifndef SDL_SENSOR_DISABLED + SDL_RemoveHintCallback(SDL_HINT_AUTO_UPDATE_SENSORS, SDL_AutoUpdateSensorsChanged, NULL); +#endif +#ifdef SDL_PLATFORM_ANDROID + Android_QuitEvents(); +#endif +} diff --git a/contrib/SDL-3.2.8/src/events/SDL_events_c.h b/contrib/SDL-3.2.8/src/events/SDL_events_c.h new file mode 100644 index 0000000..e56ac47 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_events_c.h @@ -0,0 +1,66 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_events_c_h_ +#define SDL_events_c_h_ + +#include "SDL_internal.h" + +// Useful functions and variables from SDL_events.c +#include "../video/SDL_sysvideo.h" + +#include "SDL_clipboardevents_c.h" +#include "SDL_displayevents_c.h" +#include "SDL_dropevents_c.h" +#include "SDL_keyboard_c.h" +#include "SDL_mouse_c.h" +#include "SDL_touch_c.h" +#include "SDL_pen_c.h" +#include "SDL_windowevents_c.h" + +// Start and stop the event processing loop +extern bool SDL_StartEventLoop(void); +extern void SDL_StopEventLoop(void); +extern void SDL_QuitInterrupt(void); + +extern void SDL_SendAppEvent(SDL_EventType eventType); +extern void SDL_SendKeymapChangedEvent(void); +extern void SDL_SendLocaleChangedEvent(void); +extern void SDL_SendSystemThemeChangedEvent(void); + +extern void *SDL_AllocateTemporaryMemory(size_t size); +extern const char *SDL_CreateTemporaryString(const char *string); +extern void *SDL_ClaimTemporaryMemory(const void *mem); +extern void SDL_FreeTemporaryMemory(void); + +extern void SDL_PumpEventMaintenance(void); + +extern void SDL_SendQuit(void); + +extern bool SDL_InitEvents(void); +extern void SDL_QuitEvents(void); + +extern void SDL_SendPendingSignalEvents(void); + +extern bool SDL_InitQuit(void); +extern void SDL_QuitQuit(void); + +#endif // SDL_events_c_h_ diff --git a/contrib/SDL-3.2.8/src/events/SDL_eventwatch.c b/contrib/SDL-3.2.8/src/events/SDL_eventwatch.c new file mode 100644 index 0000000..08e7248 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_eventwatch.c @@ -0,0 +1,143 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#include "SDL_eventwatch_c.h" + + +bool SDL_InitEventWatchList(SDL_EventWatchList *list) +{ + if (list->lock == NULL) { + list->lock = SDL_CreateMutex(); + if (list->lock == NULL) { + return false; + } + } + return true; +} + +void SDL_QuitEventWatchList(SDL_EventWatchList *list) +{ + if (list->lock) { + SDL_DestroyMutex(list->lock); + list->lock = NULL; + } + if (list->watchers) { + SDL_free(list->watchers); + list->watchers = NULL; + list->count = 0; + } + SDL_zero(list->filter); +} + +bool SDL_DispatchEventWatchList(SDL_EventWatchList *list, SDL_Event *event) +{ + SDL_EventWatcher *filter = &list->filter; + + if (!filter->callback && list->count == 0) { + return true; + } + + SDL_LockMutex(list->lock); + { + // Make sure we only dispatch the current watcher list + int i, count = list->count; + + if (filter->callback && !filter->callback(filter->userdata, event)) { + SDL_UnlockMutex(list->lock); + return false; + } + + list->dispatching = true; + for (i = 0; i < count; ++i) { + if (!list->watchers[i].removed) { + list->watchers[i].callback(list->watchers[i].userdata, event); + } + } + list->dispatching = false; + + if (list->removed) { + for (i = list->count; i--;) { + if (list->watchers[i].removed) { + --list->count; + if (i < list->count) { + SDL_memmove(&list->watchers[i], &list->watchers[i + 1], (list->count - i) * sizeof(list->watchers[i])); + } + } + } + list->removed = false; + } + } + SDL_UnlockMutex(list->lock); + + return true; +} + +bool SDL_AddEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata) +{ + bool result = true; + + SDL_LockMutex(list->lock); + { + SDL_EventWatcher *watchers; + + watchers = (SDL_EventWatcher *)SDL_realloc(list->watchers, (list->count + 1) * sizeof(*watchers)); + if (watchers) { + SDL_EventWatcher *watcher; + + list->watchers = watchers; + watcher = &list->watchers[list->count]; + watcher->callback = filter; + watcher->userdata = userdata; + watcher->removed = false; + ++list->count; + } else { + result = false; + } + } + SDL_UnlockMutex(list->lock); + + return result; +} + +void SDL_RemoveEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata) +{ + SDL_LockMutex(list->lock); + { + int i; + + for (i = 0; i < list->count; ++i) { + if (list->watchers[i].callback == filter && list->watchers[i].userdata == userdata) { + if (list->dispatching) { + list->watchers[i].removed = true; + list->removed = true; + } else { + --list->count; + if (i < list->count) { + SDL_memmove(&list->watchers[i], &list->watchers[i + 1], (list->count - i) * sizeof(list->watchers[i])); + } + } + break; + } + } + } + SDL_UnlockMutex(list->lock); +} diff --git a/contrib/SDL-3.2.8/src/events/SDL_eventwatch_c.h b/contrib/SDL-3.2.8/src/events/SDL_eventwatch_c.h new file mode 100644 index 0000000..c9aea38 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_eventwatch_c.h @@ -0,0 +1,45 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +typedef struct SDL_EventWatcher +{ + SDL_EventFilter callback; + void *userdata; + bool removed; +} SDL_EventWatcher; + +typedef struct SDL_EventWatchList +{ + SDL_Mutex *lock; + SDL_EventWatcher filter; + SDL_EventWatcher *watchers; + int count; + bool dispatching; + bool removed; +} SDL_EventWatchList; + + +extern bool SDL_InitEventWatchList(SDL_EventWatchList *list); +extern void SDL_QuitEventWatchList(SDL_EventWatchList *list); +extern bool SDL_DispatchEventWatchList(SDL_EventWatchList *list, SDL_Event *event); +extern bool SDL_AddEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata); +extern void SDL_RemoveEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata); diff --git a/contrib/SDL-3.2.8/src/events/SDL_keyboard.c b/contrib/SDL-3.2.8/src/events/SDL_keyboard.c new file mode 100644 index 0000000..066c6e6 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_keyboard.c @@ -0,0 +1,922 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// General keyboard handling code for SDL + +#include "SDL_events_c.h" +#include "SDL_keymap_c.h" +#include "../video/SDL_sysvideo.h" + +#if 0 +#define DEBUG_KEYBOARD +#endif + +// Global keyboard information + +#define KEYBOARD_HARDWARE 0x01 +#define KEYBOARD_VIRTUAL 0x02 +#define KEYBOARD_AUTORELEASE 0x04 +#define KEYBOARD_IGNOREMODIFIERS 0x08 + +#define KEYBOARD_SOURCE_MASK (KEYBOARD_HARDWARE | KEYBOARD_AUTORELEASE) + +#define KEYCODE_OPTION_HIDE_NUMPAD 0x01 +#define KEYCODE_OPTION_FRENCH_NUMBERS 0x02 +#define KEYCODE_OPTION_LATIN_LETTERS 0x04 +#define DEFAULT_KEYCODE_OPTIONS (KEYCODE_OPTION_FRENCH_NUMBERS | KEYCODE_OPTION_LATIN_LETTERS) + +typedef struct SDL_KeyboardInstance +{ + SDL_KeyboardID instance_id; + char *name; +} SDL_KeyboardInstance; + +typedef struct SDL_Keyboard +{ + // Data common to all keyboards + SDL_Window *focus; + SDL_Keymod modstate; + Uint8 keysource[SDL_SCANCODE_COUNT]; + bool keystate[SDL_SCANCODE_COUNT]; + SDL_Keymap *keymap; + bool french_numbers; + bool latin_letters; + bool thai_keyboard; + Uint32 keycode_options; + bool autorelease_pending; + Uint64 hardware_timestamp; + int next_reserved_scancode; +} SDL_Keyboard; + +static SDL_Keyboard SDL_keyboard; +static int SDL_keyboard_count; +static SDL_KeyboardInstance *SDL_keyboards; + +static void SDLCALL SDL_KeycodeOptionsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Keyboard *keyboard = (SDL_Keyboard *)userdata; + + if (hint && *hint) { + keyboard->keycode_options = 0; + if (!SDL_strstr(hint, "none")) { + if (SDL_strstr(hint, "hide_numpad")) { + keyboard->keycode_options |= KEYCODE_OPTION_HIDE_NUMPAD; + } + if (SDL_strstr(hint, "french_numbers")) { + keyboard->keycode_options |= KEYCODE_OPTION_FRENCH_NUMBERS; + } + if (SDL_strstr(hint, "latin_letters")) { + keyboard->keycode_options |= KEYCODE_OPTION_LATIN_LETTERS; + } + } + } else { + keyboard->keycode_options = DEFAULT_KEYCODE_OPTIONS; + } +} + +// Public functions +bool SDL_InitKeyboard(void) +{ + SDL_AddHintCallback(SDL_HINT_KEYCODE_OPTIONS, + SDL_KeycodeOptionsChanged, &SDL_keyboard); + return true; +} + +bool SDL_IsKeyboard(Uint16 vendor, Uint16 product, int num_keys) +{ + const int REAL_KEYBOARD_KEY_COUNT = 50; + if (num_keys > 0 && num_keys < REAL_KEYBOARD_KEY_COUNT) { + return false; + } + + // Eventually we'll have a blacklist of devices that enumerate as keyboards but aren't really + return true; +} + +static int SDL_GetKeyboardIndex(SDL_KeyboardID keyboardID) +{ + for (int i = 0; i < SDL_keyboard_count; ++i) { + if (keyboardID == SDL_keyboards[i].instance_id) { + return i; + } + } + return -1; +} + +void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name, bool send_event) +{ + int keyboard_index = SDL_GetKeyboardIndex(keyboardID); + if (keyboard_index >= 0) { + // We already know about this keyboard + return; + } + + SDL_assert(keyboardID != 0); + + SDL_KeyboardInstance *keyboards = (SDL_KeyboardInstance *)SDL_realloc(SDL_keyboards, (SDL_keyboard_count + 1) * sizeof(*keyboards)); + if (!keyboards) { + return; + } + SDL_KeyboardInstance *instance = &keyboards[SDL_keyboard_count]; + instance->instance_id = keyboardID; + instance->name = SDL_strdup(name ? name : ""); + SDL_keyboards = keyboards; + ++SDL_keyboard_count; + + if (send_event) { + SDL_Event event; + SDL_zero(event); + event.type = SDL_EVENT_KEYBOARD_ADDED; + event.kdevice.which = keyboardID; + SDL_PushEvent(&event); + } +} + +void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID, bool send_event) +{ + int keyboard_index = SDL_GetKeyboardIndex(keyboardID); + if (keyboard_index < 0) { + // We don't know about this keyboard + return; + } + + SDL_free(SDL_keyboards[keyboard_index].name); + + if (keyboard_index != SDL_keyboard_count - 1) { + SDL_memmove(&SDL_keyboards[keyboard_index], &SDL_keyboards[keyboard_index + 1], (SDL_keyboard_count - keyboard_index - 1) * sizeof(SDL_keyboards[keyboard_index])); + } + --SDL_keyboard_count; + + if (send_event) { + SDL_Event event; + SDL_zero(event); + event.type = SDL_EVENT_KEYBOARD_REMOVED; + event.kdevice.which = keyboardID; + SDL_PushEvent(&event); + } +} + +bool SDL_HasKeyboard(void) +{ + return (SDL_keyboard_count > 0); +} + +SDL_KeyboardID *SDL_GetKeyboards(int *count) +{ + int i; + SDL_KeyboardID *keyboards; + + keyboards = (SDL_JoystickID *)SDL_malloc((SDL_keyboard_count + 1) * sizeof(*keyboards)); + if (keyboards) { + if (count) { + *count = SDL_keyboard_count; + } + + for (i = 0; i < SDL_keyboard_count; ++i) { + keyboards[i] = SDL_keyboards[i].instance_id; + } + keyboards[i] = 0; + } else { + if (count) { + *count = 0; + } + } + + return keyboards; +} + +const char *SDL_GetKeyboardNameForID(SDL_KeyboardID instance_id) +{ + int keyboard_index = SDL_GetKeyboardIndex(instance_id); + if (keyboard_index < 0) { + SDL_SetError("Keyboard %" SDL_PRIu32 " not found", instance_id); + return NULL; + } + return SDL_GetPersistentString(SDL_keyboards[keyboard_index].name); +} + +void SDL_ResetKeyboard(void) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + int scancode; + +#ifdef DEBUG_KEYBOARD + SDL_Log("Resetting keyboard"); +#endif + for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_SCANCODE_COUNT; ++scancode) { + if (keyboard->keystate[scancode]) { + SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, 0, (SDL_Scancode)scancode, false); + } + } +} + +SDL_Keymap *SDL_GetCurrentKeymap(void) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + + if (keyboard->thai_keyboard) { + // Thai keyboards are QWERTY plus Thai characters, use the default QWERTY keymap + return NULL; + } + + if ((keyboard->keycode_options & KEYCODE_OPTION_LATIN_LETTERS) && + !keyboard->latin_letters) { + // We'll use the default QWERTY keymap + return NULL; + } + + return keyboard->keymap; +} + +void SDL_SetKeymap(SDL_Keymap *keymap, bool send_event) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + + if (keyboard->keymap) { + SDL_DestroyKeymap(keyboard->keymap); + } + + keyboard->keymap = keymap; + + // Detect French number row (all symbols) + keyboard->french_numbers = true; + for (int i = SDL_SCANCODE_1; i <= SDL_SCANCODE_0; ++i) { + if (SDL_isdigit(SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_NONE)) || + !SDL_isdigit(SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_SHIFT))) { + keyboard->french_numbers = false; + break; + } + } + + // Detect non-Latin keymap + keyboard->thai_keyboard = false; + keyboard->latin_letters = false; + for (int i = SDL_SCANCODE_A; i <= SDL_SCANCODE_D; ++i) { + SDL_Keycode key = SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_NONE); + if (key <= 0xFF) { + keyboard->latin_letters = true; + break; + } + + if (key >= 0x0E00 && key <= 0x0E7F) { + keyboard->thai_keyboard = true; + break; + } + } + + if (send_event) { + SDL_SendKeymapChangedEvent(); + } +} + +static SDL_Scancode GetNextReservedScancode(void) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + SDL_Scancode scancode; + + if (keyboard->next_reserved_scancode && keyboard->next_reserved_scancode < SDL_SCANCODE_RESERVED + 100) { + scancode = (SDL_Scancode)keyboard->next_reserved_scancode; + } else { + scancode = SDL_SCANCODE_RESERVED; + } + keyboard->next_reserved_scancode = (int)scancode + 1; + + return scancode; +} + +static void SetKeymapEntry(SDL_Scancode scancode, SDL_Keymod modstate, SDL_Keycode keycode) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + + if (!keyboard->keymap) { + keyboard->keymap = SDL_CreateKeymap(); + } + + SDL_SetKeymapEntry(keyboard->keymap, scancode, modstate, keycode); +} + +SDL_Window *SDL_GetKeyboardFocus(void) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + + return keyboard->focus; +} + +bool SDL_SetKeyboardFocus(SDL_Window *window) +{ + SDL_VideoDevice *video = SDL_GetVideoDevice(); + SDL_Keyboard *keyboard = &SDL_keyboard; + SDL_Mouse *mouse = SDL_GetMouse(); + + if (window) { + if (!SDL_ObjectValid(window, SDL_OBJECT_TYPE_WINDOW) || window->is_destroying) { + return SDL_SetError("Invalid window"); + } + } + + if (keyboard->focus && !window) { + // We won't get anymore keyboard messages, so reset keyboard state + SDL_ResetKeyboard(); + + // Also leave mouse relative mode + if (mouse->relative_mode) { + SDL_SetRelativeMouseMode(false); + + SDL_Window *focus = keyboard->focus; + if ((focus->flags & SDL_WINDOW_MINIMIZED) != 0) { + // We can't warp the mouse within minimized windows, so manually restore the position + float x = focus->x + mouse->x; + float y = focus->y + mouse->y; + SDL_WarpMouseGlobal(x, y); + } + } + } + + // See if the current window has lost focus + if (keyboard->focus && keyboard->focus != window) { + SDL_SendWindowEvent(keyboard->focus, SDL_EVENT_WINDOW_FOCUS_LOST, 0, 0); + + // Ensures IME compositions are committed + if (SDL_TextInputActive(keyboard->focus)) { + if (video && video->StopTextInput) { + video->StopTextInput(video, keyboard->focus); + } + } + } + + keyboard->focus = window; + + if (keyboard->focus) { + SDL_SendWindowEvent(keyboard->focus, SDL_EVENT_WINDOW_FOCUS_GAINED, 0, 0); + + if (SDL_TextInputActive(keyboard->focus)) { + if (video && video->StartTextInput) { + video->StartTextInput(video, keyboard->focus, keyboard->focus->text_input_props); + } + } + } + + SDL_UpdateRelativeMouseMode(); + + return true; +} + +static SDL_Keycode SDL_ConvertNumpadKeycode(SDL_Keycode keycode, bool numlock) +{ + switch (keycode) { + case SDLK_KP_DIVIDE: + return SDLK_SLASH; + case SDLK_KP_MULTIPLY: + return SDLK_ASTERISK; + case SDLK_KP_MINUS: + return SDLK_MINUS; + case SDLK_KP_PLUS: + return SDLK_PLUS; + case SDLK_KP_ENTER: + return SDLK_RETURN; + case SDLK_KP_1: + return numlock ? SDLK_1 : SDLK_END; + case SDLK_KP_2: + return numlock ? SDLK_2 : SDLK_DOWN; + case SDLK_KP_3: + return numlock ? SDLK_3 : SDLK_PAGEDOWN; + case SDLK_KP_4: + return numlock ? SDLK_4 : SDLK_LEFT; + case SDLK_KP_5: + return numlock ? SDLK_5 : SDLK_CLEAR; + case SDLK_KP_6: + return numlock ? SDLK_6 : SDLK_RIGHT; + case SDLK_KP_7: + return numlock ? SDLK_7 : SDLK_HOME; + case SDLK_KP_8: + return numlock ? SDLK_8 : SDLK_UP; + case SDLK_KP_9: + return numlock ? SDLK_9 : SDLK_PAGEUP; + case SDLK_KP_0: + return numlock ? SDLK_0 : SDLK_INSERT; + case SDLK_KP_PERIOD: + return numlock ? SDLK_PERIOD : SDLK_DELETE; + case SDLK_KP_EQUALS: + return SDLK_EQUALS; + case SDLK_KP_COMMA: + return SDLK_COMMA; + case SDLK_KP_EQUALSAS400: + return SDLK_EQUALS; + case SDLK_KP_LEFTPAREN: + return SDLK_LEFTPAREN; + case SDLK_KP_RIGHTPAREN: + return SDLK_RIGHTPAREN; + case SDLK_KP_LEFTBRACE: + return SDLK_LEFTBRACE; + case SDLK_KP_RIGHTBRACE: + return SDLK_RIGHTBRACE; + case SDLK_KP_TAB: + return SDLK_TAB; + case SDLK_KP_BACKSPACE: + return SDLK_BACKSPACE; + case SDLK_KP_A: + return SDLK_A; + case SDLK_KP_B: + return SDLK_B; + case SDLK_KP_C: + return SDLK_C; + case SDLK_KP_D: + return SDLK_D; + case SDLK_KP_E: + return SDLK_E; + case SDLK_KP_F: + return SDLK_F; + case SDLK_KP_PERCENT: + return SDLK_PERCENT; + case SDLK_KP_LESS: + return SDLK_LESS; + case SDLK_KP_GREATER: + return SDLK_GREATER; + case SDLK_KP_AMPERSAND: + return SDLK_AMPERSAND; + case SDLK_KP_COLON: + return SDLK_COLON; + case SDLK_KP_HASH: + return SDLK_HASH; + case SDLK_KP_SPACE: + return SDLK_SPACE; + case SDLK_KP_AT: + return SDLK_AT; + case SDLK_KP_EXCLAM: + return SDLK_EXCLAIM; + case SDLK_KP_PLUSMINUS: + return SDLK_PLUSMINUS; + default: + return keycode; + } +} + +SDL_Keycode SDL_GetKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate, bool key_event) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + + if (key_event) { + SDL_Keymap *keymap = SDL_GetCurrentKeymap(); + bool numlock = (modstate & SDL_KMOD_NUM) != 0; + SDL_Keycode keycode; + + // We won't be applying any modifiers by default + modstate = SDL_KMOD_NONE; + + if ((keyboard->keycode_options & KEYCODE_OPTION_FRENCH_NUMBERS) && + keyboard->french_numbers && + (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_0)) { + // Add the shift state to generate a numeric keycode + modstate |= SDL_KMOD_SHIFT; + } + + keycode = SDL_GetKeymapKeycode(keymap, scancode, modstate); + + if (keyboard->keycode_options & KEYCODE_OPTION_HIDE_NUMPAD) { + keycode = SDL_ConvertNumpadKeycode(keycode, numlock); + } + return keycode; + } + + return SDL_GetKeymapKeycode(keyboard->keymap, scancode, modstate); +} + +SDL_Scancode SDL_GetScancodeFromKey(SDL_Keycode key, SDL_Keymod *modstate) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + + return SDL_GetKeymapScancode(keyboard->keymap, key, modstate); +} + +static bool SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, bool down) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + bool posted = false; + SDL_Keycode keycode = SDLK_UNKNOWN; + Uint32 type; + bool repeat = false; + const Uint8 source = flags & KEYBOARD_SOURCE_MASK; + +#ifdef DEBUG_KEYBOARD + SDL_Log("The '%s' key has been %s", SDL_GetScancodeName(scancode), down ? "pressed" : "released"); +#endif + + // Figure out what type of event this is + if (down) { + type = SDL_EVENT_KEY_DOWN; + } else { + type = SDL_EVENT_KEY_UP; + } + + if (scancode > SDL_SCANCODE_UNKNOWN && scancode < SDL_SCANCODE_COUNT) { + // Drop events that don't change state + if (down) { + if (keyboard->keystate[scancode]) { + if (!(keyboard->keysource[scancode] & source)) { + keyboard->keysource[scancode] |= source; + return false; + } + repeat = true; + } + keyboard->keysource[scancode] |= source; + } else { + if (!keyboard->keystate[scancode]) { + return false; + } + keyboard->keysource[scancode] = 0; + } + + // Update internal keyboard state + keyboard->keystate[scancode] = down; + + keycode = SDL_GetKeyFromScancode(scancode, keyboard->modstate, true); + + } else if (rawcode == 0) { + // Nothing to do! + return false; + } + + if (source == KEYBOARD_HARDWARE) { + keyboard->hardware_timestamp = SDL_GetTicks(); + } else if (source == KEYBOARD_AUTORELEASE) { + keyboard->autorelease_pending = true; + } + + // Update modifiers state if applicable + if (!(flags & KEYBOARD_IGNOREMODIFIERS) && !repeat) { + SDL_Keymod modifier; + + switch (keycode) { + case SDLK_LCTRL: + modifier = SDL_KMOD_LCTRL; + break; + case SDLK_RCTRL: + modifier = SDL_KMOD_RCTRL; + break; + case SDLK_LSHIFT: + modifier = SDL_KMOD_LSHIFT; + break; + case SDLK_RSHIFT: + modifier = SDL_KMOD_RSHIFT; + break; + case SDLK_LALT: + modifier = SDL_KMOD_LALT; + break; + case SDLK_RALT: + modifier = SDL_KMOD_RALT; + break; + case SDLK_LGUI: + modifier = SDL_KMOD_LGUI; + break; + case SDLK_RGUI: + modifier = SDL_KMOD_RGUI; + break; + case SDLK_MODE: + modifier = SDL_KMOD_MODE; + break; + default: + modifier = SDL_KMOD_NONE; + break; + } + if (SDL_EVENT_KEY_DOWN == type) { + switch (keycode) { + case SDLK_NUMLOCKCLEAR: + keyboard->modstate ^= SDL_KMOD_NUM; + break; + case SDLK_CAPSLOCK: + keyboard->modstate ^= SDL_KMOD_CAPS; + break; + case SDLK_SCROLLLOCK: + keyboard->modstate ^= SDL_KMOD_SCROLL; + break; + default: + keyboard->modstate |= modifier; + break; + } + } else { + keyboard->modstate &= ~modifier; + } + } + + // Post the event, if desired + if (SDL_EventEnabled(type)) { + SDL_Event event; + event.type = type; + event.common.timestamp = timestamp; + event.key.scancode = scancode; + event.key.key = keycode; + event.key.mod = keyboard->modstate; + event.key.raw = (Uint16)rawcode; + event.key.down = down; + event.key.repeat = repeat; + event.key.windowID = keyboard->focus ? keyboard->focus->id : 0; + event.key.which = keyboardID; + posted = SDL_PushEvent(&event); + } + + /* If the keyboard is grabbed and the grabbed window is in full-screen, + minimize the window when we receive Alt+Tab, unless the application + has explicitly opted out of this behavior. */ + if (keycode == SDLK_TAB && down && + (keyboard->modstate & SDL_KMOD_ALT) && + keyboard->focus && + (keyboard->focus->flags & SDL_WINDOW_KEYBOARD_GRABBED) && + (keyboard->focus->flags & SDL_WINDOW_FULLSCREEN) && + SDL_GetHintBoolean(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED, true)) { + /* We will temporarily forfeit our grab by minimizing our window, + allowing the user to escape the application */ + SDL_MinimizeWindow(keyboard->focus); + } + + return posted; +} + +void SDL_SendKeyboardUnicodeKey(Uint64 timestamp, Uint32 ch) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + SDL_Keymod modstate = SDL_KMOD_NONE; + SDL_Scancode scancode; + + if (ch == '\n') { + ch = SDLK_RETURN; + } + scancode = SDL_GetKeymapScancode(keyboard->keymap, ch, &modstate); + + // Make sure we have this keycode in our keymap + if (scancode == SDL_SCANCODE_UNKNOWN && ch < SDLK_SCANCODE_MASK) { + scancode = GetNextReservedScancode(); + SetKeymapEntry(scancode, modstate, ch); + } + + if (modstate & SDL_KMOD_SHIFT) { + // If the character uses shift, press shift down + SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_LSHIFT, true); + } + + // Send a keydown and keyup for the character + SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, true); + SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, false); + + if (modstate & SDL_KMOD_SHIFT) { + // If the character uses shift, release shift + SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_LSHIFT, false); + } +} + +bool SDL_SendKeyboardKey(Uint64 timestamp, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, bool down) +{ + return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, keyboardID, rawcode, scancode, down); +} + +bool SDL_SendKeyboardKeyAndKeycode(Uint64 timestamp, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, SDL_Keycode keycode, bool down) +{ + if (down) { + // Make sure we have this keycode in our keymap + SetKeymapEntry(scancode, SDL_GetModState(), keycode); + } + + return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, keyboardID, rawcode, scancode, down); +} + +bool SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, bool down) +{ + return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE | KEYBOARD_IGNOREMODIFIERS, keyboardID, rawcode, scancode, down); +} + +bool SDL_SendKeyboardKeyAutoRelease(Uint64 timestamp, SDL_Scancode scancode) +{ + return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_AUTORELEASE, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, true); +} + +void SDL_ReleaseAutoReleaseKeys(void) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + int scancode; + + if (keyboard->autorelease_pending) { + for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_SCANCODE_COUNT; ++scancode) { + if (keyboard->keysource[scancode] == KEYBOARD_AUTORELEASE) { + SDL_SendKeyboardKeyInternal(0, KEYBOARD_AUTORELEASE, SDL_GLOBAL_KEYBOARD_ID, 0, (SDL_Scancode)scancode, false); + } + } + keyboard->autorelease_pending = false; + } + + if (keyboard->hardware_timestamp) { + // Keep hardware keyboard "active" for 250 ms + if (SDL_GetTicks() >= keyboard->hardware_timestamp + 250) { + keyboard->hardware_timestamp = 0; + } + } +} + +bool SDL_HardwareKeyboardKeyPressed(void) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + int scancode; + + for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_SCANCODE_COUNT; ++scancode) { + if (keyboard->keysource[scancode] & KEYBOARD_HARDWARE) { + return true; + } + } + + return keyboard->hardware_timestamp ? true : false; +} + +void SDL_SendKeyboardText(const char *text) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + + if (!SDL_TextInputActive(keyboard->focus)) { + return; + } + + if (!text || !*text) { + return; + } + + // Don't post text events for unprintable characters + if (SDL_iscntrl((unsigned char)*text)) { + return; + } + + // Post the event, if desired + if (SDL_EventEnabled(SDL_EVENT_TEXT_INPUT)) { + SDL_Event event; + event.type = SDL_EVENT_TEXT_INPUT; + event.common.timestamp = 0; + event.text.windowID = keyboard->focus ? keyboard->focus->id : 0; + event.text.text = SDL_CreateTemporaryString(text); + if (!event.text.text) { + return; + } + SDL_PushEvent(&event); + } +} + +void SDL_SendEditingText(const char *text, int start, int length) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + + if (!SDL_TextInputActive(keyboard->focus)) { + return; + } + + if (!text) { + return; + } + + // Post the event, if desired + if (SDL_EventEnabled(SDL_EVENT_TEXT_EDITING)) { + SDL_Event event; + + event.type = SDL_EVENT_TEXT_EDITING; + event.common.timestamp = 0; + event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0; + event.edit.start = start; + event.edit.length = length; + event.edit.text = SDL_CreateTemporaryString(text); + if (!event.edit.text) { + return; + } + SDL_PushEvent(&event); + } +} + +static const char * const *CreateCandidatesForEvent(char **candidates, int num_candidates) +{ + const char **event_candidates; + int i; + char *ptr; + size_t total_length = (num_candidates + 1) * sizeof(*event_candidates); + + for (i = 0; i < num_candidates; ++i) { + size_t length = SDL_strlen(candidates[i]) + 1; + + total_length += length; + } + + event_candidates = (const char **)SDL_AllocateTemporaryMemory(total_length); + if (!event_candidates) { + return NULL; + } + ptr = (char *)(event_candidates + (num_candidates + 1)); + + for (i = 0; i < num_candidates; ++i) { + size_t length = SDL_strlen(candidates[i]) + 1; + + event_candidates[i] = ptr; + SDL_memcpy(ptr, candidates[i], length); + ptr += length; + } + event_candidates[i] = NULL; + + return event_candidates; +} + +void SDL_SendEditingTextCandidates(char **candidates, int num_candidates, int selected_candidate, bool horizontal) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + + if (!SDL_TextInputActive(keyboard->focus)) { + return; + } + + // Post the event, if desired + if (SDL_EventEnabled(SDL_EVENT_TEXT_EDITING_CANDIDATES)) { + SDL_Event event; + + event.type = SDL_EVENT_TEXT_EDITING_CANDIDATES; + event.common.timestamp = 0; + event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0; + if (num_candidates > 0) { + const char * const *event_candidates = CreateCandidatesForEvent(candidates, num_candidates); + if (!event_candidates) { + return; + } + event.edit_candidates.candidates = event_candidates; + event.edit_candidates.num_candidates = num_candidates; + event.edit_candidates.selected_candidate = selected_candidate; + event.edit_candidates.horizontal = horizontal; + } else { + event.edit_candidates.candidates = NULL; + event.edit_candidates.num_candidates = 0; + event.edit_candidates.selected_candidate = -1; + event.edit_candidates.horizontal = false; + } + SDL_PushEvent(&event); + } +} + +void SDL_QuitKeyboard(void) +{ + for (int i = SDL_keyboard_count; i--;) { + SDL_RemoveKeyboard(SDL_keyboards[i].instance_id, false); + } + SDL_free(SDL_keyboards); + SDL_keyboards = NULL; + + if (SDL_keyboard.keymap) { + SDL_DestroyKeymap(SDL_keyboard.keymap); + SDL_keyboard.keymap = NULL; + } + + SDL_RemoveHintCallback(SDL_HINT_KEYCODE_OPTIONS, + SDL_KeycodeOptionsChanged, &SDL_keyboard); +} + +const bool *SDL_GetKeyboardState(int *numkeys) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + + if (numkeys != (int *)0) { + *numkeys = SDL_SCANCODE_COUNT; + } + return keyboard->keystate; +} + +SDL_Keymod SDL_GetModState(void) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + + return keyboard->modstate; +} + +void SDL_SetModState(SDL_Keymod modstate) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + + keyboard->modstate = modstate; +} + +// Note that SDL_ToggleModState() is not a public API. SDL_SetModState() is. +void SDL_ToggleModState(SDL_Keymod modstate, bool toggle) +{ + SDL_Keyboard *keyboard = &SDL_keyboard; + if (toggle) { + keyboard->modstate |= modstate; + } else { + keyboard->modstate &= ~modstate; + } +} + diff --git a/contrib/SDL-3.2.8/src/events/SDL_keyboard_c.h b/contrib/SDL-3.2.8/src/events/SDL_keyboard_c.h new file mode 100644 index 0000000..ddfb5c5 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_keyboard_c.h @@ -0,0 +1,87 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_keyboard_c_h_ +#define SDL_keyboard_c_h_ + +#include "SDL_keymap_c.h" + +// Keyboard events not associated with a specific input device +#define SDL_GLOBAL_KEYBOARD_ID 0 + +// The default keyboard input device, for platforms that don't have multiple keyboards +#define SDL_DEFAULT_KEYBOARD_ID 1 + +// Initialize the keyboard subsystem +extern bool SDL_InitKeyboard(void); + +// Return whether a device is actually a keyboard +extern bool SDL_IsKeyboard(Uint16 vendor, Uint16 product, int num_keys); + +// A keyboard has been added to the system +extern void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name, bool send_event); + +// A keyboard has been removed from the system +extern void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID, bool send_event); + +// Set the mapping of scancode to key codes +extern void SDL_SetKeymap(SDL_Keymap *keymap, bool send_event); + +// Set the keyboard focus window +extern bool SDL_SetKeyboardFocus(SDL_Window *window); + +/* Send a character from an on-screen keyboard as scancode and modifier key events, + currently assuming ASCII characters on a US keyboard layout + */ +extern void SDL_SendKeyboardUnicodeKey(Uint64 timestamp, Uint32 ch); + +// Send a keyboard key event +extern bool SDL_SendKeyboardKey(Uint64 timestamp, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, bool down); +extern bool SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, bool down); +extern bool SDL_SendKeyboardKeyAutoRelease(Uint64 timestamp, SDL_Scancode scancode); + +/* This is for platforms that don't know the keymap but can report scancode and keycode directly. + Most platforms should prefer to optionally call SDL_SetKeymap and then use SDL_SendKeyboardKey. */ +extern bool SDL_SendKeyboardKeyAndKeycode(Uint64 timestamp, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, SDL_Keycode keycode, bool down); + +// Release all the autorelease keys +extern void SDL_ReleaseAutoReleaseKeys(void); + +// Return true if any hardware key is pressed +extern bool SDL_HardwareKeyboardKeyPressed(void); + +// Send keyboard text input +extern void SDL_SendKeyboardText(const char *text); + +// Send editing text for selected range from start to end +extern void SDL_SendEditingText(const char *text, int start, int length); + +// Send editing text candidates, which will be copied into the event +extern void SDL_SendEditingTextCandidates(char **candidates, int num_candidates, int selected_candidate, bool horizontal); + +// Shutdown the keyboard subsystem +extern void SDL_QuitKeyboard(void); + +// Toggle on or off pieces of the keyboard mod state. +extern void SDL_ToggleModState(SDL_Keymod modstate, bool toggle); + +#endif // SDL_keyboard_c_h_ diff --git a/contrib/SDL-3.2.8/src/events/SDL_keymap.c b/contrib/SDL-3.2.8/src/events/SDL_keymap.c new file mode 100644 index 0000000..bd08786 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_keymap.c @@ -0,0 +1,1153 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#include "SDL_keymap_c.h" +#include "SDL_keyboard_c.h" + +struct SDL_Keymap +{ + SDL_HashTable *scancode_to_keycode; + SDL_HashTable *keycode_to_scancode; +}; + +static SDL_Keycode SDL_GetDefaultKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate); +static SDL_Scancode SDL_GetDefaultScancodeFromKey(SDL_Keycode key, SDL_Keymod *modstate); + +SDL_Keymap *SDL_CreateKeymap(void) +{ + SDL_Keymap *keymap = (SDL_Keymap *)SDL_malloc(sizeof(*keymap)); + if (!keymap) { + return NULL; + } + + keymap->scancode_to_keycode = SDL_CreateHashTable(256, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL); + keymap->keycode_to_scancode = SDL_CreateHashTable(256, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL); + if (!keymap->scancode_to_keycode || !keymap->keycode_to_scancode) { + SDL_DestroyKeymap(keymap); + return NULL; + } + return keymap; +} + +static SDL_Keymod NormalizeModifierStateForKeymap(SDL_Keymod modstate) +{ + // The modifiers that affect the keymap are: SHIFT, CAPS, ALT, MODE, and LEVEL5 + modstate &= (SDL_KMOD_SHIFT | SDL_KMOD_CAPS | SDL_KMOD_ALT | SDL_KMOD_MODE | SDL_KMOD_LEVEL5); + + // If either right or left Shift are set, set both in the output + if (modstate & SDL_KMOD_SHIFT) { + modstate |= SDL_KMOD_SHIFT; + } + + // If either right or left Alt are set, set both in the output + if (modstate & SDL_KMOD_ALT) { + modstate |= SDL_KMOD_ALT; + } + + return modstate; +} + +void SDL_SetKeymapEntry(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod modstate, SDL_Keycode keycode) +{ + if (!keymap) { + return; + } + + modstate = NormalizeModifierStateForKeymap(modstate); + Uint32 key = ((Uint32)modstate << 16) | scancode; + const void *value; + if (SDL_FindInHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, &value)) { + const SDL_Keycode existing_keycode = (SDL_Keycode)(uintptr_t)value; + if (existing_keycode == keycode) { + // We already have this mapping + return; + } + // InsertIntoHashTable will replace the existing entry in the keymap atomically. + } + SDL_InsertIntoHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, (void *)(uintptr_t)keycode, true); + + bool update_keycode = true; + if (SDL_FindInHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode, &value)) { + const Uint32 existing_value = (Uint32)(uintptr_t)value; + const SDL_Keymod existing_modstate = (SDL_Keymod)(existing_value >> 16); + + // Keep the simplest combination of scancode and modifiers to generate this keycode + if (existing_modstate <= modstate) { + update_keycode = false; + } + } + if (update_keycode) { + SDL_InsertIntoHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode, (void *)(uintptr_t)key, true); + } +} + +SDL_Keycode SDL_GetKeymapKeycode(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod modstate) +{ + SDL_Keycode keycode; + + const Uint32 key = ((Uint32)NormalizeModifierStateForKeymap(modstate) << 16) | scancode; + const void *value; + if (keymap && SDL_FindInHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, &value)) { + keycode = (SDL_Keycode)(uintptr_t)value; + } else { + keycode = SDL_GetDefaultKeyFromScancode(scancode, modstate); + } + return keycode; +} + +SDL_Scancode SDL_GetKeymapScancode(SDL_Keymap *keymap, SDL_Keycode keycode, SDL_Keymod *modstate) +{ + SDL_Scancode scancode; + + const void *value; + if (keymap && SDL_FindInHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode, &value)) { + scancode = (SDL_Scancode)((uintptr_t)value & 0xFFFF); + if (modstate) { + *modstate = (SDL_Keymod)((uintptr_t)value >> 16); + } + } else { + scancode = SDL_GetDefaultScancodeFromKey(keycode, modstate); + } + return scancode; +} + +void SDL_DestroyKeymap(SDL_Keymap *keymap) +{ + if (!keymap) { + return; + } + + SDL_DestroyHashTable(keymap->scancode_to_keycode); + SDL_DestroyHashTable(keymap->keycode_to_scancode); + SDL_free(keymap); +} + +static const SDL_Keycode normal_default_symbols[] = { + SDLK_1, + SDLK_2, + SDLK_3, + SDLK_4, + SDLK_5, + SDLK_6, + SDLK_7, + SDLK_8, + SDLK_9, + SDLK_0, + SDLK_RETURN, + SDLK_ESCAPE, + SDLK_BACKSPACE, + SDLK_TAB, + SDLK_SPACE, + SDLK_MINUS, + SDLK_EQUALS, + SDLK_LEFTBRACKET, + SDLK_RIGHTBRACKET, + SDLK_BACKSLASH, + SDLK_HASH, + SDLK_SEMICOLON, + SDLK_APOSTROPHE, + SDLK_GRAVE, + SDLK_COMMA, + SDLK_PERIOD, + SDLK_SLASH, +}; + +static const SDL_Keycode shifted_default_symbols[] = { + SDLK_EXCLAIM, + SDLK_AT, + SDLK_HASH, + SDLK_DOLLAR, + SDLK_PERCENT, + SDLK_CARET, + SDLK_AMPERSAND, + SDLK_ASTERISK, + SDLK_LEFTPAREN, + SDLK_RIGHTPAREN, + SDLK_RETURN, + SDLK_ESCAPE, + SDLK_BACKSPACE, + SDLK_TAB, + SDLK_SPACE, + SDLK_UNDERSCORE, + SDLK_PLUS, + SDLK_LEFTBRACE, + SDLK_RIGHTBRACE, + SDLK_PIPE, + SDLK_HASH, + SDLK_COLON, + SDLK_DBLAPOSTROPHE, + SDLK_TILDE, + SDLK_LESS, + SDLK_GREATER, + SDLK_QUESTION +}; + +static const struct +{ + SDL_Keycode keycode; + SDL_Scancode scancode; +} extended_default_symbols[] = { + { SDLK_LEFT_TAB, SDL_SCANCODE_TAB }, + { SDLK_MULTI_KEY_COMPOSE, SDL_SCANCODE_APPLICATION }, // Sun keyboards + { SDLK_LMETA, SDL_SCANCODE_LGUI }, + { SDLK_RMETA, SDL_SCANCODE_RGUI }, + { SDLK_RHYPER, SDL_SCANCODE_APPLICATION } +}; + +static SDL_Keycode SDL_GetDefaultKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate) +{ + if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_SCANCODE_COUNT) { + SDL_InvalidParamError("scancode"); + return SDLK_UNKNOWN; + } + + if (scancode < SDL_SCANCODE_A) { + return SDLK_UNKNOWN; + } + + if (scancode < SDL_SCANCODE_1) { + bool shifted = (modstate & SDL_KMOD_SHIFT) ? true : false; +#ifdef SDL_PLATFORM_APPLE + // Apple maps to upper case for either shift or capslock inclusive + if (modstate & SDL_KMOD_CAPS) { + shifted = true; + } +#else + if (modstate & SDL_KMOD_CAPS) { + shifted = !shifted; + } +#endif + if (modstate & SDL_KMOD_MODE) { + return SDLK_UNKNOWN; + } + if (!shifted) { + return (SDL_Keycode)('a' + scancode - SDL_SCANCODE_A); + } else { + return (SDL_Keycode)('A' + scancode - SDL_SCANCODE_A); + } + } + + if (scancode < SDL_SCANCODE_CAPSLOCK) { + bool shifted = (modstate & SDL_KMOD_SHIFT) ? true : false; + + if (modstate & SDL_KMOD_MODE) { + return SDLK_UNKNOWN; + } + if (!shifted) { + return normal_default_symbols[scancode - SDL_SCANCODE_1]; + } else { + return shifted_default_symbols[scancode - SDL_SCANCODE_1]; + } + } + + // These scancodes are not mapped to printable keycodes + switch (scancode) { + case SDL_SCANCODE_DELETE: + return SDLK_DELETE; + case SDL_SCANCODE_CAPSLOCK: + return SDLK_CAPSLOCK; + case SDL_SCANCODE_F1: + return SDLK_F1; + case SDL_SCANCODE_F2: + return SDLK_F2; + case SDL_SCANCODE_F3: + return SDLK_F3; + case SDL_SCANCODE_F4: + return SDLK_F4; + case SDL_SCANCODE_F5: + return SDLK_F5; + case SDL_SCANCODE_F6: + return SDLK_F6; + case SDL_SCANCODE_F7: + return SDLK_F7; + case SDL_SCANCODE_F8: + return SDLK_F8; + case SDL_SCANCODE_F9: + return SDLK_F9; + case SDL_SCANCODE_F10: + return SDLK_F10; + case SDL_SCANCODE_F11: + return SDLK_F11; + case SDL_SCANCODE_F12: + return SDLK_F12; + case SDL_SCANCODE_PRINTSCREEN: + return SDLK_PRINTSCREEN; + case SDL_SCANCODE_SCROLLLOCK: + return SDLK_SCROLLLOCK; + case SDL_SCANCODE_PAUSE: + return SDLK_PAUSE; + case SDL_SCANCODE_INSERT: + return SDLK_INSERT; + case SDL_SCANCODE_HOME: + return SDLK_HOME; + case SDL_SCANCODE_PAGEUP: + return SDLK_PAGEUP; + case SDL_SCANCODE_END: + return SDLK_END; + case SDL_SCANCODE_PAGEDOWN: + return SDLK_PAGEDOWN; + case SDL_SCANCODE_RIGHT: + return SDLK_RIGHT; + case SDL_SCANCODE_LEFT: + return SDLK_LEFT; + case SDL_SCANCODE_DOWN: + return SDLK_DOWN; + case SDL_SCANCODE_UP: + return SDLK_UP; + case SDL_SCANCODE_NUMLOCKCLEAR: + return SDLK_NUMLOCKCLEAR; + case SDL_SCANCODE_KP_DIVIDE: + return SDLK_KP_DIVIDE; + case SDL_SCANCODE_KP_MULTIPLY: + return SDLK_KP_MULTIPLY; + case SDL_SCANCODE_KP_MINUS: + return SDLK_KP_MINUS; + case SDL_SCANCODE_KP_PLUS: + return SDLK_KP_PLUS; + case SDL_SCANCODE_KP_ENTER: + return SDLK_KP_ENTER; + case SDL_SCANCODE_KP_1: + return SDLK_KP_1; + case SDL_SCANCODE_KP_2: + return SDLK_KP_2; + case SDL_SCANCODE_KP_3: + return SDLK_KP_3; + case SDL_SCANCODE_KP_4: + return SDLK_KP_4; + case SDL_SCANCODE_KP_5: + return SDLK_KP_5; + case SDL_SCANCODE_KP_6: + return SDLK_KP_6; + case SDL_SCANCODE_KP_7: + return SDLK_KP_7; + case SDL_SCANCODE_KP_8: + return SDLK_KP_8; + case SDL_SCANCODE_KP_9: + return SDLK_KP_9; + case SDL_SCANCODE_KP_0: + return SDLK_KP_0; + case SDL_SCANCODE_KP_PERIOD: + return SDLK_KP_PERIOD; + case SDL_SCANCODE_APPLICATION: + return SDLK_APPLICATION; + case SDL_SCANCODE_POWER: + return SDLK_POWER; + case SDL_SCANCODE_KP_EQUALS: + return SDLK_KP_EQUALS; + case SDL_SCANCODE_F13: + return SDLK_F13; + case SDL_SCANCODE_F14: + return SDLK_F14; + case SDL_SCANCODE_F15: + return SDLK_F15; + case SDL_SCANCODE_F16: + return SDLK_F16; + case SDL_SCANCODE_F17: + return SDLK_F17; + case SDL_SCANCODE_F18: + return SDLK_F18; + case SDL_SCANCODE_F19: + return SDLK_F19; + case SDL_SCANCODE_F20: + return SDLK_F20; + case SDL_SCANCODE_F21: + return SDLK_F21; + case SDL_SCANCODE_F22: + return SDLK_F22; + case SDL_SCANCODE_F23: + return SDLK_F23; + case SDL_SCANCODE_F24: + return SDLK_F24; + case SDL_SCANCODE_EXECUTE: + return SDLK_EXECUTE; + case SDL_SCANCODE_HELP: + return SDLK_HELP; + case SDL_SCANCODE_MENU: + return SDLK_MENU; + case SDL_SCANCODE_SELECT: + return SDLK_SELECT; + case SDL_SCANCODE_STOP: + return SDLK_STOP; + case SDL_SCANCODE_AGAIN: + return SDLK_AGAIN; + case SDL_SCANCODE_UNDO: + return SDLK_UNDO; + case SDL_SCANCODE_CUT: + return SDLK_CUT; + case SDL_SCANCODE_COPY: + return SDLK_COPY; + case SDL_SCANCODE_PASTE: + return SDLK_PASTE; + case SDL_SCANCODE_FIND: + return SDLK_FIND; + case SDL_SCANCODE_MUTE: + return SDLK_MUTE; + case SDL_SCANCODE_VOLUMEUP: + return SDLK_VOLUMEUP; + case SDL_SCANCODE_VOLUMEDOWN: + return SDLK_VOLUMEDOWN; + case SDL_SCANCODE_KP_COMMA: + return SDLK_KP_COMMA; + case SDL_SCANCODE_KP_EQUALSAS400: + return SDLK_KP_EQUALSAS400; + case SDL_SCANCODE_ALTERASE: + return SDLK_ALTERASE; + case SDL_SCANCODE_SYSREQ: + return SDLK_SYSREQ; + case SDL_SCANCODE_CANCEL: + return SDLK_CANCEL; + case SDL_SCANCODE_CLEAR: + return SDLK_CLEAR; + case SDL_SCANCODE_PRIOR: + return SDLK_PRIOR; + case SDL_SCANCODE_RETURN2: + return SDLK_RETURN2; + case SDL_SCANCODE_SEPARATOR: + return SDLK_SEPARATOR; + case SDL_SCANCODE_OUT: + return SDLK_OUT; + case SDL_SCANCODE_OPER: + return SDLK_OPER; + case SDL_SCANCODE_CLEARAGAIN: + return SDLK_CLEARAGAIN; + case SDL_SCANCODE_CRSEL: + return SDLK_CRSEL; + case SDL_SCANCODE_EXSEL: + return SDLK_EXSEL; + case SDL_SCANCODE_KP_00: + return SDLK_KP_00; + case SDL_SCANCODE_KP_000: + return SDLK_KP_000; + case SDL_SCANCODE_THOUSANDSSEPARATOR: + return SDLK_THOUSANDSSEPARATOR; + case SDL_SCANCODE_DECIMALSEPARATOR: + return SDLK_DECIMALSEPARATOR; + case SDL_SCANCODE_CURRENCYUNIT: + return SDLK_CURRENCYUNIT; + case SDL_SCANCODE_CURRENCYSUBUNIT: + return SDLK_CURRENCYSUBUNIT; + case SDL_SCANCODE_KP_LEFTPAREN: + return SDLK_KP_LEFTPAREN; + case SDL_SCANCODE_KP_RIGHTPAREN: + return SDLK_KP_RIGHTPAREN; + case SDL_SCANCODE_KP_LEFTBRACE: + return SDLK_KP_LEFTBRACE; + case SDL_SCANCODE_KP_RIGHTBRACE: + return SDLK_KP_RIGHTBRACE; + case SDL_SCANCODE_KP_TAB: + return SDLK_KP_TAB; + case SDL_SCANCODE_KP_BACKSPACE: + return SDLK_KP_BACKSPACE; + case SDL_SCANCODE_KP_A: + return SDLK_KP_A; + case SDL_SCANCODE_KP_B: + return SDLK_KP_B; + case SDL_SCANCODE_KP_C: + return SDLK_KP_C; + case SDL_SCANCODE_KP_D: + return SDLK_KP_D; + case SDL_SCANCODE_KP_E: + return SDLK_KP_E; + case SDL_SCANCODE_KP_F: + return SDLK_KP_F; + case SDL_SCANCODE_KP_XOR: + return SDLK_KP_XOR; + case SDL_SCANCODE_KP_POWER: + return SDLK_KP_POWER; + case SDL_SCANCODE_KP_PERCENT: + return SDLK_KP_PERCENT; + case SDL_SCANCODE_KP_LESS: + return SDLK_KP_LESS; + case SDL_SCANCODE_KP_GREATER: + return SDLK_KP_GREATER; + case SDL_SCANCODE_KP_AMPERSAND: + return SDLK_KP_AMPERSAND; + case SDL_SCANCODE_KP_DBLAMPERSAND: + return SDLK_KP_DBLAMPERSAND; + case SDL_SCANCODE_KP_VERTICALBAR: + return SDLK_KP_VERTICALBAR; + case SDL_SCANCODE_KP_DBLVERTICALBAR: + return SDLK_KP_DBLVERTICALBAR; + case SDL_SCANCODE_KP_COLON: + return SDLK_KP_COLON; + case SDL_SCANCODE_KP_HASH: + return SDLK_KP_HASH; + case SDL_SCANCODE_KP_SPACE: + return SDLK_KP_SPACE; + case SDL_SCANCODE_KP_AT: + return SDLK_KP_AT; + case SDL_SCANCODE_KP_EXCLAM: + return SDLK_KP_EXCLAM; + case SDL_SCANCODE_KP_MEMSTORE: + return SDLK_KP_MEMSTORE; + case SDL_SCANCODE_KP_MEMRECALL: + return SDLK_KP_MEMRECALL; + case SDL_SCANCODE_KP_MEMCLEAR: + return SDLK_KP_MEMCLEAR; + case SDL_SCANCODE_KP_MEMADD: + return SDLK_KP_MEMADD; + case SDL_SCANCODE_KP_MEMSUBTRACT: + return SDLK_KP_MEMSUBTRACT; + case SDL_SCANCODE_KP_MEMMULTIPLY: + return SDLK_KP_MEMMULTIPLY; + case SDL_SCANCODE_KP_MEMDIVIDE: + return SDLK_KP_MEMDIVIDE; + case SDL_SCANCODE_KP_PLUSMINUS: + return SDLK_KP_PLUSMINUS; + case SDL_SCANCODE_KP_CLEAR: + return SDLK_KP_CLEAR; + case SDL_SCANCODE_KP_CLEARENTRY: + return SDLK_KP_CLEARENTRY; + case SDL_SCANCODE_KP_BINARY: + return SDLK_KP_BINARY; + case SDL_SCANCODE_KP_OCTAL: + return SDLK_KP_OCTAL; + case SDL_SCANCODE_KP_DECIMAL: + return SDLK_KP_DECIMAL; + case SDL_SCANCODE_KP_HEXADECIMAL: + return SDLK_KP_HEXADECIMAL; + case SDL_SCANCODE_LCTRL: + return SDLK_LCTRL; + case SDL_SCANCODE_LSHIFT: + return SDLK_LSHIFT; + case SDL_SCANCODE_LALT: + return SDLK_LALT; + case SDL_SCANCODE_LGUI: + return SDLK_LGUI; + case SDL_SCANCODE_RCTRL: + return SDLK_RCTRL; + case SDL_SCANCODE_RSHIFT: + return SDLK_RSHIFT; + case SDL_SCANCODE_RALT: + return SDLK_RALT; + case SDL_SCANCODE_RGUI: + return SDLK_RGUI; + case SDL_SCANCODE_MODE: + return SDLK_MODE; + case SDL_SCANCODE_SLEEP: + return SDLK_SLEEP; + case SDL_SCANCODE_WAKE: + return SDLK_WAKE; + case SDL_SCANCODE_CHANNEL_INCREMENT: + return SDLK_CHANNEL_INCREMENT; + case SDL_SCANCODE_CHANNEL_DECREMENT: + return SDLK_CHANNEL_DECREMENT; + case SDL_SCANCODE_MEDIA_PLAY: + return SDLK_MEDIA_PLAY; + case SDL_SCANCODE_MEDIA_PAUSE: + return SDLK_MEDIA_PAUSE; + case SDL_SCANCODE_MEDIA_RECORD: + return SDLK_MEDIA_RECORD; + case SDL_SCANCODE_MEDIA_FAST_FORWARD: + return SDLK_MEDIA_FAST_FORWARD; + case SDL_SCANCODE_MEDIA_REWIND: + return SDLK_MEDIA_REWIND; + case SDL_SCANCODE_MEDIA_NEXT_TRACK: + return SDLK_MEDIA_NEXT_TRACK; + case SDL_SCANCODE_MEDIA_PREVIOUS_TRACK: + return SDLK_MEDIA_PREVIOUS_TRACK; + case SDL_SCANCODE_MEDIA_STOP: + return SDLK_MEDIA_STOP; + case SDL_SCANCODE_MEDIA_EJECT: + return SDLK_MEDIA_EJECT; + case SDL_SCANCODE_MEDIA_PLAY_PAUSE: + return SDLK_MEDIA_PLAY_PAUSE; + case SDL_SCANCODE_MEDIA_SELECT: + return SDLK_MEDIA_SELECT; + case SDL_SCANCODE_AC_NEW: + return SDLK_AC_NEW; + case SDL_SCANCODE_AC_OPEN: + return SDLK_AC_OPEN; + case SDL_SCANCODE_AC_CLOSE: + return SDLK_AC_CLOSE; + case SDL_SCANCODE_AC_EXIT: + return SDLK_AC_EXIT; + case SDL_SCANCODE_AC_SAVE: + return SDLK_AC_SAVE; + case SDL_SCANCODE_AC_PRINT: + return SDLK_AC_PRINT; + case SDL_SCANCODE_AC_PROPERTIES: + return SDLK_AC_PROPERTIES; + case SDL_SCANCODE_AC_SEARCH: + return SDLK_AC_SEARCH; + case SDL_SCANCODE_AC_HOME: + return SDLK_AC_HOME; + case SDL_SCANCODE_AC_BACK: + return SDLK_AC_BACK; + case SDL_SCANCODE_AC_FORWARD: + return SDLK_AC_FORWARD; + case SDL_SCANCODE_AC_STOP: + return SDLK_AC_STOP; + case SDL_SCANCODE_AC_REFRESH: + return SDLK_AC_REFRESH; + case SDL_SCANCODE_AC_BOOKMARKS: + return SDLK_AC_BOOKMARKS; + case SDL_SCANCODE_SOFTLEFT: + return SDLK_SOFTLEFT; + case SDL_SCANCODE_SOFTRIGHT: + return SDLK_SOFTRIGHT; + case SDL_SCANCODE_CALL: + return SDLK_CALL; + case SDL_SCANCODE_ENDCALL: + return SDLK_ENDCALL; + default: + return SDLK_UNKNOWN; + } +} + +static SDL_Scancode SDL_GetDefaultScancodeFromKey(SDL_Keycode key, SDL_Keymod *modstate) +{ + if (modstate) { + *modstate = SDL_KMOD_NONE; + } + + if (key == SDLK_UNKNOWN) { + return SDL_SCANCODE_UNKNOWN; + } + + if (key & SDLK_EXTENDED_MASK) { + for (int i = 0; i < SDL_arraysize(extended_default_symbols); ++i) { + if (extended_default_symbols[i].keycode == key) { + return extended_default_symbols[i].scancode; + } + } + + return SDL_SCANCODE_UNKNOWN; + } + + if (key & SDLK_SCANCODE_MASK) { + return (SDL_Scancode)(key & ~SDLK_SCANCODE_MASK); + } + + if (key >= SDLK_A && key <= SDLK_Z) { + return (SDL_Scancode)(SDL_SCANCODE_A + key - SDLK_A); + } + + if (key >= 'A' && key <= 'Z') { + if (modstate) { + *modstate = SDL_KMOD_SHIFT; + } + return (SDL_Scancode)(SDL_SCANCODE_A + key - 'A'); + } + + for (int i = 0; i < SDL_arraysize(normal_default_symbols); ++i) { + if (key == normal_default_symbols[i]) { + return(SDL_Scancode)(SDL_SCANCODE_1 + i); + } + } + + for (int i = 0; i < SDL_arraysize(shifted_default_symbols); ++i) { + if (key == shifted_default_symbols[i]) { + if (modstate) { + *modstate = SDL_KMOD_SHIFT; + } + return(SDL_Scancode)(SDL_SCANCODE_1 + i); + } + } + + if (key == SDLK_DELETE) { + return SDL_SCANCODE_DELETE; + } + + return SDL_SCANCODE_UNKNOWN; +} + +static const char *SDL_scancode_names[SDL_SCANCODE_COUNT] = +{ + /* 0 */ NULL, + /* 1 */ NULL, + /* 2 */ NULL, + /* 3 */ NULL, + /* 4 */ "A", + /* 5 */ "B", + /* 6 */ "C", + /* 7 */ "D", + /* 8 */ "E", + /* 9 */ "F", + /* 10 */ "G", + /* 11 */ "H", + /* 12 */ "I", + /* 13 */ "J", + /* 14 */ "K", + /* 15 */ "L", + /* 16 */ "M", + /* 17 */ "N", + /* 18 */ "O", + /* 19 */ "P", + /* 20 */ "Q", + /* 21 */ "R", + /* 22 */ "S", + /* 23 */ "T", + /* 24 */ "U", + /* 25 */ "V", + /* 26 */ "W", + /* 27 */ "X", + /* 28 */ "Y", + /* 29 */ "Z", + /* 30 */ "1", + /* 31 */ "2", + /* 32 */ "3", + /* 33 */ "4", + /* 34 */ "5", + /* 35 */ "6", + /* 36 */ "7", + /* 37 */ "8", + /* 38 */ "9", + /* 39 */ "0", + /* 40 */ "Return", + /* 41 */ "Escape", + /* 42 */ "Backspace", + /* 43 */ "Tab", + /* 44 */ "Space", + /* 45 */ "-", + /* 46 */ "=", + /* 47 */ "[", + /* 48 */ "]", + /* 49 */ "\\", + /* 50 */ "#", + /* 51 */ ";", + /* 52 */ "'", + /* 53 */ "`", + /* 54 */ ",", + /* 55 */ ".", + /* 56 */ "/", + /* 57 */ "CapsLock", + /* 58 */ "F1", + /* 59 */ "F2", + /* 60 */ "F3", + /* 61 */ "F4", + /* 62 */ "F5", + /* 63 */ "F6", + /* 64 */ "F7", + /* 65 */ "F8", + /* 66 */ "F9", + /* 67 */ "F10", + /* 68 */ "F11", + /* 69 */ "F12", + /* 70 */ "PrintScreen", + /* 71 */ "ScrollLock", + /* 72 */ "Pause", + /* 73 */ "Insert", + /* 74 */ "Home", + /* 75 */ "PageUp", + /* 76 */ "Delete", + /* 77 */ "End", + /* 78 */ "PageDown", + /* 79 */ "Right", + /* 80 */ "Left", + /* 81 */ "Down", + /* 82 */ "Up", + /* 83 */ "Numlock", + /* 84 */ "Keypad /", + /* 85 */ "Keypad *", + /* 86 */ "Keypad -", + /* 87 */ "Keypad +", + /* 88 */ "Keypad Enter", + /* 89 */ "Keypad 1", + /* 90 */ "Keypad 2", + /* 91 */ "Keypad 3", + /* 92 */ "Keypad 4", + /* 93 */ "Keypad 5", + /* 94 */ "Keypad 6", + /* 95 */ "Keypad 7", + /* 96 */ "Keypad 8", + /* 97 */ "Keypad 9", + /* 98 */ "Keypad 0", + /* 99 */ "Keypad .", + /* 100 */ "NonUSBackslash", + /* 101 */ "Application", + /* 102 */ "Power", + /* 103 */ "Keypad =", + /* 104 */ "F13", + /* 105 */ "F14", + /* 106 */ "F15", + /* 107 */ "F16", + /* 108 */ "F17", + /* 109 */ "F18", + /* 110 */ "F19", + /* 111 */ "F20", + /* 112 */ "F21", + /* 113 */ "F22", + /* 114 */ "F23", + /* 115 */ "F24", + /* 116 */ "Execute", + /* 117 */ "Help", + /* 118 */ "Menu", + /* 119 */ "Select", + /* 120 */ "Stop", + /* 121 */ "Again", + /* 122 */ "Undo", + /* 123 */ "Cut", + /* 124 */ "Copy", + /* 125 */ "Paste", + /* 126 */ "Find", + /* 127 */ "Mute", + /* 128 */ "VolumeUp", + /* 129 */ "VolumeDown", + /* 130 */ NULL, + /* 131 */ NULL, + /* 132 */ NULL, + /* 133 */ "Keypad ,", + /* 134 */ "Keypad = (AS400)", + /* 135 */ "International 1", + /* 136 */ "International 2", + /* 137 */ "International 3", + /* 138 */ "International 4", + /* 139 */ "International 5", + /* 140 */ "International 6", + /* 141 */ "International 7", + /* 142 */ "International 8", + /* 143 */ "International 9", + /* 144 */ "Language 1", + /* 145 */ "Language 2", + /* 146 */ "Language 3", + /* 147 */ "Language 4", + /* 148 */ "Language 5", + /* 149 */ "Language 6", + /* 150 */ "Language 7", + /* 151 */ "Language 8", + /* 152 */ "Language 9", + /* 153 */ "AltErase", + /* 154 */ "SysReq", + /* 155 */ "Cancel", + /* 156 */ "Clear", + /* 157 */ "Prior", + /* 158 */ "Return", + /* 159 */ "Separator", + /* 160 */ "Out", + /* 161 */ "Oper", + /* 162 */ "Clear / Again", + /* 163 */ "CrSel", + /* 164 */ "ExSel", + /* 165 */ NULL, + /* 166 */ NULL, + /* 167 */ NULL, + /* 168 */ NULL, + /* 169 */ NULL, + /* 170 */ NULL, + /* 171 */ NULL, + /* 172 */ NULL, + /* 173 */ NULL, + /* 174 */ NULL, + /* 175 */ NULL, + /* 176 */ "Keypad 00", + /* 177 */ "Keypad 000", + /* 178 */ "ThousandsSeparator", + /* 179 */ "DecimalSeparator", + /* 180 */ "CurrencyUnit", + /* 181 */ "CurrencySubUnit", + /* 182 */ "Keypad (", + /* 183 */ "Keypad )", + /* 184 */ "Keypad {", + /* 185 */ "Keypad }", + /* 186 */ "Keypad Tab", + /* 187 */ "Keypad Backspace", + /* 188 */ "Keypad A", + /* 189 */ "Keypad B", + /* 190 */ "Keypad C", + /* 191 */ "Keypad D", + /* 192 */ "Keypad E", + /* 193 */ "Keypad F", + /* 194 */ "Keypad XOR", + /* 195 */ "Keypad ^", + /* 196 */ "Keypad %", + /* 197 */ "Keypad <", + /* 198 */ "Keypad >", + /* 199 */ "Keypad &", + /* 200 */ "Keypad &&", + /* 201 */ "Keypad |", + /* 202 */ "Keypad ||", + /* 203 */ "Keypad :", + /* 204 */ "Keypad #", + /* 205 */ "Keypad Space", + /* 206 */ "Keypad @", + /* 207 */ "Keypad !", + /* 208 */ "Keypad MemStore", + /* 209 */ "Keypad MemRecall", + /* 210 */ "Keypad MemClear", + /* 211 */ "Keypad MemAdd", + /* 212 */ "Keypad MemSubtract", + /* 213 */ "Keypad MemMultiply", + /* 214 */ "Keypad MemDivide", + /* 215 */ "Keypad +/-", + /* 216 */ "Keypad Clear", + /* 217 */ "Keypad ClearEntry", + /* 218 */ "Keypad Binary", + /* 219 */ "Keypad Octal", + /* 220 */ "Keypad Decimal", + /* 221 */ "Keypad Hexadecimal", + /* 222 */ NULL, + /* 223 */ NULL, + /* 224 */ "Left Ctrl", + /* 225 */ "Left Shift", + /* 226 */ "Left Alt", + /* 227 */ "Left GUI", + /* 228 */ "Right Ctrl", + /* 229 */ "Right Shift", + /* 230 */ "Right Alt", + /* 231 */ "Right GUI", + /* 232 */ NULL, + /* 233 */ NULL, + /* 234 */ NULL, + /* 235 */ NULL, + /* 236 */ NULL, + /* 237 */ NULL, + /* 238 */ NULL, + /* 239 */ NULL, + /* 240 */ NULL, + /* 241 */ NULL, + /* 242 */ NULL, + /* 243 */ NULL, + /* 244 */ NULL, + /* 245 */ NULL, + /* 246 */ NULL, + /* 247 */ NULL, + /* 248 */ NULL, + /* 249 */ NULL, + /* 250 */ NULL, + /* 251 */ NULL, + /* 252 */ NULL, + /* 253 */ NULL, + /* 254 */ NULL, + /* 255 */ NULL, + /* 256 */ NULL, + /* 257 */ "ModeSwitch", + /* 258 */ "Sleep", + /* 259 */ "Wake", + /* 260 */ "ChannelUp", + /* 261 */ "ChannelDown", + /* 262 */ "MediaPlay", + /* 263 */ "MediaPause", + /* 264 */ "MediaRecord", + /* 265 */ "MediaFastForward", + /* 266 */ "MediaRewind", + /* 267 */ "MediaTrackNext", + /* 268 */ "MediaTrackPrevious", + /* 269 */ "MediaStop", + /* 270 */ "Eject", + /* 271 */ "MediaPlayPause", + /* 272 */ "MediaSelect", + /* 273 */ "AC New", + /* 274 */ "AC Open", + /* 275 */ "AC Close", + /* 276 */ "AC Exit", + /* 277 */ "AC Save", + /* 278 */ "AC Print", + /* 279 */ "AC Properties", + /* 280 */ "AC Search", + /* 281 */ "AC Home", + /* 282 */ "AC Back", + /* 283 */ "AC Forward", + /* 284 */ "AC Stop", + /* 285 */ "AC Refresh", + /* 286 */ "AC Bookmarks", + /* 287 */ "SoftLeft", + /* 288 */ "SoftRight", + /* 289 */ "Call", + /* 290 */ "EndCall", +}; + +static const char *SDL_extended_key_names[] = { + "LeftTab", /* 0x01 SDLK_LEFT_TAB */ + "Level5Shift", /* 0x02 SDLK_LEVEL5_SHIFT */ + "MultiKeyCompose", /* 0x03 SDLK_MULTI_KEY_COMPOSE */ + "Left Meta", /* 0x04 SDLK_LMETA */ + "Right Meta", /* 0x05 SDLK_RMETA */ + "Left Hyper", /* 0x06 SDLK_LHYPER */ + "Right Hyper" /* 0x07 SDLK_RHYPER */ +}; + +bool SDL_SetScancodeName(SDL_Scancode scancode, const char *name) +{ + if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_SCANCODE_COUNT) { + return SDL_InvalidParamError("scancode"); + } + + SDL_scancode_names[scancode] = name; + return true; +} + +const char *SDL_GetScancodeName(SDL_Scancode scancode) +{ + const char *name; + if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_SCANCODE_COUNT) { + SDL_InvalidParamError("scancode"); + return ""; + } + + name = SDL_scancode_names[scancode]; + if (!name) { + name = ""; + } + // This is pointing to static memory or application managed memory + return name; +} + +SDL_Scancode SDL_GetScancodeFromName(const char *name) +{ + int i; + + if (!name || !*name) { + SDL_InvalidParamError("name"); + return SDL_SCANCODE_UNKNOWN; + } + + for (i = 0; i < SDL_arraysize(SDL_scancode_names); ++i) { + if (!SDL_scancode_names[i]) { + continue; + } + if (SDL_strcasecmp(name, SDL_scancode_names[i]) == 0) { + return (SDL_Scancode)i; + } + } + + SDL_InvalidParamError("name"); + return SDL_SCANCODE_UNKNOWN; +} + +const char *SDL_GetKeyName(SDL_Keycode key) +{ + const bool uppercase = true; + char name[8]; + char *end; + + if (key & SDLK_SCANCODE_MASK) { + return SDL_GetScancodeName((SDL_Scancode)(key & ~SDLK_SCANCODE_MASK)); + } + + if (key & SDLK_EXTENDED_MASK) { + const SDL_Keycode idx = (key & ~SDLK_EXTENDED_MASK); + if (idx > 0 && (idx - 1) < SDL_arraysize(SDL_extended_key_names)) { + return SDL_extended_key_names[idx - 1]; + } + + // Key out of name index bounds. + SDL_InvalidParamError("key"); + return ""; + } + + switch (key) { + case SDLK_RETURN: + return SDL_GetScancodeName(SDL_SCANCODE_RETURN); + case SDLK_ESCAPE: + return SDL_GetScancodeName(SDL_SCANCODE_ESCAPE); + case SDLK_BACKSPACE: + return SDL_GetScancodeName(SDL_SCANCODE_BACKSPACE); + case SDLK_TAB: + return SDL_GetScancodeName(SDL_SCANCODE_TAB); + case SDLK_SPACE: + return SDL_GetScancodeName(SDL_SCANCODE_SPACE); + case SDLK_DELETE: + return SDL_GetScancodeName(SDL_SCANCODE_DELETE); + default: + if (uppercase) { + // SDL_Keycode is defined as the unshifted key on the keyboard, + // but the key name is defined as the letter printed on that key, + // which is usually the shifted capital letter. + if (key > 0x7F || (key >= 'a' && key <= 'z')) { + SDL_Keymap *keymap = SDL_GetCurrentKeymap(); + SDL_Keymod modstate; + SDL_Scancode scancode = SDL_GetKeymapScancode(keymap, key, &modstate); + if (scancode != SDL_SCANCODE_UNKNOWN && !(modstate & SDL_KMOD_SHIFT)) { + SDL_Keycode capital = SDL_GetKeymapKeycode(keymap, scancode, SDL_KMOD_SHIFT); + if (capital > 0x7F || (capital >= 'A' && capital <= 'Z')) { + key = capital; + } + } + } + } + + end = SDL_UCS4ToUTF8(key, name); + *end = '\0'; + return SDL_GetPersistentString(name); + } +} + +SDL_Keycode SDL_GetKeyFromName(const char *name) +{ + const bool uppercase = true; + SDL_Keycode key; + + // Check input + if (!name) { + return SDLK_UNKNOWN; + } + + // If it's a single UTF-8 character, then that's the keycode itself + key = *(const unsigned char *)name; + if (key >= 0xF0) { + if (SDL_strlen(name) == 4) { + int i = 0; + key = (Uint16)(name[i] & 0x07) << 18; + key |= (Uint16)(name[++i] & 0x3F) << 12; + key |= (Uint16)(name[++i] & 0x3F) << 6; + key |= (Uint16)(name[++i] & 0x3F); + } else { + key = SDLK_UNKNOWN; + } + } else if (key >= 0xE0) { + if (SDL_strlen(name) == 3) { + int i = 0; + key = (Uint16)(name[i] & 0x0F) << 12; + key |= (Uint16)(name[++i] & 0x3F) << 6; + key |= (Uint16)(name[++i] & 0x3F); + } else { + key = SDLK_UNKNOWN; + } + } else if (key >= 0xC0) { + if (SDL_strlen(name) == 2) { + int i = 0; + key = (Uint16)(name[i] & 0x1F) << 6; + key |= (Uint16)(name[++i] & 0x3F); + } else { + key = SDLK_UNKNOWN; + } + } else { + if (SDL_strlen(name) != 1) { + key = SDLK_UNKNOWN; + } + } + + if (key != SDLK_UNKNOWN) { + if (uppercase) { + // SDL_Keycode is defined as the unshifted key on the keyboard, + // but the key name is defined as the letter printed on that key, + // which is usually the shifted capital letter. + SDL_Keymap *keymap = SDL_GetCurrentKeymap(); + SDL_Keymod modstate; + SDL_Scancode scancode = SDL_GetKeymapScancode(keymap, key, &modstate); + if (scancode != SDL_SCANCODE_UNKNOWN && (modstate & (SDL_KMOD_SHIFT | SDL_KMOD_CAPS))) { + key = SDL_GetKeymapKeycode(keymap, scancode, SDL_KMOD_NONE); + } + } + return key; + } + + // Check the extended key names + for (SDL_Keycode i = 0; i < SDL_arraysize(SDL_extended_key_names); ++i) { + if (SDL_strcasecmp(name, SDL_extended_key_names[i]) == 0) { + return (i + 1) | SDLK_EXTENDED_MASK; + } + } + + return SDL_GetKeyFromScancode(SDL_GetScancodeFromName(name), SDL_KMOD_NONE, false); +} diff --git a/contrib/SDL-3.2.8/src/events/SDL_keymap_c.h b/contrib/SDL-3.2.8/src/events/SDL_keymap_c.h new file mode 100644 index 0000000..9c80397 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_keymap_c.h @@ -0,0 +1,35 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_keymap_c_h_ +#define SDL_keymap_c_h_ + +typedef struct SDL_Keymap SDL_Keymap; + +SDL_Keymap *SDL_GetCurrentKeymap(void); +SDL_Keymap *SDL_CreateKeymap(void); +void SDL_SetKeymapEntry(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod modstate, SDL_Keycode keycode); +SDL_Keycode SDL_GetKeymapKeycode(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod modstate); +SDL_Scancode SDL_GetKeymapScancode(SDL_Keymap *keymap, SDL_Keycode keycode, SDL_Keymod *modstate); +void SDL_DestroyKeymap(SDL_Keymap *keymap); + +#endif // SDL_keymap_c_h_ diff --git a/contrib/SDL-3.2.8/src/events/SDL_keysym_to_keycode.c b/contrib/SDL-3.2.8/src/events/SDL_keysym_to_keycode.c new file mode 100644 index 0000000..7cbfcb6 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_keysym_to_keycode.c @@ -0,0 +1,68 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#if defined(SDL_VIDEO_DRIVER_WAYLAND) || defined(SDL_VIDEO_DRIVER_X11) + +#include "SDL_keyboard_c.h" +#include "SDL_keysym_to_scancode_c.h" +#include "imKStoUCS.h" + + +// Extended key code mappings +static const struct +{ + Uint32 keysym; + SDL_Keycode keycode; +} keysym_to_keycode_table[] = { + { 0xfe03, SDLK_MODE }, // XK_ISO_Level3_Shift + { 0xfe11, SDLK_LEVEL5_SHIFT }, // XK_ISO_Level5_Shift + { 0xfe20, SDLK_LEFT_TAB }, // XK_ISO_Left_Tab + { 0xff20, SDLK_MULTI_KEY_COMPOSE }, // XK_Multi_key + { 0xffe7, SDLK_LMETA }, // XK_Meta_L + { 0xffe8, SDLK_RMETA }, // XK_Meta_R + { 0xffed, SDLK_LHYPER }, // XK_Hyper_L + { 0xffee, SDLK_RHYPER }, // XK_Hyper_R +}; + +SDL_Keycode SDL_GetKeyCodeFromKeySym(Uint32 keysym, Uint32 keycode, SDL_Keymod modifiers) +{ + SDL_Keycode sdl_keycode = SDL_KeySymToUcs4(keysym); + + if (!sdl_keycode) { + for (int i = 0; i < SDL_arraysize(keysym_to_keycode_table); ++i) { + if (keysym == keysym_to_keycode_table[i].keysym) { + return keysym_to_keycode_table[i].keycode; + } + } + } + + if (!sdl_keycode) { + const SDL_Scancode scancode = SDL_GetScancodeFromKeySym(keysym, keycode); + if (scancode != SDL_SCANCODE_UNKNOWN) { + sdl_keycode = SDL_GetKeymapKeycode(NULL, scancode, modifiers); + } + } + + return sdl_keycode; +} + +#endif // SDL_VIDEO_DRIVER_WAYLAND || SDL_VIDEO_DRIVER_X11 diff --git a/contrib/SDL-3.2.8/src/events/SDL_keysym_to_keycode_c.h b/contrib/SDL-3.2.8/src/events/SDL_keysym_to_keycode_c.h new file mode 100644 index 0000000..2321d20 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_keysym_to_keycode_c.h @@ -0,0 +1,28 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_keysym_to_keycode_c_h_ +#define SDL_keysym_to_keycode_c_h_ + +// Convert a keysym to an SDL key code +extern SDL_Keycode SDL_GetKeyCodeFromKeySym(Uint32 keysym, Uint32 keycode, SDL_Keymod modifiers); + +#endif // SDL_keysym_to_scancode_c_h_ diff --git a/contrib/SDL-3.2.8/src/events/SDL_keysym_to_scancode.c b/contrib/SDL-3.2.8/src/events/SDL_keysym_to_scancode.c new file mode 100644 index 0000000..8d43ca3 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_keysym_to_scancode.c @@ -0,0 +1,439 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#if defined(SDL_VIDEO_DRIVER_WAYLAND) || defined(SDL_VIDEO_DRIVER_X11) + +#include "SDL_keyboard_c.h" +#include "SDL_scancode_tables_c.h" +#include "SDL_keysym_to_scancode_c.h" + +/* *INDENT-OFF* */ // clang-format off +static const struct { + Uint32 keysym; + SDL_Scancode scancode; +} KeySymToSDLScancode[] = { + { 0xFF9C, SDL_SCANCODE_KP_1 }, // XK_KP_End + { 0xFF99, SDL_SCANCODE_KP_2 }, // XK_KP_Down + { 0xFF9B, SDL_SCANCODE_KP_3 }, // XK_KP_Next + { 0xFF96, SDL_SCANCODE_KP_4 }, // XK_KP_Left + { 0xFF9D, SDL_SCANCODE_KP_5 }, // XK_KP_Begin + { 0xFF98, SDL_SCANCODE_KP_6 }, // XK_KP_Right + { 0xFF95, SDL_SCANCODE_KP_7 }, // XK_KP_Home + { 0xFF97, SDL_SCANCODE_KP_8 }, // XK_KP_Up + { 0xFF9A, SDL_SCANCODE_KP_9 }, // XK_KP_Prior + { 0xFF9E, SDL_SCANCODE_KP_0 }, // XK_KP_Insert + { 0xFF9F, SDL_SCANCODE_KP_PERIOD }, // XK_KP_Delete + { 0xFF62, SDL_SCANCODE_EXECUTE }, // XK_Execute + { 0xFFEE, SDL_SCANCODE_APPLICATION }, // XK_Hyper_R + { 0xFE03, SDL_SCANCODE_RALT }, // XK_ISO_Level3_Shift + { 0xFE20, SDL_SCANCODE_TAB }, // XK_ISO_Left_Tab + { 0xFFEB, SDL_SCANCODE_LGUI }, // XK_Super_L + { 0xFFEC, SDL_SCANCODE_RGUI }, // XK_Super_R + { 0xFF7E, SDL_SCANCODE_MODE }, // XK_Mode_switch + { 0x1008FF65, SDL_SCANCODE_MENU }, // XF86MenuKB + { 0x1008FF81, SDL_SCANCODE_F13 }, // XF86Tools + { 0x1008FF45, SDL_SCANCODE_F14 }, // XF86Launch5 + { 0x1008FF46, SDL_SCANCODE_F15 }, // XF86Launch6 + { 0x1008FF47, SDL_SCANCODE_F16 }, // XF86Launch7 + { 0x1008FF48, SDL_SCANCODE_F17 }, // XF86Launch8 + { 0x1008FF49, SDL_SCANCODE_F18 }, // XF86Launch9 +}; + +// This is a mapping from X keysym to Linux keycode +static const Uint32 LinuxKeycodeKeysyms[] = { + /* 0, 0x000 */ 0x0, // NoSymbol + /* 1, 0x001 */ 0xFF1B, // Escape + /* 2, 0x002 */ 0x31, // 1 + /* 3, 0x003 */ 0x32, // 2 + /* 4, 0x004 */ 0x33, // 3 + /* 5, 0x005 */ 0x34, // 4 + /* 6, 0x006 */ 0x35, // 5 + /* 7, 0x007 */ 0x36, // 6 + /* 8, 0x008 */ 0x37, // 7 + /* 9, 0x009 */ 0x38, // 8 + /* 10, 0x00a */ 0x39, // 9 + /* 11, 0x00b */ 0x30, // 0 + /* 12, 0x00c */ 0x2D, // minus + /* 13, 0x00d */ 0x3D, // equal + /* 14, 0x00e */ 0xFF08, // BackSpace + /* 15, 0x00f */ 0xFF09, // Tab + /* 16, 0x010 */ 0x71, // q + /* 17, 0x011 */ 0x77, // w + /* 18, 0x012 */ 0x65, // e + /* 19, 0x013 */ 0x72, // r + /* 20, 0x014 */ 0x74, // t + /* 21, 0x015 */ 0x79, // y + /* 22, 0x016 */ 0x75, // u + /* 23, 0x017 */ 0x69, // i + /* 24, 0x018 */ 0x6F, // o + /* 25, 0x019 */ 0x70, // p + /* 26, 0x01a */ 0x5B, // bracketleft + /* 27, 0x01b */ 0x5D, // bracketright + /* 28, 0x01c */ 0xFF0D, // Return + /* 29, 0x01d */ 0xFFE3, // Control_L + /* 30, 0x01e */ 0x61, // a + /* 31, 0x01f */ 0x73, // s + /* 32, 0x020 */ 0x64, // d + /* 33, 0x021 */ 0x66, // f + /* 34, 0x022 */ 0x67, // g + /* 35, 0x023 */ 0x68, // h + /* 36, 0x024 */ 0x6A, // j + /* 37, 0x025 */ 0x6B, // k + /* 38, 0x026 */ 0x6C, // l + /* 39, 0x027 */ 0x3B, // semicolon + /* 40, 0x028 */ 0x27, // apostrophe + /* 41, 0x029 */ 0x60, // grave + /* 42, 0x02a */ 0xFFE1, // Shift_L + /* 43, 0x02b */ 0x5C, // backslash + /* 44, 0x02c */ 0x7A, // z + /* 45, 0x02d */ 0x78, // x + /* 46, 0x02e */ 0x63, // c + /* 47, 0x02f */ 0x76, // v + /* 48, 0x030 */ 0x62, // b + /* 49, 0x031 */ 0x6E, // n + /* 50, 0x032 */ 0x6D, // m + /* 51, 0x033 */ 0x2C, // comma + /* 52, 0x034 */ 0x2E, // period + /* 53, 0x035 */ 0x2F, // slash + /* 54, 0x036 */ 0xFFE2, // Shift_R + /* 55, 0x037 */ 0xFFAA, // KP_Multiply + /* 56, 0x038 */ 0xFFE9, // Alt_L + /* 57, 0x039 */ 0x20, // space + /* 58, 0x03a */ 0xFFE5, // Caps_Lock + /* 59, 0x03b */ 0xFFBE, // F1 + /* 60, 0x03c */ 0xFFBF, // F2 + /* 61, 0x03d */ 0xFFC0, // F3 + /* 62, 0x03e */ 0xFFC1, // F4 + /* 63, 0x03f */ 0xFFC2, // F5 + /* 64, 0x040 */ 0xFFC3, // F6 + /* 65, 0x041 */ 0xFFC4, // F7 + /* 66, 0x042 */ 0xFFC5, // F8 + /* 67, 0x043 */ 0xFFC6, // F9 + /* 68, 0x044 */ 0xFFC7, // F10 + /* 69, 0x045 */ 0xFF7F, // Num_Lock + /* 70, 0x046 */ 0xFF14, // Scroll_Lock + /* 71, 0x047 */ 0xFFB7, // KP_7 + /* 72, 0x048 */ 0XFFB8, // KP_8 + /* 73, 0x049 */ 0XFFB9, // KP_9 + /* 74, 0x04a */ 0xFFAD, // KP_Subtract + /* 75, 0x04b */ 0xFFB4, // KP_4 + /* 76, 0x04c */ 0xFFB5, // KP_5 + /* 77, 0x04d */ 0xFFB6, // KP_6 + /* 78, 0x04e */ 0xFFAB, // KP_Add + /* 79, 0x04f */ 0xFFB1, // KP_1 + /* 80, 0x050 */ 0xFFB2, // KP_2 + /* 81, 0x051 */ 0xFFB3, // KP_3 + /* 82, 0x052 */ 0xFFB0, // KP_0 + /* 83, 0x053 */ 0xFFAE, // KP_Decimal + /* 84, 0x054 */ 0x0, // NoSymbol + /* 85, 0x055 */ 0x0, // NoSymbol + /* 86, 0x056 */ 0x3C, // less + /* 87, 0x057 */ 0xFFC8, // F11 + /* 88, 0x058 */ 0xFFC9, // F12 + /* 89, 0x059 */ 0x0, // NoSymbol + /* 90, 0x05a */ 0xFF26, // Katakana + /* 91, 0x05b */ 0xFF25, // Hiragana + /* 92, 0x05c */ 0xFF23, // Henkan_Mode + /* 93, 0x05d */ 0xFF27, // Hiragana_Katakana + /* 94, 0x05e */ 0xFF22, // Muhenkan + /* 95, 0x05f */ 0x0, // NoSymbol + /* 96, 0x060 */ 0xFF8D, // KP_Enter + /* 97, 0x061 */ 0xFFE4, // Control_R + /* 98, 0x062 */ 0xFFAF, // KP_Divide + /* 99, 0x063 */ 0xFF15, // Sys_Req + /* 100, 0x064 */ 0xFFEA, // Alt_R + /* 101, 0x065 */ 0xFF0A, // Linefeed + /* 102, 0x066 */ 0xFF50, // Home + /* 103, 0x067 */ 0xFF52, // Up + /* 104, 0x068 */ 0xFF55, // Prior + /* 105, 0x069 */ 0xFF51, // Left + /* 106, 0x06a */ 0xFF53, // Right + /* 107, 0x06b */ 0xFF57, // End + /* 108, 0x06c */ 0xFF54, // Down + /* 109, 0x06d */ 0xFF56, // Next + /* 110, 0x06e */ 0xFF63, // Insert + /* 111, 0x06f */ 0xFFFF, // Delete + /* 112, 0x070 */ 0x0, // NoSymbol + /* 113, 0x071 */ 0x1008FF12, // XF86AudioMute + /* 114, 0x072 */ 0x1008FF11, // XF86AudioLowerVolume + /* 115, 0x073 */ 0x1008FF13, // XF86AudioRaiseVolume + /* 116, 0x074 */ 0x1008FF2A, // XF86PowerOff + /* 117, 0x075 */ 0xFFBD, // KP_Equal + /* 118, 0x076 */ 0xB1, // plusminus + /* 119, 0x077 */ 0xFF13, // Pause + /* 120, 0x078 */ 0x1008FF4A, // XF86LaunchA + /* 121, 0x079 */ 0xFFAC, // KP_Separator + /* 122, 0x07a */ 0xFF31, // Hangul + /* 123, 0x07b */ 0xFF34, // Hangul_Hanja + /* 124, 0x07c */ 0x0, // NoSymbol + /* 125, 0x07d */ 0xFFE7, // Meta_L + /* 126, 0x07e */ 0xFFE8, // Meta_R + /* 127, 0x07f */ 0xFF67, // Menu + /* 128, 0x080 */ 0x00, // NoSymbol + /* 129, 0x081 */ 0xFF66, // Redo + /* 130, 0x082 */ 0x1005FF70, // SunProps + /* 131, 0x083 */ 0xFF65, // Undo + /* 132, 0x084 */ 0x1005FF71, // SunFront + /* 133, 0x085 */ 0x1008FF57, // XF86Copy + /* 134, 0x086 */ 0x1008FF6B, // XF86Open + /* 135, 0x087 */ 0x1008FF6D, // XF86Paste + /* 136, 0x088 */ 0xFF68, // Find + /* 137, 0x089 */ 0x1008FF58, // XF86Cut + /* 138, 0x08a */ 0xFF6A, // Help + /* 139, 0x08b */ 0xFF67, // Menu + /* 140, 0x08c */ 0x1008FF1D, // XF86Calculator + /* 141, 0x08d */ 0x0, // NoSymbol + /* 142, 0x08e */ 0x1008FF2F, // XF86Sleep + /* 143, 0x08f */ 0x1008FF2B, // XF86WakeUp + /* 144, 0x090 */ 0x1008FF5D, // XF86Explorer + /* 145, 0x091 */ 0x1008FF7B, // XF86Send + /* 146, 0x092 */ 0x0, // NoSymbol + /* 147, 0x093 */ 0x1008FF8A, // XF86Xfer + /* 148, 0x094 */ 0x1008FF41, // XF86Launch1 + /* 149, 0x095 */ 0x1008FF42, // XF86Launch2 + /* 150, 0x096 */ 0x1008FF2E, // XF86WWW + /* 151, 0x097 */ 0x1008FF5A, // XF86DOS + /* 152, 0x098 */ 0x1008FF2D, // XF86ScreenSaver + /* 153, 0x099 */ 0x1008FF74, // XF86RotateWindows + /* 154, 0x09a */ 0x1008FF7F, // XF86TaskPane + /* 155, 0x09b */ 0x1008FF19, // XF86Mail + /* 156, 0x09c */ 0x1008FF30, // XF86Favorites + /* 157, 0x09d */ 0x1008FF33, // XF86MyComputer + /* 158, 0x09e */ 0x1008FF26, // XF86Back + /* 159, 0x09f */ 0x1008FF27, // XF86Forward + /* 160, 0x0a0 */ 0x0, // NoSymbol + /* 161, 0x0a1 */ 0x1008FF2C, // XF86Eject + /* 162, 0x0a2 */ 0x1008FF2C, // XF86Eject + /* 163, 0x0a3 */ 0x1008FF17, // XF86AudioNext + /* 164, 0x0a4 */ 0x1008FF14, // XF86AudioPlay + /* 165, 0x0a5 */ 0x1008FF16, // XF86AudioPrev + /* 166, 0x0a6 */ 0x1008FF15, // XF86AudioStop + /* 167, 0x0a7 */ 0x1008FF1C, // XF86AudioRecord + /* 168, 0x0a8 */ 0x1008FF3E, // XF86AudioRewind + /* 169, 0x0a9 */ 0x1008FF6E, // XF86Phone + /* 170, 0x0aa */ 0x0, // NoSymbol + /* 171, 0x0ab */ 0x1008FF81, // XF86Tools + /* 172, 0x0ac */ 0x1008FF18, // XF86HomePage + /* 173, 0x0ad */ 0x1008FF73, // XF86Reload + /* 174, 0x0ae */ 0x1008FF56, // XF86Close + /* 175, 0x0af */ 0x0, // NoSymbol + /* 176, 0x0b0 */ 0x0, // NoSymbol + /* 177, 0x0b1 */ 0x1008FF78, // XF86ScrollUp + /* 178, 0x0b2 */ 0x1008FF79, // XF86ScrollDown + /* 179, 0x0b3 */ 0x0, // NoSymbol + /* 180, 0x0b4 */ 0x0, // NoSymbol + /* 181, 0x0b5 */ 0x1008FF68, // XF86New + /* 182, 0x0b6 */ 0xFF66, // Redo + /* 183, 0x0b7 */ 0xFFCA, // F13 + /* 184, 0x0b8 */ 0xFFCB, // F14 + /* 185, 0x0b9 */ 0xFFCC, // F15 + /* 186, 0x0ba */ 0xFFCD, // F16 + /* 187, 0x0bb */ 0xFFCE, // F17 + /* 188, 0x0bc */ 0xFFCF, // F18 + /* 189, 0x0bd */ 0xFFD0, // F19 + /* 190, 0x0be */ 0xFFD1, // F20 + /* 191, 0x0bf */ 0xFFD2, // F21 + /* 192, 0x0c0 */ 0xFFD3, // F22 + /* 193, 0x0c1 */ 0xFFD4, // F23 + /* 194, 0x0c2 */ 0xFFD5, // F24 + /* 195, 0x0c3 */ 0x0, // NoSymbol + /* 196, 0x0c4 */ 0x0, // NoSymbol + /* 197, 0x0c5 */ 0x0, // NoSymbol + /* 198, 0x0c6 */ 0x0, // NoSymbol + /* 199, 0x0c7 */ 0x0, // NoSymbol + /* 200, 0x0c8 */ 0x1008FF14, // XF86AudioPlay + /* 201, 0x0c9 */ 0x1008FF31, // XF86AudioPause + /* 202, 0x0ca */ 0x1008FF43, // XF86Launch3 + /* 203, 0x0cb */ 0x1008FF44, // XF86Launch4 + /* 204, 0x0cc */ 0x1008FF4B, // XF86LaunchB + /* 205, 0x0cd */ 0x1008FFA7, // XF86Suspend + /* 206, 0x0ce */ 0x1008FF56, // XF86Close + /* 207, 0x0cf */ 0x1008FF14, // XF86AudioPlay + /* 208, 0x0d0 */ 0x1008FF97, // XF86AudioForward + /* 209, 0x0d1 */ 0x0, // NoSymbol + /* 210, 0x0d2 */ 0xFF61, // Print + /* 211, 0x0d3 */ 0x0, // NoSymbol + /* 212, 0x0d4 */ 0x1008FF8F, // XF86WebCam + /* 213, 0x0d5 */ 0x1008FFB6, // XF86AudioPreset + /* 214, 0x0d6 */ 0x0, // NoSymbol + /* 215, 0x0d7 */ 0x1008FF19, // XF86Mail + /* 216, 0x0d8 */ 0x1008FF8E, // XF86Messenger + /* 217, 0x0d9 */ 0x1008FF1B, // XF86Search + /* 218, 0x0da */ 0x1008FF5F, // XF86Go + /* 219, 0x0db */ 0x1008FF3C, // XF86Finance + /* 220, 0x0dc */ 0x1008FF5E, // XF86Game + /* 221, 0x0dd */ 0x1008FF36, // XF86Shop + /* 222, 0x0de */ 0x0, // NoSymbol + /* 223, 0x0df */ 0xFF69, // Cancel + /* 224, 0x0e0 */ 0x1008FF03, // XF86MonBrightnessDown + /* 225, 0x0e1 */ 0x1008FF02, // XF86MonBrightnessUp + /* 226, 0x0e2 */ 0x1008FF32, // XF86AudioMedia + /* 227, 0x0e3 */ 0x1008FF59, // XF86Display + /* 228, 0x0e4 */ 0x1008FF04, // XF86KbdLightOnOff + /* 229, 0x0e5 */ 0x1008FF06, // XF86KbdBrightnessDown + /* 230, 0x0e6 */ 0x1008FF05, // XF86KbdBrightnessUp + /* 231, 0x0e7 */ 0x1008FF7B, // XF86Send + /* 232, 0x0e8 */ 0x1008FF72, // XF86Reply + /* 233, 0x0e9 */ 0x1008FF90, // XF86MailForward + /* 234, 0x0ea */ 0x1008FF77, // XF86Save + /* 235, 0x0eb */ 0x1008FF5B, // XF86Documents + /* 236, 0x0ec */ 0x1008FF93, // XF86Battery + /* 237, 0x0ed */ 0x1008FF94, // XF86Bluetooth + /* 238, 0x0ee */ 0x1008FF95, // XF86WLAN + /* 239, 0x0ef */ 0x1008FF96, // XF86UWB + /* 240, 0x0f0 */ 0x0, // NoSymbol + /* 241, 0x0f1 */ 0x1008FE22, // XF86Next_VMode + /* 242, 0x0f2 */ 0x1008FE23, // XF86Prev_VMode + /* 243, 0x0f3 */ 0x1008FF07, // XF86MonBrightnessCycle + /* 244, 0x0f4 */ 0x100810F4, // XF86BrightnessAuto + /* 245, 0x0f5 */ 0x100810F5, // XF86DisplayOff + /* 246, 0x0f6 */ 0x1008FFB4, // XF86WWAN + /* 247, 0x0f7 */ 0x1008FFB5, // XF86RFKill +}; + +#if 0 // Here is a script to generate the ExtendedLinuxKeycodeKeysyms table +#!/bin/bash + +function process_line +{ + sym=$(echo "$1" | awk '{print $3}') + code=$(echo "$1" | sed 's,.*_EVDEVK(\(0x[0-9A-Fa-f]*\)).*,\1,') + value=$(grep -E "#define ${sym}\s" -R /usr/include/X11 | awk '{print $3}') + printf " { 0x%.8X, 0x%.3x }, /* $sym */\n" $value $code +} + +grep -F "/* Use: " /usr/include/xkbcommon/xkbcommon-keysyms.h | grep -F _EVDEVK | while read line; do + process_line "$line" +done +#endif + +static const struct { + Uint32 keysym; + int linux_keycode; +} ExtendedLinuxKeycodeKeysyms[] = { + { 0x1008FF2C, 0x0a2 }, // XF86XK_Eject + { 0x1008FF68, 0x0b5 }, // XF86XK_New + { 0x0000FF66, 0x0b6 }, // XK_Redo + { 0x1008FF4B, 0x0cc }, // XF86XK_LaunchB + { 0x1008FF59, 0x0e3 }, // XF86XK_Display + { 0x1008FF04, 0x0e4 }, // XF86XK_KbdLightOnOff + { 0x1008FF06, 0x0e5 }, // XF86XK_KbdBrightnessDown + { 0x1008FF05, 0x0e6 }, // XF86XK_KbdBrightnessUp + { 0x1008FF7B, 0x0e7 }, // XF86XK_Send + { 0x1008FF72, 0x0e8 }, // XF86XK_Reply + { 0x1008FF90, 0x0e9 }, // XF86XK_MailForward + { 0x1008FF77, 0x0ea }, // XF86XK_Save + { 0x1008FF5B, 0x0eb }, // XF86XK_Documents + { 0x1008FF93, 0x0ec }, // XF86XK_Battery + { 0x1008FF94, 0x0ed }, // XF86XK_Bluetooth + { 0x1008FF95, 0x0ee }, // XF86XK_WLAN + { 0x1008FF96, 0x0ef }, // XF86XK_UWB + { 0x1008FE22, 0x0f1 }, // XF86XK_Next_VMode + { 0x1008FE23, 0x0f2 }, // XF86XK_Prev_VMode + { 0x1008FF07, 0x0f3 }, // XF86XK_MonBrightnessCycle + { 0x1008FFB4, 0x0f6 }, // XF86XK_WWAN + { 0x1008FFB5, 0x0f7 }, // XF86XK_RFKill + { 0x1008FFB2, 0x0f8 }, // XF86XK_AudioMicMute + { 0x1008FF9C, 0x173 }, // XF86XK_CycleAngle + { 0x1008FFB8, 0x174 }, // XF86XK_FullScreen + { 0x1008FF87, 0x189 }, // XF86XK_Video + { 0x1008FF20, 0x18d }, // XF86XK_Calendar + { 0x1008FF99, 0x19a }, // XF86XK_AudioRandomPlay + { 0x1008FF5E, 0x1a1 }, // XF86XK_Game + { 0x1008FF8B, 0x1a2 }, // XF86XK_ZoomIn + { 0x1008FF8C, 0x1a3 }, // XF86XK_ZoomOut + { 0x1008FF89, 0x1a5 }, // XF86XK_Word + { 0x1008FF5C, 0x1a7 }, // XF86XK_Excel + { 0x1008FF69, 0x1ab }, // XF86XK_News + { 0x1008FF8E, 0x1ae }, // XF86XK_Messenger + { 0x1008FF61, 0x1b1 }, // XF86XK_LogOff + { 0x00000024, 0x1b2 }, // XK_dollar + { 0x000020AC, 0x1b3 }, // XK_EuroSign + { 0x1008FF9D, 0x1b4 }, // XF86XK_FrameBack + { 0x1008FF9E, 0x1b5 }, // XF86XK_FrameForward + { 0x0000FFF1, 0x1f1 }, // XK_braille_dot_1 + { 0x0000FFF2, 0x1f2 }, // XK_braille_dot_2 + { 0x0000FFF3, 0x1f3 }, // XK_braille_dot_3 + { 0x0000FFF4, 0x1f4 }, // XK_braille_dot_4 + { 0x0000FFF5, 0x1f5 }, // XK_braille_dot_5 + { 0x0000FFF6, 0x1f6 }, // XK_braille_dot_6 + { 0x0000FFF7, 0x1f7 }, // XK_braille_dot_7 + { 0x0000FFF8, 0x1f8 }, // XK_braille_dot_8 + { 0x0000FFF9, 0x1f9 }, // XK_braille_dot_9 + { 0x0000FFF1, 0x1fa }, // XK_braille_dot_1 + { 0x1008FFA9, 0x212 }, // XF86XK_TouchpadToggle + { 0x1008FFB0, 0x213 }, // XF86XK_TouchpadOn + { 0x1008FFB1, 0x214 }, // XF86XK_TouchpadOff + { 0x1008FFB7, 0x231 }, // XF86XK_RotationLockToggle + { 0x0000FE08, 0x248 }, // XK_ISO_Next_Group +}; +/* *INDENT-ON* */ // clang-format on + +SDL_Scancode SDL_GetScancodeFromKeySym(Uint32 keysym, Uint32 keycode) +{ + int i; + Uint32 linux_keycode = 0; + + // First check our custom list + for (i = 0; i < SDL_arraysize(KeySymToSDLScancode); ++i) { + if (keysym == KeySymToSDLScancode[i].keysym) { + return KeySymToSDLScancode[i].scancode; + } + } + + if (keysym >= 0x41 && keysym <= 0x5a) { + // Normalize alphabetic keysyms to the lowercase form + keysym += 0x20; + } else if (keysym >= 0x10081000 && keysym <= 0x10081FFF) { + /* The rest of the keysyms map to Linux keycodes, so use that mapping + * Per xkbcommon-keysyms.h, this is actually a linux keycode. + */ + linux_keycode = (keysym - 0x10081000); + } + if (!linux_keycode) { + // See if this keysym is an exact match in our table + i = (keycode - 8); + if (i >= 0 && i < SDL_arraysize(LinuxKeycodeKeysyms) && keysym == LinuxKeycodeKeysyms[i]) { + linux_keycode = i; + } else { + // Scan the table for this keysym + for (i = 0; i < SDL_arraysize(LinuxKeycodeKeysyms); ++i) { + if (keysym == LinuxKeycodeKeysyms[i]) { + linux_keycode = i; + break; + } + } + } + } + if (!linux_keycode) { + // Scan the extended table for this keysym + for (i = 0; i < SDL_arraysize(ExtendedLinuxKeycodeKeysyms); ++i) { + if (keysym == ExtendedLinuxKeycodeKeysyms[i].keysym) { + linux_keycode = ExtendedLinuxKeycodeKeysyms[i].linux_keycode; + break; + } + } + } + return SDL_GetScancodeFromTable(SDL_SCANCODE_TABLE_LINUX, linux_keycode); +} + +#endif // SDL_VIDEO_DRIVER_WAYLAND diff --git a/contrib/SDL-3.2.8/src/events/SDL_keysym_to_scancode_c.h b/contrib/SDL-3.2.8/src/events/SDL_keysym_to_scancode_c.h new file mode 100644 index 0000000..8d0e214 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_keysym_to_scancode_c.h @@ -0,0 +1,28 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_keysym_to_scancode_c_h_ +#define SDL_keysym_to_scancode_c_h_ + +// This function only correctly maps letters and numbers for keyboards in US QWERTY layout +extern SDL_Scancode SDL_GetScancodeFromKeySym(Uint32 keysym, Uint32 keycode); + +#endif // SDL_keysym_to_scancode_c_h_ diff --git a/contrib/SDL-3.2.8/src/events/SDL_mouse.c b/contrib/SDL-3.2.8/src/events/SDL_mouse.c new file mode 100644 index 0000000..2ea5995 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_mouse.c @@ -0,0 +1,1673 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// General mouse handling code for SDL + +#include "../SDL_hints_c.h" +#include "../video/SDL_sysvideo.h" +#include "SDL_events_c.h" +#include "SDL_mouse_c.h" +#if defined(SDL_PLATFORM_WINDOWS) +#include "../core/windows/SDL_windows.h" // For GetDoubleClickTime() +#endif + +// #define DEBUG_MOUSE + +#define WARP_EMULATION_THRESHOLD_NS SDL_MS_TO_NS(30) + +typedef struct SDL_MouseInstance +{ + SDL_MouseID instance_id; + char *name; +} SDL_MouseInstance; + +// The mouse state +static SDL_Mouse SDL_mouse; +static int SDL_mouse_count; +static SDL_MouseInstance *SDL_mice; + +// for mapping mouse events to touch +static bool track_mouse_down = false; + +static void SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, bool relative, float x, float y); + +static void SDLCALL SDL_MouseDoubleClickTimeChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + + if (hint && *hint) { + mouse->double_click_time = SDL_atoi(hint); + } else { +#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) + mouse->double_click_time = GetDoubleClickTime(); +#else + mouse->double_click_time = 500; +#endif + } +} + +static void SDLCALL SDL_MouseDoubleClickRadiusChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + + if (hint && *hint) { + mouse->double_click_radius = SDL_atoi(hint); + } else { + mouse->double_click_radius = 32; // 32 pixels seems about right for touch interfaces + } +} + +static void SDLCALL SDL_MouseNormalSpeedScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + + if (hint && *hint) { + mouse->enable_normal_speed_scale = true; + mouse->normal_speed_scale = (float)SDL_atof(hint); + } else { + mouse->enable_normal_speed_scale = false; + mouse->normal_speed_scale = 1.0f; + } +} + +static void SDLCALL SDL_MouseRelativeSpeedScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + + if (hint && *hint) { + mouse->enable_relative_speed_scale = true; + mouse->relative_speed_scale = (float)SDL_atof(hint); + } else { + mouse->enable_relative_speed_scale = false; + mouse->relative_speed_scale = 1.0f; + } +} + +static void SDLCALL SDL_MouseRelativeModeCenterChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + + mouse->relative_mode_center = SDL_GetStringBoolean(hint, true); +} + +static void SDLCALL SDL_MouseRelativeSystemScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + + mouse->enable_relative_system_scale = SDL_GetStringBoolean(hint, false); +} + +static void SDLCALL SDL_MouseWarpEmulationChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + + mouse->warp_emulation_hint = SDL_GetStringBoolean(hint, true); + + if (!mouse->warp_emulation_hint && mouse->warp_emulation_active) { + SDL_SetRelativeMouseMode(false); + mouse->warp_emulation_active = false; + } +} + +static void SDLCALL SDL_TouchMouseEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + + mouse->touch_mouse_events = SDL_GetStringBoolean(hint, true); +} + +#ifdef SDL_PLATFORM_VITA +static void SDLCALL SDL_VitaTouchMouseDeviceChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + if (hint) { + switch (*hint) { + default: + case '0': + mouse->vita_touch_mouse_device = 1; + break; + case '1': + mouse->vita_touch_mouse_device = 2; + break; + case '2': + mouse->vita_touch_mouse_device = 3; + break; + } + } +} +#endif + +static void SDLCALL SDL_MouseTouchEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + bool default_value; + +#if defined(SDL_PLATFORM_ANDROID) || (defined(SDL_PLATFORM_IOS) && !defined(SDL_PLATFORM_TVOS)) + default_value = true; +#else + default_value = false; +#endif + mouse->mouse_touch_events = SDL_GetStringBoolean(hint, default_value); + + if (mouse->mouse_touch_events) { + if (!mouse->added_mouse_touch_device) { + SDL_AddTouch(SDL_MOUSE_TOUCHID, SDL_TOUCH_DEVICE_DIRECT, "mouse_input"); + mouse->added_mouse_touch_device = true; + } + } else { + if (mouse->added_mouse_touch_device) { + SDL_DelTouch(SDL_MOUSE_TOUCHID); + mouse->added_mouse_touch_device = false; + } + } +} + +static void SDLCALL SDL_PenMouseEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + + mouse->pen_mouse_events = SDL_GetStringBoolean(hint, true); +} + +static void SDLCALL SDL_PenTouchEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + + mouse->pen_touch_events = SDL_GetStringBoolean(hint, true); + + if (mouse->pen_touch_events) { + if (!mouse->added_pen_touch_device) { + SDL_AddTouch(SDL_PEN_TOUCHID, SDL_TOUCH_DEVICE_DIRECT, "pen_input"); + mouse->added_pen_touch_device = true; + } + } else { + if (mouse->added_pen_touch_device) { + SDL_DelTouch(SDL_PEN_TOUCHID); + mouse->added_pen_touch_device = false; + } + } +} + +static void SDLCALL SDL_MouseAutoCaptureChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + bool auto_capture = SDL_GetStringBoolean(hint, true); + + if (auto_capture != mouse->auto_capture) { + mouse->auto_capture = auto_capture; + SDL_UpdateMouseCapture(false); + } +} + +static void SDLCALL SDL_MouseRelativeWarpMotionChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + + mouse->relative_mode_warp_motion = SDL_GetStringBoolean(hint, false); +} + +static void SDLCALL SDL_MouseRelativeCursorVisibleChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + + mouse->relative_mode_cursor_visible = SDL_GetStringBoolean(hint, false); + + SDL_SetCursor(NULL); // Update cursor visibility +} + +// Public functions +bool SDL_PreInitMouse(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + SDL_zerop(mouse); + + SDL_AddHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_TIME, + SDL_MouseDoubleClickTimeChanged, mouse); + + SDL_AddHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS, + SDL_MouseDoubleClickRadiusChanged, mouse); + + SDL_AddHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE, + SDL_MouseNormalSpeedScaleChanged, mouse); + + SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE, + SDL_MouseRelativeSpeedScaleChanged, mouse); + + SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE, + SDL_MouseRelativeSystemScaleChanged, mouse); + + SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, + SDL_MouseRelativeModeCenterChanged, mouse); + + SDL_AddHintCallback(SDL_HINT_MOUSE_EMULATE_WARP_WITH_RELATIVE, + SDL_MouseWarpEmulationChanged, mouse); + + SDL_AddHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS, + SDL_TouchMouseEventsChanged, mouse); + +#ifdef SDL_PLATFORM_VITA + SDL_AddHintCallback(SDL_HINT_VITA_TOUCH_MOUSE_DEVICE, + SDL_VitaTouchMouseDeviceChanged, mouse); +#endif + + SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS, + SDL_MouseTouchEventsChanged, mouse); + + SDL_AddHintCallback(SDL_HINT_PEN_MOUSE_EVENTS, + SDL_PenMouseEventsChanged, mouse); + + SDL_AddHintCallback(SDL_HINT_PEN_TOUCH_EVENTS, + SDL_PenTouchEventsChanged, mouse); + + SDL_AddHintCallback(SDL_HINT_MOUSE_AUTO_CAPTURE, + SDL_MouseAutoCaptureChanged, mouse); + + SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION, + SDL_MouseRelativeWarpMotionChanged, mouse); + + SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE, + SDL_MouseRelativeCursorVisibleChanged, mouse); + + mouse->was_touch_mouse_events = false; // no touch to mouse movement event pending + + mouse->cursor_shown = true; + + return true; +} + +void SDL_PostInitMouse(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + /* Create a dummy mouse cursor for video backends that don't support true cursors, + * so that mouse grab and focus functionality will work. + */ + if (!mouse->def_cursor) { + SDL_Surface *surface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_ARGB8888); + if (surface) { + SDL_memset(surface->pixels, 0, (size_t)surface->h * surface->pitch); + SDL_SetDefaultCursor(SDL_CreateColorCursor(surface, 0, 0)); + SDL_DestroySurface(surface); + } + } +} + +bool SDL_IsMouse(Uint16 vendor, Uint16 product) +{ + // Eventually we'll have a blacklist of devices that enumerate as mice but aren't really + return true; +} + +static int SDL_GetMouseIndex(SDL_MouseID mouseID) +{ + for (int i = 0; i < SDL_mouse_count; ++i) { + if (mouseID == SDL_mice[i].instance_id) { + return i; + } + } + return -1; +} + +void SDL_AddMouse(SDL_MouseID mouseID, const char *name, bool send_event) +{ + int mouse_index = SDL_GetMouseIndex(mouseID); + if (mouse_index >= 0) { + // We already know about this mouse + return; + } + + SDL_assert(mouseID != 0); + + SDL_MouseInstance *mice = (SDL_MouseInstance *)SDL_realloc(SDL_mice, (SDL_mouse_count + 1) * sizeof(*mice)); + if (!mice) { + return; + } + SDL_MouseInstance *instance = &mice[SDL_mouse_count]; + instance->instance_id = mouseID; + instance->name = SDL_strdup(name ? name : ""); + SDL_mice = mice; + ++SDL_mouse_count; + + if (send_event) { + SDL_Event event; + SDL_zero(event); + event.type = SDL_EVENT_MOUSE_ADDED; + event.mdevice.which = mouseID; + SDL_PushEvent(&event); + } +} + +void SDL_RemoveMouse(SDL_MouseID mouseID, bool send_event) +{ + int mouse_index = SDL_GetMouseIndex(mouseID); + if (mouse_index < 0) { + // We don't know about this mouse + return; + } + + SDL_free(SDL_mice[mouse_index].name); + + if (mouse_index != SDL_mouse_count - 1) { + SDL_memmove(&SDL_mice[mouse_index], &SDL_mice[mouse_index + 1], (SDL_mouse_count - mouse_index - 1) * sizeof(SDL_mice[mouse_index])); + } + --SDL_mouse_count; + + // Remove any mouse input sources for this mouseID + SDL_Mouse *mouse = SDL_GetMouse(); + for (int i = 0; i < mouse->num_sources; ++i) { + SDL_MouseInputSource *source = &mouse->sources[i]; + if (source->mouseID == mouseID) { + SDL_free(source->clickstate); + if (i != mouse->num_sources - 1) { + SDL_memmove(&mouse->sources[i], &mouse->sources[i + 1], (mouse->num_sources - i - 1) * sizeof(mouse->sources[i])); + } + --mouse->num_sources; + break; + } + } + + if (send_event) { + SDL_Event event; + SDL_zero(event); + event.type = SDL_EVENT_MOUSE_REMOVED; + event.mdevice.which = mouseID; + SDL_PushEvent(&event); + } +} + +bool SDL_HasMouse(void) +{ + return (SDL_mouse_count > 0); +} + +SDL_MouseID *SDL_GetMice(int *count) +{ + int i; + SDL_MouseID *mice; + + mice = (SDL_JoystickID *)SDL_malloc((SDL_mouse_count + 1) * sizeof(*mice)); + if (mice) { + if (count) { + *count = SDL_mouse_count; + } + + for (i = 0; i < SDL_mouse_count; ++i) { + mice[i] = SDL_mice[i].instance_id; + } + mice[i] = 0; + } else { + if (count) { + *count = 0; + } + } + + return mice; +} + +const char *SDL_GetMouseNameForID(SDL_MouseID instance_id) +{ + int mouse_index = SDL_GetMouseIndex(instance_id); + if (mouse_index < 0) { + SDL_SetError("Mouse %" SDL_PRIu32 " not found", instance_id); + return NULL; + } + return SDL_GetPersistentString(SDL_mice[mouse_index].name); +} + +void SDL_SetDefaultCursor(SDL_Cursor *cursor) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (cursor == mouse->def_cursor) { + return; + } + + if (mouse->def_cursor) { + SDL_Cursor *default_cursor = mouse->def_cursor; + SDL_Cursor *prev, *curr; + + if (mouse->cur_cursor == mouse->def_cursor) { + mouse->cur_cursor = NULL; + } + mouse->def_cursor = NULL; + + for (prev = NULL, curr = mouse->cursors; curr; + prev = curr, curr = curr->next) { + if (curr == default_cursor) { + if (prev) { + prev->next = curr->next; + } else { + mouse->cursors = curr->next; + } + + break; + } + } + + if (mouse->FreeCursor && default_cursor->internal) { + mouse->FreeCursor(default_cursor); + } else { + SDL_free(default_cursor); + } + } + + mouse->def_cursor = cursor; + + if (!mouse->cur_cursor) { + SDL_SetCursor(cursor); + } +} + +SDL_SystemCursor SDL_GetDefaultSystemCursor(void) +{ + SDL_SystemCursor id = SDL_SYSTEM_CURSOR_DEFAULT; + const char *value = SDL_GetHint(SDL_HINT_MOUSE_DEFAULT_SYSTEM_CURSOR); + if (value) { + int index = SDL_atoi(value); + if (0 <= index && index < SDL_SYSTEM_CURSOR_COUNT) { + id = (SDL_SystemCursor)index; + } + } + return id; +} + +SDL_Mouse *SDL_GetMouse(void) +{ + return &SDL_mouse; +} + +static SDL_MouseButtonFlags SDL_GetMouseButtonState(SDL_Mouse *mouse, SDL_MouseID mouseID, bool include_touch) +{ + int i; + SDL_MouseButtonFlags buttonstate = 0; + + for (i = 0; i < mouse->num_sources; ++i) { + if (mouseID == SDL_GLOBAL_MOUSE_ID || mouseID == SDL_TOUCH_MOUSEID) { + if (include_touch || mouse->sources[i].mouseID != SDL_TOUCH_MOUSEID) { + buttonstate |= mouse->sources[i].buttonstate; + } + } else { + if (mouseID == mouse->sources[i].mouseID) { + buttonstate |= mouse->sources[i].buttonstate; + break; + } + } + } + return buttonstate; +} + +SDL_Window *SDL_GetMouseFocus(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + return mouse->focus; +} + +/* TODO RECONNECT: Hello from the Wayland video driver! + * This was once removed from SDL, but it's been added back in comment form + * because we will need it when Wayland adds compositor reconnect support. + * If you need this before we do, great! Otherwise, leave this alone, we'll + * uncomment it at the right time. + * -flibit + */ +#if 0 +void SDL_ResetMouse(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + Uint32 buttonState = SDL_GetMouseButtonState(mouse, SDL_GLOBAL_MOUSE_ID, false); + int i; + + for (i = 1; i <= sizeof(buttonState)*8; ++i) { + if (buttonState & SDL_BUTTON_MASK(i)) { + SDL_SendMouseButton(0, mouse->focus, mouse->mouseID, i, false); + } + } + SDL_assert(SDL_GetMouseButtonState(mouse, SDL_GLOBAL_MOUSE_ID, false) == 0); +} +#endif // 0 + +void SDL_SetMouseFocus(SDL_Window *window) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (mouse->focus == window) { + return; + } + + /* Actually, this ends up being a bad idea, because most operating + systems have an implicit grab when you press the mouse button down + so you can drag things out of the window and then get the mouse up + when it happens. So, #if 0... + */ +#if 0 + if (mouse->focus && !window) { + // We won't get anymore mouse messages, so reset mouse state + SDL_ResetMouse(); + } +#endif + + // See if the current window has lost focus + if (mouse->focus) { + SDL_SendWindowEvent(mouse->focus, SDL_EVENT_WINDOW_MOUSE_LEAVE, 0, 0); + } + + mouse->focus = window; + mouse->has_position = false; + + if (mouse->focus) { + SDL_SendWindowEvent(mouse->focus, SDL_EVENT_WINDOW_MOUSE_ENTER, 0, 0); + } + + // Update cursor visibility + SDL_SetCursor(NULL); +} + +bool SDL_MousePositionInWindow(SDL_Window *window, float x, float y) +{ + if (!window) { + return false; + } + + if (window && !(window->flags & SDL_WINDOW_MOUSE_CAPTURE)) { + if (x < 0.0f || y < 0.0f || x >= (float)window->w || y >= (float)window->h) { + return false; + } + } + return true; +} + +// Check to see if we need to synthesize focus events +static bool SDL_UpdateMouseFocus(SDL_Window *window, float x, float y, Uint32 buttonstate, bool send_mouse_motion) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + bool inWindow = SDL_MousePositionInWindow(window, x, y); + + if (!inWindow) { + if (window == mouse->focus) { +#ifdef DEBUG_MOUSE + SDL_Log("Mouse left window, synthesizing move & focus lost event"); +#endif + if (send_mouse_motion) { + SDL_PrivateSendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, false, x, y); + } + SDL_SetMouseFocus(NULL); + } + return false; + } + + if (window != mouse->focus) { +#ifdef DEBUG_MOUSE + SDL_Log("Mouse entered window, synthesizing focus gain & move event"); +#endif + SDL_SetMouseFocus(window); + if (send_mouse_motion) { + SDL_PrivateSendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, false, x, y); + } + } + return true; +} + +void SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, bool relative, float x, float y) +{ + if (window && !relative) { + SDL_Mouse *mouse = SDL_GetMouse(); + if (!SDL_UpdateMouseFocus(window, x, y, SDL_GetMouseButtonState(mouse, mouseID, true), (mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID))) { + return; + } + } + + SDL_PrivateSendMouseMotion(timestamp, window, mouseID, relative, x, y); +} + +static void ConstrainMousePosition(SDL_Mouse *mouse, SDL_Window *window, float *x, float *y) +{ + /* make sure that the pointers find themselves inside the windows, + unless we have the mouse captured. */ + if (window && !(window->flags & SDL_WINDOW_MOUSE_CAPTURE)) { + int x_min = 0, x_max = window->w - 1; + int y_min = 0, y_max = window->h - 1; + const SDL_Rect *confine = SDL_GetWindowMouseRect(window); + + if (confine) { + SDL_Rect window_rect; + SDL_Rect mouse_rect; + + window_rect.x = 0; + window_rect.y = 0; + window_rect.w = x_max + 1; + window_rect.h = y_max + 1; + if (SDL_GetRectIntersection(confine, &window_rect, &mouse_rect)) { + x_min = mouse_rect.x; + y_min = mouse_rect.y; + x_max = x_min + mouse_rect.w - 1; + y_max = y_min + mouse_rect.h - 1; + } + } + + if (*x >= (float)(x_max + 1)) { + *x = SDL_max((float)x_max, mouse->last_x); + } + if (*x < (float)x_min) { + *x = (float)x_min; + } + + if (*y >= (float)(y_max + 1)) { + *y = SDL_max((float)y_max, mouse->last_y); + } + if (*y < (float)y_min) { + *y = (float)y_min; + } + } +} + +static void SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, bool relative, float x, float y) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + float xrel = 0.0f; + float yrel = 0.0f; + bool window_is_relative = mouse->focus && (mouse->focus->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE); + + // SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events + if (mouse->mouse_touch_events) { + if (mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID && !relative && track_mouse_down) { + if (window) { + float normalized_x = x / (float)window->w; + float normalized_y = y / (float)window->h; + SDL_SendTouchMotion(timestamp, SDL_MOUSE_TOUCHID, SDL_BUTTON_LEFT, window, normalized_x, normalized_y, 1.0f); + } + } + } + + // SDL_HINT_TOUCH_MOUSE_EVENTS: if not set, discard synthetic mouse events coming from platform layer + if (!mouse->touch_mouse_events && mouseID == SDL_TOUCH_MOUSEID) { + return; + } + + if (relative) { + if (mouse->relative_mode) { + if (mouse->enable_relative_system_scale) { + if (mouse->ApplySystemScale) { + mouse->ApplySystemScale(mouse->system_scale_data, timestamp, window, mouseID, &x, &y); + } + } + if (mouse->enable_relative_speed_scale) { + x *= mouse->relative_speed_scale; + y *= mouse->relative_speed_scale; + } + } else { + if (mouse->enable_normal_speed_scale) { + x *= mouse->normal_speed_scale; + y *= mouse->normal_speed_scale; + } + } + xrel = x; + yrel = y; + x = (mouse->last_x + xrel); + y = (mouse->last_y + yrel); + ConstrainMousePosition(mouse, window, &x, &y); + } else { + ConstrainMousePosition(mouse, window, &x, &y); + if (mouse->has_position) { + xrel = x - mouse->last_x; + yrel = y - mouse->last_y; + } + } + + if (mouse->has_position && xrel == 0.0f && yrel == 0.0f) { // Drop events that don't change state +#ifdef DEBUG_MOUSE + SDL_Log("Mouse event didn't change state - dropped!"); +#endif + return; + } + + // Ignore relative motion positioning the first touch + if (mouseID == SDL_TOUCH_MOUSEID && !SDL_GetMouseButtonState(mouse, mouseID, true)) { + xrel = 0.0f; + yrel = 0.0f; + } + + // modify internal state + { + mouse->x_accu += xrel; + mouse->y_accu += yrel; + + if (relative && mouse->has_position) { + mouse->x += xrel; + mouse->y += yrel; + ConstrainMousePosition(mouse, window, &mouse->x, &mouse->y); + } else { + mouse->x = x; + mouse->y = y; + } + mouse->has_position = true; + + // Use unclamped values if we're getting events outside the window + mouse->last_x = relative ? mouse->x : x; + mouse->last_y = relative ? mouse->y : y; + + mouse->click_motion_x += xrel; + mouse->click_motion_y += yrel; + } + + // Move the mouse cursor, if needed + if (mouse->cursor_shown && !mouse->relative_mode && + mouse->MoveCursor && mouse->cur_cursor) { + mouse->MoveCursor(mouse->cur_cursor); + } + + // Post the event, if desired + if (SDL_EventEnabled(SDL_EVENT_MOUSE_MOTION)) { + if ((!mouse->relative_mode || mouse->warp_emulation_active) && mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID) { + // We're not in relative mode, so all mouse events are global mouse events + mouseID = SDL_GLOBAL_MOUSE_ID; + } + + if (!relative && window_is_relative) { + if (!mouse->relative_mode_warp_motion) { + return; + } + xrel = 0.0f; + yrel = 0.0f; + } + + SDL_Event event; + event.type = SDL_EVENT_MOUSE_MOTION; + event.common.timestamp = timestamp; + event.motion.windowID = mouse->focus ? mouse->focus->id : 0; + event.motion.which = mouseID; + // Set us pending (or clear during a normal mouse movement event) as having triggered + mouse->was_touch_mouse_events = (mouseID == SDL_TOUCH_MOUSEID); + event.motion.state = SDL_GetMouseButtonState(mouse, mouseID, true); + event.motion.x = mouse->x; + event.motion.y = mouse->y; + event.motion.xrel = xrel; + event.motion.yrel = yrel; + SDL_PushEvent(&event); + } +} + +static SDL_MouseInputSource *GetMouseInputSource(SDL_Mouse *mouse, SDL_MouseID mouseID, bool down, Uint8 button) +{ + SDL_MouseInputSource *source, *match = NULL, *sources; + int i; + + for (i = 0; i < mouse->num_sources; ++i) { + source = &mouse->sources[i]; + if (source->mouseID == mouseID) { + match = source; + break; + } + } + + if (!down && (!match || !(match->buttonstate & SDL_BUTTON_MASK(button)))) { + /* This might be a button release from a transition between mouse messages and raw input. + * See if there's another mouse source that already has that button down and use that. + */ + for (i = 0; i < mouse->num_sources; ++i) { + source = &mouse->sources[i]; + if ((source->buttonstate & SDL_BUTTON_MASK(button))) { + match = source; + break; + } + } + } + if (match) { + return match; + } + + sources = (SDL_MouseInputSource *)SDL_realloc(mouse->sources, (mouse->num_sources + 1) * sizeof(*mouse->sources)); + if (sources) { + mouse->sources = sources; + ++mouse->num_sources; + source = &sources[mouse->num_sources - 1]; + SDL_zerop(source); + source->mouseID = mouseID; + return source; + } + return NULL; +} + +static SDL_MouseClickState *GetMouseClickState(SDL_MouseInputSource *source, Uint8 button) +{ + if (button >= source->num_clickstates) { + int i, count = button + 1; + SDL_MouseClickState *clickstate = (SDL_MouseClickState *)SDL_realloc(source->clickstate, count * sizeof(*source->clickstate)); + if (!clickstate) { + return NULL; + } + source->clickstate = clickstate; + + for (i = source->num_clickstates; i < count; ++i) { + SDL_zero(source->clickstate[i]); + } + source->num_clickstates = count; + } + return &source->clickstate[button]; +} + +static void SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, Uint8 button, bool down, int clicks) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_EventType type; + Uint32 buttonstate; + SDL_MouseInputSource *source; + + source = GetMouseInputSource(mouse, mouseID, down, button); + if (!source) { + return; + } + buttonstate = source->buttonstate; + + // SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events + if (mouse->mouse_touch_events) { + if (mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID && button == SDL_BUTTON_LEFT) { + if (down) { + track_mouse_down = true; + } else { + track_mouse_down = false; + } + if (window) { + type = track_mouse_down ? SDL_EVENT_FINGER_DOWN : SDL_EVENT_FINGER_UP; + float normalized_x = mouse->x / (float)window->w; + float normalized_y = mouse->y / (float)window->h; + SDL_SendTouch(timestamp, SDL_MOUSE_TOUCHID, SDL_BUTTON_LEFT, window, type, normalized_x, normalized_y, 1.0f); + } + } + } + + // SDL_HINT_TOUCH_MOUSE_EVENTS: if not set, discard synthetic mouse events coming from platform layer + if (mouse->touch_mouse_events == 0) { + if (mouseID == SDL_TOUCH_MOUSEID) { + return; + } + } + + // Figure out which event to perform + if (down) { + type = SDL_EVENT_MOUSE_BUTTON_DOWN; + buttonstate |= SDL_BUTTON_MASK(button); + } else { + type = SDL_EVENT_MOUSE_BUTTON_UP; + buttonstate &= ~SDL_BUTTON_MASK(button); + } + + // We do this after calculating buttonstate so button presses gain focus + if (window && down) { + SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, true); + } + + if (buttonstate == source->buttonstate) { + // Ignore this event, no state change + return; + } + source->buttonstate = buttonstate; + + if (clicks < 0) { + SDL_MouseClickState *clickstate = GetMouseClickState(source, button); + if (clickstate) { + if (down) { + Uint64 now = SDL_GetTicks(); + + if (now >= (clickstate->last_timestamp + mouse->double_click_time) || + SDL_fabs(mouse->click_motion_x - clickstate->click_motion_x) > mouse->double_click_radius || + SDL_fabs(mouse->click_motion_y - clickstate->click_motion_y) > mouse->double_click_radius) { + clickstate->click_count = 0; + } + clickstate->last_timestamp = now; + clickstate->click_motion_x = mouse->click_motion_x; + clickstate->click_motion_y = mouse->click_motion_y; + if (clickstate->click_count < 255) { + ++clickstate->click_count; + } + } + clicks = clickstate->click_count; + } else { + clicks = 1; + } + } + + // Post the event, if desired + if (SDL_EventEnabled(type)) { + if ((!mouse->relative_mode || mouse->warp_emulation_active) && mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID) { + // We're not in relative mode, so all mouse events are global mouse events + mouseID = SDL_GLOBAL_MOUSE_ID; + } else { + mouseID = source->mouseID; + } + + SDL_Event event; + event.type = type; + event.common.timestamp = timestamp; + event.button.windowID = mouse->focus ? mouse->focus->id : 0; + event.button.which = mouseID; + event.button.down = down; + event.button.button = button; + event.button.clicks = (Uint8)SDL_min(clicks, 255); + event.button.x = mouse->x; + event.button.y = mouse->y; + SDL_PushEvent(&event); + } + + // We do this after dispatching event so button releases can lose focus + if (window && !down) { + SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, true); + } + + // Automatically capture the mouse while buttons are pressed + if (mouse->auto_capture) { + SDL_UpdateMouseCapture(false); + } +} + +void SDL_SendMouseButtonClicks(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, Uint8 button, bool down, int clicks) +{ + clicks = SDL_max(clicks, 0); + SDL_PrivateSendMouseButton(timestamp, window, mouseID, button, down, clicks); +} + +void SDL_SendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, Uint8 button, bool down) +{ + SDL_PrivateSendMouseButton(timestamp, window, mouseID, button, down, -1); +} + +void SDL_SendMouseWheel(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (window) { + SDL_SetMouseFocus(window); + } + + if (x == 0.0f && y == 0.0f) { + return; + } + + // Post the event, if desired + if (SDL_EventEnabled(SDL_EVENT_MOUSE_WHEEL)) { + if (!mouse->relative_mode || mouse->warp_emulation_active) { + // We're not in relative mode, so all mouse events are global mouse events + mouseID = SDL_GLOBAL_MOUSE_ID; + } + + SDL_Event event; + event.type = SDL_EVENT_MOUSE_WHEEL; + event.common.timestamp = timestamp; + event.wheel.windowID = mouse->focus ? mouse->focus->id : 0; + event.wheel.which = mouseID; + event.wheel.x = x; + event.wheel.y = y; + event.wheel.direction = direction; + event.wheel.mouse_x = mouse->x; + event.wheel.mouse_y = mouse->y; + SDL_PushEvent(&event); + } +} + +void SDL_QuitMouse(void) +{ + SDL_Cursor *cursor, *next; + SDL_Mouse *mouse = SDL_GetMouse(); + + if (mouse->added_mouse_touch_device) { + SDL_DelTouch(SDL_MOUSE_TOUCHID); + } + + if (mouse->added_pen_touch_device) { + SDL_DelTouch(SDL_PEN_TOUCHID); + } + + if (mouse->CaptureMouse) { + SDL_CaptureMouse(false); + SDL_UpdateMouseCapture(true); + } + SDL_SetRelativeMouseMode(false); + SDL_ShowCursor(); + + if (mouse->def_cursor) { + SDL_SetDefaultCursor(NULL); + } + + cursor = mouse->cursors; + while (cursor) { + next = cursor->next; + SDL_DestroyCursor(cursor); + cursor = next; + } + mouse->cursors = NULL; + mouse->cur_cursor = NULL; + + if (mouse->sources) { + for (int i = 0; i < mouse->num_sources; ++i) { + SDL_MouseInputSource *source = &mouse->sources[i]; + SDL_free(source->clickstate); + } + SDL_free(mouse->sources); + mouse->sources = NULL; + } + mouse->num_sources = 0; + + SDL_RemoveHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_TIME, + SDL_MouseDoubleClickTimeChanged, mouse); + + SDL_RemoveHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS, + SDL_MouseDoubleClickRadiusChanged, mouse); + + SDL_RemoveHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE, + SDL_MouseNormalSpeedScaleChanged, mouse); + + SDL_RemoveHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE, + SDL_MouseRelativeSpeedScaleChanged, mouse); + + SDL_RemoveHintCallback(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE, + SDL_MouseRelativeSystemScaleChanged, mouse); + + SDL_RemoveHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, + SDL_MouseRelativeModeCenterChanged, mouse); + + SDL_RemoveHintCallback(SDL_HINT_MOUSE_EMULATE_WARP_WITH_RELATIVE, + SDL_MouseWarpEmulationChanged, mouse); + + SDL_RemoveHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS, + SDL_TouchMouseEventsChanged, mouse); + + SDL_RemoveHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS, + SDL_MouseTouchEventsChanged, mouse); + + SDL_RemoveHintCallback(SDL_HINT_PEN_MOUSE_EVENTS, + SDL_PenMouseEventsChanged, mouse); + + SDL_RemoveHintCallback(SDL_HINT_PEN_TOUCH_EVENTS, + SDL_PenTouchEventsChanged, mouse); + + SDL_RemoveHintCallback(SDL_HINT_MOUSE_AUTO_CAPTURE, + SDL_MouseAutoCaptureChanged, mouse); + + SDL_RemoveHintCallback(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION, + SDL_MouseRelativeWarpMotionChanged, mouse); + + SDL_RemoveHintCallback(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE, + SDL_MouseRelativeCursorVisibleChanged, mouse); + + for (int i = SDL_mouse_count; i--; ) { + SDL_RemoveMouse(SDL_mice[i].instance_id, false); + } + SDL_free(SDL_mice); + SDL_mice = NULL; +} + +SDL_MouseButtonFlags SDL_GetMouseState(float *x, float *y) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (x) { + *x = mouse->x; + } + if (y) { + *y = mouse->y; + } + return SDL_GetMouseButtonState(mouse, SDL_GLOBAL_MOUSE_ID, true); +} + +SDL_MouseButtonFlags SDL_GetRelativeMouseState(float *x, float *y) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (x) { + *x = mouse->x_accu; + } + if (y) { + *y = mouse->y_accu; + } + mouse->x_accu = 0.0f; + mouse->y_accu = 0.0f; + return SDL_GetMouseButtonState(mouse, SDL_GLOBAL_MOUSE_ID, true); +} + +SDL_MouseButtonFlags SDL_GetGlobalMouseState(float *x, float *y) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (mouse->GetGlobalMouseState) { + float tmpx, tmpy; + + // make sure these are never NULL for the backend implementations... + if (!x) { + x = &tmpx; + } + if (!y) { + y = &tmpy; + } + + *x = *y = 0.0f; + + return mouse->GetGlobalMouseState(x, y); + } else { + return SDL_GetMouseState(x, y); + } +} + +void SDL_PerformWarpMouseInWindow(SDL_Window *window, float x, float y, bool ignore_relative_mode) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (!window) { + window = mouse->focus; + } + + if (!window) { + return; + } + + if ((window->flags & SDL_WINDOW_MINIMIZED) == SDL_WINDOW_MINIMIZED) { + return; + } + + // Ignore the previous position when we warp + mouse->last_x = x; + mouse->last_y = y; + mouse->has_position = false; + + if (mouse->relative_mode && !ignore_relative_mode) { + /* 2.0.22 made warping in relative mode actually functional, which + * surprised many applications that weren't expecting the additional + * mouse motion. + * + * So for now, warping in relative mode adjusts the absolution position + * but doesn't generate motion events, unless SDL_HINT_MOUSE_RELATIVE_WARP_MOTION is set. + */ + if (!mouse->relative_mode_warp_motion) { + mouse->x = x; + mouse->y = y; + mouse->has_position = true; + return; + } + } + + if (mouse->WarpMouse && !mouse->relative_mode) { + mouse->WarpMouse(window, x, y); + } else { + SDL_PrivateSendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, false, x, y); + } +} + +void SDL_DisableMouseWarpEmulation(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (mouse->warp_emulation_active) { + SDL_SetRelativeMouseMode(false); + } + + mouse->warp_emulation_prohibited = true; +} + +static void SDL_MaybeEnableWarpEmulation(SDL_Window *window, float x, float y) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (!mouse->warp_emulation_prohibited && mouse->warp_emulation_hint && !mouse->cursor_shown && !mouse->warp_emulation_active) { + if (!window) { + window = mouse->focus; + } + + if (window) { + const float cx = window->w / 2.f; + const float cy = window->h / 2.f; + if (x >= SDL_floorf(cx) && x <= SDL_ceilf(cx) && + y >= SDL_floorf(cy) && y <= SDL_ceilf(cy)) { + + // Require two consecutive warps to the center within a certain timespan to enter warp emulation mode. + const Uint64 now = SDL_GetTicksNS(); + if (now - mouse->last_center_warp_time_ns < WARP_EMULATION_THRESHOLD_NS) { + if (SDL_SetRelativeMouseMode(true)) { + mouse->warp_emulation_active = true; + } + } + + mouse->last_center_warp_time_ns = now; + return; + } + } + + mouse->last_center_warp_time_ns = 0; + } +} + +void SDL_WarpMouseInWindow(SDL_Window *window, float x, float y) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_MaybeEnableWarpEmulation(window, x, y); + + SDL_PerformWarpMouseInWindow(window, x, y, mouse->warp_emulation_active); +} + +bool SDL_WarpMouseGlobal(float x, float y) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (mouse->WarpMouseGlobal) { + return mouse->WarpMouseGlobal(x, y); + } + + return SDL_Unsupported(); +} + +bool SDL_SetRelativeMouseMode(bool enabled) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_Window *focusWindow = SDL_GetKeyboardFocus(); + + if (!enabled) { + // If warps were being emulated, reset the flag. + mouse->warp_emulation_active = false; + } + + if (enabled == mouse->relative_mode) { + return true; + } + + // Set the relative mode + if (!mouse->SetRelativeMouseMode || !mouse->SetRelativeMouseMode(enabled)) { + if (enabled) { + return SDL_SetError("No relative mode implementation available"); + } + } + mouse->relative_mode = enabled; + + if (enabled) { + // Update cursor visibility before we potentially warp the mouse + SDL_SetCursor(NULL); + } + + if (enabled && focusWindow) { + SDL_SetMouseFocus(focusWindow); + } + + if (focusWindow) { + SDL_UpdateWindowGrab(focusWindow); + + // Put the cursor back to where the application expects it + if (!enabled) { + SDL_PerformWarpMouseInWindow(focusWindow, mouse->x, mouse->y, true); + } + + SDL_UpdateMouseCapture(false); + } + + if (!enabled) { + // Update cursor visibility after we restore the mouse position + SDL_SetCursor(NULL); + } + + // Flush pending mouse motion - ideally we would pump events, but that's not always safe + SDL_FlushEvent(SDL_EVENT_MOUSE_MOTION); + + return true; +} + +bool SDL_GetRelativeMouseMode(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + return mouse->relative_mode; +} + +void SDL_UpdateRelativeMouseMode(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_Window *focus = SDL_GetKeyboardFocus(); + bool relative_mode = (focus && (focus->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE)); + + if (relative_mode != mouse->relative_mode) { + SDL_SetRelativeMouseMode(relative_mode); + } +} + +bool SDL_UpdateMouseCapture(bool force_release) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_Window *capture_window = NULL; + + if (!mouse->CaptureMouse) { + return true; + } + + if (!force_release) { + if (SDL_GetMessageBoxCount() == 0 && + (mouse->capture_desired || (mouse->auto_capture && SDL_GetMouseButtonState(mouse, SDL_GLOBAL_MOUSE_ID, false) != 0))) { + if (!mouse->relative_mode) { + capture_window = mouse->focus; + } + } + } + + if (capture_window != mouse->capture_window) { + /* We can get here recursively on Windows, so make sure we complete + * all of the window state operations before we change the capture state + * (e.g. https://github.com/libsdl-org/SDL/pull/5608) + */ + SDL_Window *previous_capture = mouse->capture_window; + + if (previous_capture) { + previous_capture->flags &= ~SDL_WINDOW_MOUSE_CAPTURE; + } + + if (capture_window) { + capture_window->flags |= SDL_WINDOW_MOUSE_CAPTURE; + } + + mouse->capture_window = capture_window; + + if (!mouse->CaptureMouse(capture_window)) { + // CaptureMouse() will have set an error, just restore the state + if (previous_capture) { + previous_capture->flags |= SDL_WINDOW_MOUSE_CAPTURE; + } + if (capture_window) { + capture_window->flags &= ~SDL_WINDOW_MOUSE_CAPTURE; + } + mouse->capture_window = previous_capture; + + return false; + } + } + return true; +} + +bool SDL_CaptureMouse(bool enabled) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (!mouse->CaptureMouse) { + return SDL_Unsupported(); + } + +#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) + /* Windows mouse capture is tied to the current thread, and must be called + * from the thread that created the window being captured. Since we update + * the mouse capture state from the event processing, any application state + * changes must be processed on that thread as well. + */ + if (!SDL_OnVideoThread()) { + return SDL_SetError("SDL_CaptureMouse() must be called on the main thread"); + } +#endif // defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) + + if (enabled && SDL_GetKeyboardFocus() == NULL) { + return SDL_SetError("No window has focus"); + } + mouse->capture_desired = enabled; + + return SDL_UpdateMouseCapture(false); +} + +SDL_Cursor *SDL_CreateCursor(const Uint8 *data, const Uint8 *mask, int w, int h, int hot_x, int hot_y) +{ + SDL_Surface *surface; + SDL_Cursor *cursor; + int x, y; + Uint32 *pixel; + Uint8 datab = 0, maskb = 0; + const Uint32 black = 0xFF000000; + const Uint32 white = 0xFFFFFFFF; + const Uint32 transparent = 0x00000000; +#if defined(SDL_PLATFORM_WIN32) + // Only Windows backend supports inverted pixels in mono cursors. + const Uint32 inverted = 0x00FFFFFF; +#else + const Uint32 inverted = 0xFF000000; +#endif // defined(SDL_PLATFORM_WIN32) + + // Make sure the width is a multiple of 8 + w = ((w + 7) & ~7); + + // Create the surface from a bitmap + surface = SDL_CreateSurface(w, h, SDL_PIXELFORMAT_ARGB8888); + if (!surface) { + return NULL; + } + for (y = 0; y < h; ++y) { + pixel = (Uint32 *)((Uint8 *)surface->pixels + y * surface->pitch); + for (x = 0; x < w; ++x) { + if ((x % 8) == 0) { + datab = *data++; + maskb = *mask++; + } + if (maskb & 0x80) { + *pixel++ = (datab & 0x80) ? black : white; + } else { + *pixel++ = (datab & 0x80) ? inverted : transparent; + } + datab <<= 1; + maskb <<= 1; + } + } + + cursor = SDL_CreateColorCursor(surface, hot_x, hot_y); + + SDL_DestroySurface(surface); + + return cursor; +} + +SDL_Cursor *SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_Surface *temp = NULL; + SDL_Cursor *cursor; + + if (!surface) { + SDL_InvalidParamError("surface"); + return NULL; + } + + // Allow specifying the hot spot via properties on the surface + SDL_PropertiesID props = SDL_GetSurfaceProperties(surface); + hot_x = (int)SDL_GetNumberProperty(props, SDL_PROP_SURFACE_HOTSPOT_X_NUMBER, hot_x); + hot_y = (int)SDL_GetNumberProperty(props, SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER, hot_y); + + // Sanity check the hot spot + if ((hot_x < 0) || (hot_y < 0) || + (hot_x >= surface->w) || (hot_y >= surface->h)) { + SDL_SetError("Cursor hot spot doesn't lie within cursor"); + return NULL; + } + + if (surface->format != SDL_PIXELFORMAT_ARGB8888) { + temp = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ARGB8888); + if (!temp) { + return NULL; + } + surface = temp; + } + + if (mouse->CreateCursor) { + cursor = mouse->CreateCursor(surface, hot_x, hot_y); + } else { + cursor = (SDL_Cursor *)SDL_calloc(1, sizeof(*cursor)); + } + if (cursor) { + cursor->next = mouse->cursors; + mouse->cursors = cursor; + } + + SDL_DestroySurface(temp); + + return cursor; +} + +SDL_Cursor *SDL_CreateSystemCursor(SDL_SystemCursor id) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_Cursor *cursor; + + if (!mouse->CreateSystemCursor) { + SDL_SetError("CreateSystemCursor is not currently supported"); + return NULL; + } + + cursor = mouse->CreateSystemCursor(id); + if (cursor) { + cursor->next = mouse->cursors; + mouse->cursors = cursor; + } + + return cursor; +} + +/* SDL_SetCursor(NULL) can be used to force the cursor redraw, + if this is desired for any reason. This is used when setting + the video mode and when the SDL window gains the mouse focus. + */ +bool SDL_SetCursor(SDL_Cursor *cursor) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + // Return immediately if setting the cursor to the currently set one (fixes #7151) + if (cursor == mouse->cur_cursor) { + return true; + } + + // Set the new cursor + if (cursor) { + // Make sure the cursor is still valid for this mouse + if (cursor != mouse->def_cursor) { + SDL_Cursor *found; + for (found = mouse->cursors; found; found = found->next) { + if (found == cursor) { + break; + } + } + if (!found) { + return SDL_SetError("Cursor not associated with the current mouse"); + } + } + mouse->cur_cursor = cursor; + } else { + if (mouse->focus) { + cursor = mouse->cur_cursor; + } else { + cursor = mouse->def_cursor; + } + } + + if (cursor && (!mouse->focus || (mouse->cursor_shown && (!mouse->relative_mode || mouse->relative_mode_cursor_visible)))) { + if (mouse->ShowCursor) { + mouse->ShowCursor(cursor); + } + } else { + if (mouse->ShowCursor) { + mouse->ShowCursor(NULL); + } + } + return true; +} + +SDL_Cursor *SDL_GetCursor(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (!mouse) { + return NULL; + } + return mouse->cur_cursor; +} + +SDL_Cursor *SDL_GetDefaultCursor(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (!mouse) { + return NULL; + } + return mouse->def_cursor; +} + +void SDL_DestroyCursor(SDL_Cursor *cursor) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_Cursor *curr, *prev; + + if (!cursor) { + return; + } + + if (cursor == mouse->def_cursor) { + return; + } + if (cursor == mouse->cur_cursor) { + SDL_SetCursor(mouse->def_cursor); + } + + for (prev = NULL, curr = mouse->cursors; curr; + prev = curr, curr = curr->next) { + if (curr == cursor) { + if (prev) { + prev->next = curr->next; + } else { + mouse->cursors = curr->next; + } + + if (mouse->FreeCursor && curr->internal) { + mouse->FreeCursor(curr); + } else { + SDL_free(curr); + } + return; + } + } +} + +bool SDL_ShowCursor(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (mouse->warp_emulation_active) { + SDL_SetRelativeMouseMode(false); + mouse->warp_emulation_active = false; + } + + if (!mouse->cursor_shown) { + mouse->cursor_shown = true; + SDL_SetCursor(NULL); + } + return true; +} + +bool SDL_HideCursor(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (mouse->cursor_shown) { + mouse->cursor_shown = false; + SDL_SetCursor(NULL); + } + return true; +} + +bool SDL_CursorVisible(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + return mouse->cursor_shown; +} diff --git a/contrib/SDL-3.2.8/src/events/SDL_mouse_c.h b/contrib/SDL-3.2.8/src/events/SDL_mouse_c.h new file mode 100644 index 0000000..43cc520 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_mouse_c.h @@ -0,0 +1,208 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_mouse_c_h_ +#define SDL_mouse_c_h_ + +// Mouse events not associated with a specific input device +#define SDL_GLOBAL_MOUSE_ID 0 + +// The default mouse input device, for platforms that don't have multiple mice +#define SDL_DEFAULT_MOUSE_ID 1 + +typedef struct SDL_CursorData SDL_CursorData; + +struct SDL_Cursor +{ + struct SDL_Cursor *next; + SDL_CursorData *internal; +}; + +typedef struct +{ + Uint64 last_timestamp; + double click_motion_x; + double click_motion_y; + Uint8 click_count; +} SDL_MouseClickState; + +typedef struct +{ + SDL_MouseID mouseID; + Uint32 buttonstate; + + // Data for double-click tracking + int num_clickstates; + SDL_MouseClickState *clickstate; +} SDL_MouseInputSource; + +typedef struct +{ + // Create a cursor from a surface + SDL_Cursor *(*CreateCursor)(SDL_Surface *surface, int hot_x, int hot_y); + + // Create a system cursor + SDL_Cursor *(*CreateSystemCursor)(SDL_SystemCursor id); + + // Show the specified cursor, or hide if cursor is NULL + bool (*ShowCursor)(SDL_Cursor *cursor); + + // This is called when a mouse motion event occurs + bool (*MoveCursor)(SDL_Cursor *cursor); + + // Free a window manager cursor + void (*FreeCursor)(SDL_Cursor *cursor); + + // Warp the mouse to (x,y) within a window + bool (*WarpMouse)(SDL_Window *window, float x, float y); + + // Warp the mouse to (x,y) in screen space + bool (*WarpMouseGlobal)(float x, float y); + + // Set relative mode + bool (*SetRelativeMouseMode)(bool enabled); + + // Set mouse capture + bool (*CaptureMouse)(SDL_Window *window); + + // Get absolute mouse coordinates. (x) and (y) are never NULL and set to zero before call. + SDL_MouseButtonFlags (*GetGlobalMouseState)(float *x, float *y); + + // Platform-specific system mouse transform + void (*ApplySystemScale)(void *internal, Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, float *x, float *y); + void *system_scale_data; + + // Data common to all mice + SDL_Window *focus; + float x; + float y; + float x_accu; + float y_accu; + float last_x, last_y; // the last reported x and y coordinates + double click_motion_x; + double click_motion_y; + bool has_position; + bool relative_mode; + bool relative_mode_warp_motion; + bool relative_mode_cursor_visible; + bool relative_mode_center; + bool warp_emulation_hint; + bool warp_emulation_active; + bool warp_emulation_prohibited; + Uint64 last_center_warp_time_ns; + bool enable_normal_speed_scale; + float normal_speed_scale; + bool enable_relative_speed_scale; + float relative_speed_scale; + bool enable_relative_system_scale; + Uint32 double_click_time; + int double_click_radius; + bool touch_mouse_events; + bool mouse_touch_events; + bool pen_mouse_events; + bool pen_touch_events; + bool was_touch_mouse_events; // Was a touch-mouse event pending? + bool added_mouse_touch_device; // did we SDL_AddTouch() a virtual touch device for the mouse? + bool added_pen_touch_device; // did we SDL_AddTouch() a virtual touch device for pens? +#ifdef SDL_PLATFORM_VITA + Uint8 vita_touch_mouse_device; +#endif + bool auto_capture; + bool capture_desired; + SDL_Window *capture_window; + + // Data for input source state + int num_sources; + SDL_MouseInputSource *sources; + + SDL_Cursor *cursors; + SDL_Cursor *def_cursor; + SDL_Cursor *cur_cursor; + bool cursor_shown; + + // Driver-dependent data. + void *internal; +} SDL_Mouse; + +// Initialize the mouse subsystem, called before the main video driver is initialized +extern bool SDL_PreInitMouse(void); + +// Finish initializing the mouse subsystem, called after the main video driver was initialized +extern void SDL_PostInitMouse(void); + +// Return whether a device is actually a mouse +extern bool SDL_IsMouse(Uint16 vendor, Uint16 product); + +// A mouse has been added to the system +extern void SDL_AddMouse(SDL_MouseID mouseID, const char *name, bool send_event); + +// A mouse has been removed from the system +extern void SDL_RemoveMouse(SDL_MouseID mouseID, bool send_event); + +// Get the mouse state structure +extern SDL_Mouse *SDL_GetMouse(void); + +// Set the default mouse cursor +extern void SDL_SetDefaultCursor(SDL_Cursor *cursor); + +// Get the preferred default system cursor +extern SDL_SystemCursor SDL_GetDefaultSystemCursor(void); + +// Set the mouse focus window +extern void SDL_SetMouseFocus(SDL_Window *window); + +// Update the mouse capture window +extern bool SDL_UpdateMouseCapture(bool force_release); + +// Send a mouse motion event +extern void SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, bool relative, float x, float y); + +// Send a mouse button event +extern void SDL_SendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, Uint8 button, bool down); + +// Send a mouse button event with a click count +extern void SDL_SendMouseButtonClicks(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, Uint8 button, bool down, int clicks); + +// Send a mouse wheel event +extern void SDL_SendMouseWheel(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction); + +// Warp the mouse within the window, potentially overriding relative mode +extern void SDL_PerformWarpMouseInWindow(SDL_Window *window, float x, float y, bool ignore_relative_mode); + +// Relative mouse mode +extern bool SDL_SetRelativeMouseMode(bool enabled); +extern bool SDL_GetRelativeMouseMode(void); +extern void SDL_UpdateRelativeMouseMode(void); +extern void SDL_DisableMouseWarpEmulation(void); + +// TODO RECONNECT: Set mouse state to "zero" +#if 0 +extern void SDL_ResetMouse(void); +#endif // 0 + +// Check if mouse position is within window or captured by window +extern bool SDL_MousePositionInWindow(SDL_Window *window, float x, float y); + +// Shutdown the mouse subsystem +extern void SDL_QuitMouse(void); + +#endif // SDL_mouse_c_h_ diff --git a/contrib/SDL-3.2.8/src/events/SDL_pen.c b/contrib/SDL-3.2.8/src/events/SDL_pen.c new file mode 100644 index 0000000..1ef7062 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_pen.c @@ -0,0 +1,577 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// Pressure-sensitive pen handling code for SDL + +#include "../SDL_hints_c.h" +#include "SDL_events_c.h" +#include "SDL_pen_c.h" + +static SDL_PenID pen_touching = 0; // used for synthetic mouse/touch events. + +typedef struct SDL_Pen +{ + SDL_PenID instance_id; + char *name; + SDL_PenInfo info; + float axes[SDL_PEN_AXIS_COUNT]; + float x; + float y; + SDL_PenInputFlags input_state; + void *driverdata; +} SDL_Pen; + +// we assume there's usually 0-1 pens in most cases and this list doesn't +// usually change after startup, so a simple array with a RWlock is fine for now. +static SDL_RWLock *pen_device_rwlock = NULL; +static SDL_Pen *pen_devices SDL_GUARDED_BY(pen_device_rwlock) = NULL; +static int pen_device_count SDL_GUARDED_BY(pen_device_rwlock) = 0; + +// You must hold pen_device_rwlock before calling this, and result is only safe while lock is held! +// If SDL isn't initialized, grabbing the NULL lock is a no-op and there will be zero devices, so +// locking and calling this in that case will do the right thing. +static SDL_Pen *FindPenByInstanceId(SDL_PenID instance_id) SDL_REQUIRES_SHARED(pen_device_rwlock) +{ + if (instance_id) { + for (int i = 0; i < pen_device_count; i++) { + if (pen_devices[i].instance_id == instance_id) { + return &pen_devices[i]; + } + } + } + SDL_SetError("Invalid pen instance ID"); + return NULL; +} + +SDL_PenID SDL_FindPenByHandle(void *handle) +{ + SDL_PenID result = 0; + SDL_LockRWLockForReading(pen_device_rwlock); + for (int i = 0; i < pen_device_count; i++) { + if (pen_devices[i].driverdata == handle) { + result = pen_devices[i].instance_id; + break; + } + } + SDL_UnlockRWLock(pen_device_rwlock); + return result; +} + +SDL_PenID SDL_FindPenByCallback(bool (*callback)(void *handle, void *userdata), void *userdata) +{ + SDL_PenID result = 0; + SDL_LockRWLockForReading(pen_device_rwlock); + for (int i = 0; i < pen_device_count; i++) { + if (callback(pen_devices[i].driverdata, userdata)) { + result = pen_devices[i].instance_id; + break; + } + } + SDL_UnlockRWLock(pen_device_rwlock); + return result; +} + + + +// public API ... + +bool SDL_InitPen(void) +{ + SDL_assert(pen_device_rwlock == NULL); + SDL_assert(pen_devices == NULL); + SDL_assert(pen_device_count == 0); + pen_device_rwlock = SDL_CreateRWLock(); + if (!pen_device_rwlock) { + return false; + } + return true; +} + +void SDL_QuitPen(void) +{ + SDL_DestroyRWLock(pen_device_rwlock); + pen_device_rwlock = NULL; + if (pen_devices) { + for (int i = pen_device_count; i--; ) { + SDL_free(pen_devices[i].name); + } + SDL_free(pen_devices); + pen_devices = NULL; + } + pen_device_count = 0; + pen_touching = 0; +} + +#if 0 // not a public API at the moment. +SDL_PenID *SDL_GetPens(int *count) +{ + SDL_LockRWLockForReading(pen_device_rwlock); + const int num_devices = pen_device_count; + SDL_PenID *result = (SDL_PenID *) SDL_malloc((num_devices + 1) * sizeof (SDL_PenID)); + if (result) { + for (int i = 0; i < num_devices; i++) { + result[i] = pen_devices[i].instance_id; + } + result[num_devices] = 0; // null-terminated. + } + SDL_UnlockRWLock(pen_device_rwlock); + + if (count) { + *count = result ? num_devices : 0; + } + return result; +} + +const char *SDL_GetPenName(SDL_PenID instance_id) +{ + SDL_LockRWLockForReading(pen_device_rwlock); + const SDL_Pen *pen = FindPenByInstanceId(instance_id); + const char *result = pen ? SDL_GetPersistentString(pen->name) : NULL; + SDL_UnlockRWLock(pen_device_rwlock); + return result; +} + +bool SDL_GetPenInfo(SDL_PenID instance_id, SDL_PenInfo *info) +{ + SDL_LockRWLockForReading(pen_device_rwlock); + const SDL_Pen *pen = FindPenByInstanceId(instance_id); + const bool result = pen ? true : false; + if (info) { + if (result) { + SDL_copyp(info, &pen->info); + } else { + SDL_zerop(info); + } + } + SDL_UnlockRWLock(pen_device_rwlock); + return result; +} + +bool SDL_PenConnected(SDL_PenID instance_id) +{ + SDL_LockRWLockForReading(pen_device_rwlock); + const SDL_Pen *pen = FindPenByInstanceId(instance_id); + const bool result = (pen != NULL); + SDL_UnlockRWLock(pen_device_rwlock); + return result; +} +#endif + +SDL_PenInputFlags SDL_GetPenStatus(SDL_PenID instance_id, float *axes, int num_axes) +{ + if (num_axes < 0) { + num_axes = 0; + } + + SDL_LockRWLockForReading(pen_device_rwlock); + const SDL_Pen *pen = FindPenByInstanceId(instance_id); + SDL_PenInputFlags result = 0; + if (pen) { + result = pen->input_state; + if (axes && num_axes) { + SDL_memcpy(axes, pen->axes, SDL_min(num_axes, SDL_PEN_AXIS_COUNT) * sizeof (*axes)); + // zero out axes we don't know about, in case the caller built with newer SDL headers that support more of them. + if (num_axes > SDL_PEN_AXIS_COUNT) { + SDL_memset(&axes[SDL_PEN_AXIS_COUNT], '\0', (num_axes - SDL_PEN_AXIS_COUNT) * sizeof (*axes)); + } + } + } + SDL_UnlockRWLock(pen_device_rwlock); + return result; +} + +SDL_PenCapabilityFlags SDL_GetPenCapabilityFromAxis(SDL_PenAxis axis) +{ + // the initial capability bits happen to match up, but as + // more features show up later, the bits may no longer be contiguous! + if ((axis >= SDL_PEN_AXIS_PRESSURE) && (axis <= SDL_PEN_AXIS_SLIDER)) { + return ((SDL_PenCapabilityFlags) 1u) << ((SDL_PenCapabilityFlags) axis); + } + return 0; // oh well. +} + +SDL_PenID SDL_AddPenDevice(Uint64 timestamp, const char *name, const SDL_PenInfo *info, void *handle) +{ + SDL_assert(handle != NULL); // just allocate a Uint8 so you have a unique pointer if not needed! + SDL_assert(SDL_FindPenByHandle(handle) == 0); // Backends shouldn't double-add pens! + SDL_assert(pen_device_rwlock != NULL); // subsystem should be initialized by now! + + char *namecpy = SDL_strdup(name ? name : "Unnamed pen"); + if (!namecpy) { + return 0; + } + + SDL_PenID result = 0; + + SDL_LockRWLockForWriting(pen_device_rwlock); + + SDL_Pen *pen = NULL; + void *ptr = SDL_realloc(pen_devices, (pen_device_count + 1) * sizeof (*pen)); + if (ptr) { + result = (SDL_PenID) SDL_GetNextObjectID(); + pen_devices = (SDL_Pen *) ptr; + pen = &pen_devices[pen_device_count]; + pen_device_count++; + + SDL_zerop(pen); + pen->instance_id = result; + pen->name = namecpy; + if (info) { + SDL_copyp(&pen->info, info); + } + pen->driverdata = handle; + // axes and input state defaults to zero. + } + SDL_UnlockRWLock(pen_device_rwlock); + + if (!pen) { + SDL_free(namecpy); + } + + if (result && SDL_EventEnabled(SDL_EVENT_PEN_PROXIMITY_IN)) { + SDL_Event event; + SDL_zero(event); + event.pproximity.type = SDL_EVENT_PEN_PROXIMITY_IN; + event.pproximity.timestamp = timestamp; + event.pproximity.which = result; + SDL_PushEvent(&event); + } + + return result; +} + +void SDL_RemovePenDevice(Uint64 timestamp, SDL_PenID instance_id) +{ + if (!instance_id) { + return; + } + + SDL_LockRWLockForWriting(pen_device_rwlock); + SDL_Pen *pen = FindPenByInstanceId(instance_id); + if (pen) { + SDL_free(pen->name); + // we don't free `pen`, it's just part of simple array. Shuffle it out. + const int idx = ((int) (pen - pen_devices)); + SDL_assert((idx >= 0) && (idx < pen_device_count)); + if ( idx < (pen_device_count - 1) ) { + SDL_memmove(&pen_devices[idx], &pen_devices[idx + 1], sizeof (*pen) * ((pen_device_count - idx) - 1)); + } + + SDL_assert(pen_device_count > 0); + pen_device_count--; + + if (pen_device_count) { + void *ptr = SDL_realloc(pen_devices, sizeof (*pen) * pen_device_count); // shrink it down. + if (ptr) { + pen_devices = (SDL_Pen *) ptr; + } + } else { + SDL_free(pen_devices); + pen_devices = NULL; + } + } + SDL_UnlockRWLock(pen_device_rwlock); + + if (pen && SDL_EventEnabled(SDL_EVENT_PEN_PROXIMITY_OUT)) { + SDL_Event event; + SDL_zero(event); + event.pproximity.type = SDL_EVENT_PEN_PROXIMITY_OUT; + event.pproximity.timestamp = timestamp; + event.pproximity.which = instance_id; + SDL_PushEvent(&event); + } +} + +// This presumably is happening during video quit, so we don't send PROXIMITY_OUT events here. +void SDL_RemoveAllPenDevices(void (*callback)(SDL_PenID instance_id, void *handle, void *userdata), void *userdata) +{ + SDL_LockRWLockForWriting(pen_device_rwlock); + if (pen_device_count > 0) { + SDL_assert(pen_devices != NULL); + for (int i = 0; i < pen_device_count; i++) { + callback(pen_devices[i].instance_id, pen_devices[i].driverdata, userdata); + SDL_free(pen_devices[i].name); + } + } + SDL_free(pen_devices); + pen_devices = NULL; + SDL_UnlockRWLock(pen_device_rwlock); +} + +void SDL_SendPenTouch(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *window, bool eraser, bool down) +{ + bool send_event = false; + SDL_PenInputFlags input_state = 0; + float x = 0.0f; + float y = 0.0f; + + // note that this locks for _reading_ because the lock protects the + // pen_devices array from being reallocated from under us, not the data in it; + // we assume only one thread (in the backend) is modifying an individual pen at + // a time, so it can update input state cleanly here. + SDL_LockRWLockForReading(pen_device_rwlock); + SDL_Pen *pen = FindPenByInstanceId(instance_id); + if (pen) { + input_state = pen->input_state; + x = pen->x; + y = pen->y; + + if (down && ((input_state & SDL_PEN_INPUT_DOWN) == 0)) { + input_state |= SDL_PEN_INPUT_DOWN; + send_event = true; + } else if (!down && (input_state & SDL_PEN_INPUT_DOWN)) { + input_state &= ~SDL_PEN_INPUT_DOWN; + send_event = true; + } + + if (eraser && ((input_state & SDL_PEN_INPUT_ERASER_TIP) == 0)) { + input_state |= SDL_PEN_INPUT_ERASER_TIP; + send_event = true; + } else if (!eraser && (input_state & SDL_PEN_INPUT_ERASER_TIP)) { + input_state &= ~SDL_PEN_INPUT_ERASER_TIP; + send_event = true; + } + + pen->input_state = input_state; // we could do an SDL_SetAtomicInt here if we run into trouble... + } + SDL_UnlockRWLock(pen_device_rwlock); + + if (send_event) { + const SDL_EventType evtype = down ? SDL_EVENT_PEN_DOWN : SDL_EVENT_PEN_UP; + if (SDL_EventEnabled(evtype)) { + SDL_Event event; + SDL_zero(event); + event.ptouch.type = evtype; + event.ptouch.timestamp = timestamp; + event.ptouch.windowID = window ? window->id : 0; + event.ptouch.which = instance_id; + event.ptouch.pen_state = input_state; + event.ptouch.x = x; + event.ptouch.y = y; + event.ptouch.eraser = eraser; + event.ptouch.down = down; + SDL_PushEvent(&event); + } + + SDL_Mouse *mouse = SDL_GetMouse(); + if (mouse && window) { + if (mouse->pen_mouse_events) { + if (down) { + if (!pen_touching) { + SDL_SendMouseMotion(timestamp, window, SDL_PEN_MOUSEID, false, x, y); + SDL_SendMouseButton(timestamp, window, SDL_PEN_MOUSEID, SDL_BUTTON_LEFT, true); + } + } else { + if (pen_touching == instance_id) { + SDL_SendMouseButton(timestamp, window, SDL_PEN_MOUSEID, SDL_BUTTON_LEFT, false); + } + } + } + + if (mouse->pen_touch_events) { + const SDL_EventType touchtype = down ? SDL_EVENT_FINGER_DOWN : SDL_EVENT_FINGER_UP; + const float normalized_x = x / (float)window->w; + const float normalized_y = y / (float)window->h; + if (!pen_touching || (pen_touching == instance_id)) { + SDL_SendTouch(timestamp, SDL_PEN_TOUCHID, SDL_BUTTON_LEFT, window, touchtype, normalized_x, normalized_y, pen->axes[SDL_PEN_AXIS_PRESSURE]); + } + } + } + + if (down) { + if (!pen_touching) { + pen_touching = instance_id; + } + } else { + if (pen_touching == instance_id) { + pen_touching = 0; + } + } + } +} + +void SDL_SendPenAxis(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *window, SDL_PenAxis axis, float value) +{ + SDL_assert((axis >= 0) && (axis < SDL_PEN_AXIS_COUNT)); // fix the backend if this triggers. + + bool send_event = false; + SDL_PenInputFlags input_state = 0; + float x = 0.0f; + float y = 0.0f; + + // note that this locks for _reading_ because the lock protects the + // pen_devices array from being reallocated from under us, not the data in it; + // we assume only one thread (in the backend) is modifying an individual pen at + // a time, so it can update input state cleanly here. + SDL_LockRWLockForReading(pen_device_rwlock); + SDL_Pen *pen = FindPenByInstanceId(instance_id); + if (pen) { + if (pen->axes[axis] != value) { + pen->axes[axis] = value; // we could do an SDL_SetAtomicInt here if we run into trouble... + input_state = pen->input_state; + x = pen->x; + y = pen->y; + send_event = true; + } + } + SDL_UnlockRWLock(pen_device_rwlock); + + if (send_event && SDL_EventEnabled(SDL_EVENT_PEN_AXIS)) { + SDL_Event event; + SDL_zero(event); + event.paxis.type = SDL_EVENT_PEN_AXIS; + event.paxis.timestamp = timestamp; + event.paxis.windowID = window ? window->id : 0; + event.paxis.which = instance_id; + event.paxis.pen_state = input_state; + event.paxis.x = x; + event.paxis.y = y; + event.paxis.axis = axis; + event.paxis.value = value; + SDL_PushEvent(&event); + + if (window && (axis == SDL_PEN_AXIS_PRESSURE) && (pen_touching == instance_id)) { + SDL_Mouse *mouse = SDL_GetMouse(); + if (mouse && mouse->pen_touch_events) { + const float normalized_x = x / (float)window->w; + const float normalized_y = y / (float)window->h; + SDL_SendTouchMotion(timestamp, SDL_PEN_TOUCHID, SDL_BUTTON_LEFT, window, normalized_x, normalized_y, value); + } + } + } +} + +void SDL_SendPenMotion(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *window, float x, float y) +{ + bool send_event = false; + SDL_PenInputFlags input_state = 0; + + // note that this locks for _reading_ because the lock protects the + // pen_devices array from being reallocated from under us, not the data in it; + // we assume only one thread (in the backend) is modifying an individual pen at + // a time, so it can update input state cleanly here. + SDL_LockRWLockForReading(pen_device_rwlock); + SDL_Pen *pen = FindPenByInstanceId(instance_id); + if (pen) { + if ((pen->x != x) || (pen->y != y)) { + pen->x = x; // we could do an SDL_SetAtomicInt here if we run into trouble... + pen->y = y; // we could do an SDL_SetAtomicInt here if we run into trouble... + input_state = pen->input_state; + send_event = true; + } + } + SDL_UnlockRWLock(pen_device_rwlock); + + if (send_event && SDL_EventEnabled(SDL_EVENT_PEN_MOTION)) { + SDL_Event event; + SDL_zero(event); + event.pmotion.type = SDL_EVENT_PEN_MOTION; + event.pmotion.timestamp = timestamp; + event.pmotion.windowID = window ? window->id : 0; + event.pmotion.which = instance_id; + event.pmotion.pen_state = input_state; + event.pmotion.x = x; + event.pmotion.y = y; + SDL_PushEvent(&event); + + if (window) { + SDL_Mouse *mouse = SDL_GetMouse(); + if (mouse) { + if (pen_touching == instance_id) { + if (mouse->pen_mouse_events) { + SDL_SendMouseMotion(timestamp, window, SDL_PEN_MOUSEID, false, x, y); + } + + if (mouse->pen_touch_events) { + const float normalized_x = x / (float)window->w; + const float normalized_y = y / (float)window->h; + SDL_SendTouchMotion(timestamp, SDL_PEN_TOUCHID, SDL_BUTTON_LEFT, window, normalized_x, normalized_y, pen->axes[SDL_PEN_AXIS_PRESSURE]); + } + } else if (pen_touching == 0) { // send mouse motion (without a pressed button) for pens that aren't touching. + // this might cause a little chaos if you have multiple pens hovering at the same time, but this seems unlikely in the real world, and also something you did to yourself. :) + SDL_SendMouseMotion(timestamp, window, SDL_PEN_MOUSEID, false, x, y); + } + } + } + } +} + +void SDL_SendPenButton(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *window, Uint8 button, bool down) +{ + bool send_event = false; + SDL_PenInputFlags input_state = 0; + float x = 0.0f; + float y = 0.0f; + + if ((button < 1) || (button > 5)) { + return; // clamp for now. + } + + // note that this locks for _reading_ because the lock protects the + // pen_devices array from being reallocated from under us, not the data in it; + // we assume only one thread (in the backend) is modifying an individual pen at + // a time, so it can update input state cleanly here. + SDL_LockRWLockForReading(pen_device_rwlock); + SDL_Pen *pen = FindPenByInstanceId(instance_id); + if (pen) { + input_state = pen->input_state; + const Uint32 flag = (Uint32) (1u << button); + const bool current = ((input_state & flag) != 0); + x = pen->x; + y = pen->y; + if (down && !current) { + input_state |= flag; + send_event = true; + } else if (!down && current) { + input_state &= ~flag; + send_event = true; + } + pen->input_state = input_state; // we could do an SDL_SetAtomicInt here if we run into trouble... + } + SDL_UnlockRWLock(pen_device_rwlock); + + if (send_event) { + const SDL_EventType evtype = down ? SDL_EVENT_PEN_BUTTON_DOWN : SDL_EVENT_PEN_BUTTON_UP; + if (SDL_EventEnabled(evtype)) { + SDL_Event event; + SDL_zero(event); + event.pbutton.type = evtype; + event.pbutton.timestamp = timestamp; + event.pbutton.windowID = window ? window->id : 0; + event.pbutton.which = instance_id; + event.pbutton.pen_state = input_state; + event.pbutton.x = x; + event.pbutton.y = y; + event.pbutton.button = button; + event.pbutton.down = down; + SDL_PushEvent(&event); + + if (window && (pen_touching == instance_id)) { + SDL_Mouse *mouse = SDL_GetMouse(); + if (mouse && mouse->pen_mouse_events) { + SDL_SendMouseButton(timestamp, window, SDL_PEN_MOUSEID, button + 1, down); + } + } + } + } +} + diff --git a/contrib/SDL-3.2.8/src/events/SDL_pen_c.h b/contrib/SDL-3.2.8/src/events/SDL_pen_c.h new file mode 100644 index 0000000..1eff47f --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_pen_c.h @@ -0,0 +1,99 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "../SDL_internal.h" + +#ifndef SDL_pen_c_h_ +#define SDL_pen_c_h_ + +#include "SDL_mouse_c.h" + +typedef Uint32 SDL_PenCapabilityFlags; +#define SDL_PEN_CAPABILITY_PRESSURE (1u << 0) /**< Provides pressure information on SDL_PEN_AXIS_PRESSURE. */ +#define SDL_PEN_CAPABILITY_XTILT (1u << 1) /**< Provides horizontal tilt information on SDL_PEN_AXIS_XTILT. */ +#define SDL_PEN_CAPABILITY_YTILT (1u << 2) /**< Provides vertical tilt information on SDL_PEN_AXIS_YTILT. */ +#define SDL_PEN_CAPABILITY_DISTANCE (1u << 3) /**< Provides distance to drawing tablet on SDL_PEN_AXIS_DISTANCE. */ +#define SDL_PEN_CAPABILITY_ROTATION (1u << 4) /**< Provides barrel rotation info on SDL_PEN_AXIS_ROTATION. */ +#define SDL_PEN_CAPABILITY_SLIDER (1u << 5) /**< Provides slider/finger wheel/etc on SDL_PEN_AXIS_SLIDER. */ +#define SDL_PEN_CAPABILITY_TANGENTIAL_PRESSURE (1u << 6) /**< Provides barrel pressure on SDL_PEN_AXIS_TANGENTIAL_PRESSURE. */ +#define SDL_PEN_CAPABILITY_ERASER (1u << 7) /**< Pen also has an eraser tip. */ + +typedef enum SDL_PenSubtype +{ + SDL_PEN_TYPE_UNKNOWN, /**< Unknown pen device */ + SDL_PEN_TYPE_ERASER, /**< Eraser */ + SDL_PEN_TYPE_PEN, /**< Generic pen; this is the default. */ + SDL_PEN_TYPE_PENCIL, /**< Pencil */ + SDL_PEN_TYPE_BRUSH, /**< Brush-like device */ + SDL_PEN_TYPE_AIRBRUSH /**< Airbrush device that "sprays" ink */ +} SDL_PenSubtype; + +typedef struct SDL_PenInfo +{ + SDL_PenCapabilityFlags capabilities; /**< bitflags of device capabilities */ + float max_tilt; /**< Physical maximum tilt angle, for XTILT and YTILT, or -1.0f if unknown. Pens cannot typically tilt all the way to 90 degrees, so this value is usually less than 90.0. */ + Uint32 wacom_id; /**< For Wacom devices: wacom tool type ID, otherwise 0 (useful e.g. with libwacom) */ + int num_buttons; /**< Number of pen buttons (not counting the pen tip), or -1 if unknown. */ + SDL_PenSubtype subtype; /**< type of pen device */ +} SDL_PenInfo; + +// Backend calls this when a new pen device is hotplugged, plus once for each pen already connected at startup. +// Note that name and info are copied but currently unused; this is placeholder for a potentially more robust API later. +// Both are allowed to be NULL. +extern SDL_PenID SDL_AddPenDevice(Uint64 timestamp, const char *name, const SDL_PenInfo *info, void *handle); + +// Backend calls this when an existing pen device is disconnected during runtime. They must free their own stuff separately. +extern void SDL_RemovePenDevice(Uint64 timestamp, SDL_PenID instance_id); + +// Backend can call this to remove all pens, probably during shutdown, with a callback to let them free their own handle. +extern void SDL_RemoveAllPenDevices(void (*callback)(SDL_PenID instance_id, void *handle, void *userdata), void *userdata); + +// Backend calls this when a pen's button changes, to generate events and update state. +extern void SDL_SendPenTouch(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *window, bool eraser, bool down); + +// Backend calls this when a pen moves on the tablet, to generate events and update state. +extern void SDL_SendPenMotion(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *window, float x, float y); + +// Backend calls this when a pen's axis changes, to generate events and update state. +extern void SDL_SendPenAxis(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *window, SDL_PenAxis axis, float value); + +// Backend calls this when a pen's button changes, to generate events and update state. +extern void SDL_SendPenButton(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *window, Uint8 button, bool down); + +// Backend can optionally use this to find the SDL_PenID for the `handle` that was passed to SDL_AddPenDevice. +extern SDL_PenID SDL_FindPenByHandle(void *handle); + +// Backend can optionally use this to find a SDL_PenID, selected by a callback examining all devices. Zero if not found. +extern SDL_PenID SDL_FindPenByCallback(bool (*callback)(void *handle, void *userdata), void *userdata); + +// Backend can use this to query current pen status. +SDL_PenInputFlags SDL_GetPenStatus(SDL_PenID instance_id, float *axes, int num_axes); + +// Backend can use this to map an axis to a capability bit. +SDL_PenCapabilityFlags SDL_GetPenCapabilityFromAxis(SDL_PenAxis axis); + +// Higher-level SDL video subsystem code calls this when starting up. Backends shouldn't. +extern bool SDL_InitPen(void); + +// Higher-level SDL video subsystem code calls this when shutting down. Backends shouldn't. +extern void SDL_QuitPen(void); + +#endif // SDL_pen_c_h_ diff --git a/contrib/SDL-3.2.8/src/events/SDL_quit.c b/contrib/SDL-3.2.8/src/events/SDL_quit.c new file mode 100644 index 0000000..5456203 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_quit.c @@ -0,0 +1,194 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// General quit handling code for SDL + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#include "SDL_events_c.h" + +#if defined(HAVE_SIGNAL_H) || defined(HAVE_SIGACTION) +#define HAVE_SIGNAL_SUPPORT 1 +#endif + +#ifdef HAVE_SIGNAL_SUPPORT +static bool disable_signals = false; +static bool send_quit_pending = false; + +#ifdef SDL_BACKGROUNDING_SIGNAL +static bool send_backgrounding_pending = false; +#endif + +#ifdef SDL_FOREGROUNDING_SIGNAL +static bool send_foregrounding_pending = false; +#endif + +static void SDL_HandleSIG(int sig) +{ + // Reset the signal handler + (void)signal(sig, SDL_HandleSIG); + + // Send a quit event next time the event loop pumps. + // We can't send it in signal handler; SDL_malloc() might be interrupted! + if ((sig == SIGINT) || (sig == SIGTERM)) { + send_quit_pending = true; + } + +#ifdef SDL_BACKGROUNDING_SIGNAL + else if (sig == SDL_BACKGROUNDING_SIGNAL) { + send_backgrounding_pending = true; + } +#endif + +#ifdef SDL_FOREGROUNDING_SIGNAL + else if (sig == SDL_FOREGROUNDING_SIGNAL) { + send_foregrounding_pending = true; + } +#endif +} + +static void SDL_EventSignal_Init(const int sig) +{ +#ifdef HAVE_SIGACTION + struct sigaction action; + + sigaction(sig, NULL, &action); +#ifdef HAVE_SA_SIGACTION + if (action.sa_handler == SIG_DFL && (void (*)(int))action.sa_sigaction == SIG_DFL) { +#else + if (action.sa_handler == SIG_DFL) { +#endif + action.sa_handler = SDL_HandleSIG; + sigaction(sig, &action, NULL); + } +#elif defined(HAVE_SIGNAL_H) + void (*ohandler)(int) = signal(sig, SDL_HandleSIG); + if (ohandler != SIG_DFL) { + signal(sig, ohandler); + } +#endif +} + +static void SDL_EventSignal_Quit(const int sig) +{ +#ifdef HAVE_SIGACTION + struct sigaction action; + sigaction(sig, NULL, &action); + if (action.sa_handler == SDL_HandleSIG) { + action.sa_handler = SIG_DFL; + sigaction(sig, &action, NULL); + } +#elif defined(HAVE_SIGNAL_H) + void (*ohandler)(int) = signal(sig, SIG_DFL); + if (ohandler != SDL_HandleSIG) { + signal(sig, ohandler); + } +#endif // HAVE_SIGNAL_H +} + +// Public functions +static bool SDL_QuitInit_Internal(void) +{ + // Both SIGINT and SIGTERM are translated into quit interrupts + // and SDL can be built to simulate iOS/Android semantics with arbitrary signals. + SDL_EventSignal_Init(SIGINT); + SDL_EventSignal_Init(SIGTERM); + +#ifdef SDL_BACKGROUNDING_SIGNAL + SDL_EventSignal_Init(SDL_BACKGROUNDING_SIGNAL); +#endif + +#ifdef SDL_FOREGROUNDING_SIGNAL + SDL_EventSignal_Init(SDL_FOREGROUNDING_SIGNAL); +#endif + + // That's it! + return true; +} + +static void SDL_QuitQuit_Internal(void) +{ + SDL_EventSignal_Quit(SIGINT); + SDL_EventSignal_Quit(SIGTERM); + +#ifdef SDL_BACKGROUNDING_SIGNAL + SDL_EventSignal_Quit(SDL_BACKGROUNDING_SIGNAL); +#endif + +#ifdef SDL_FOREGROUNDING_SIGNAL + SDL_EventSignal_Quit(SDL_FOREGROUNDING_SIGNAL); +#endif +} +#endif + +bool SDL_InitQuit(void) +{ +#ifdef HAVE_SIGNAL_SUPPORT + if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, false)) { + return SDL_QuitInit_Internal(); + } +#endif + return true; +} + +void SDL_QuitQuit(void) +{ +#ifdef HAVE_SIGNAL_SUPPORT + if (!disable_signals) { + SDL_QuitQuit_Internal(); + } +#endif +} + +void SDL_SendPendingSignalEvents(void) +{ +#ifdef HAVE_SIGNAL_SUPPORT + if (send_quit_pending) { + SDL_SendQuit(); + SDL_assert(!send_quit_pending); + } + +#ifdef SDL_BACKGROUNDING_SIGNAL + if (send_backgrounding_pending) { + send_backgrounding_pending = false; + SDL_OnApplicationWillEnterBackground(); + } +#endif + +#ifdef SDL_FOREGROUNDING_SIGNAL + if (send_foregrounding_pending) { + send_foregrounding_pending = false; + SDL_OnApplicationDidEnterForeground(); + } +#endif +#endif +} + +void SDL_SendQuit(void) +{ +#ifdef HAVE_SIGNAL_SUPPORT + send_quit_pending = false; +#endif + SDL_SendAppEvent(SDL_EVENT_QUIT); +} diff --git a/contrib/SDL-3.2.8/src/events/SDL_scancode_tables.c b/contrib/SDL-3.2.8/src/events/SDL_scancode_tables.c new file mode 100644 index 0000000..a780f13 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_scancode_tables.c @@ -0,0 +1,71 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#if defined(SDL_INPUT_LINUXEV) || defined(SDL_VIDEO_DRIVER_WAYLAND) || defined(SDL_VIDEO_DRIVER_X11) + +#include "SDL_scancode_tables_c.h" + +#include "scancodes_darwin.h" +#include "scancodes_linux.h" +#include "scancodes_xfree86.h" + +static const struct +{ + SDL_ScancodeTable table; + SDL_Scancode const *scancodes; + int num_entries; +} SDL_scancode_tables[] = { + { SDL_SCANCODE_TABLE_DARWIN, darwin_scancode_table, SDL_arraysize(darwin_scancode_table) }, + { SDL_SCANCODE_TABLE_LINUX, linux_scancode_table, SDL_arraysize(linux_scancode_table) }, + { SDL_SCANCODE_TABLE_XFREE86_1, xfree86_scancode_table, SDL_arraysize(xfree86_scancode_table) }, + { SDL_SCANCODE_TABLE_XFREE86_2, xfree86_scancode_table2, SDL_arraysize(xfree86_scancode_table2) }, + { SDL_SCANCODE_TABLE_XVNC, xvnc_scancode_table, SDL_arraysize(xvnc_scancode_table) }, +}; + +const SDL_Scancode *SDL_GetScancodeTable(SDL_ScancodeTable table, int *num_entries) +{ + int i; + + for (i = 0; i < SDL_arraysize(SDL_scancode_tables); ++i) { + if (table == SDL_scancode_tables[i].table) { + *num_entries = SDL_scancode_tables[i].num_entries; + return SDL_scancode_tables[i].scancodes; + } + } + + *num_entries = 0; + return NULL; +} + +SDL_Scancode SDL_GetScancodeFromTable(SDL_ScancodeTable table, int keycode) +{ + SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN; + int num_entries; + const SDL_Scancode *scancodes = SDL_GetScancodeTable(table, &num_entries); + + if (keycode >= 0 && keycode < num_entries) { + scancode = scancodes[keycode]; + } + return scancode; +} + +#endif // SDL_INPUT_LINUXEV || SDL_VIDEO_DRIVER_WAYLAND || SDL_VIDEO_DRIVER_X11 diff --git a/contrib/SDL-3.2.8/src/events/SDL_scancode_tables_c.h b/contrib/SDL-3.2.8/src/events/SDL_scancode_tables_c.h new file mode 100644 index 0000000..c8ad5fc --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_scancode_tables_c.h @@ -0,0 +1,33 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +typedef enum +{ + SDL_SCANCODE_TABLE_DARWIN, + SDL_SCANCODE_TABLE_LINUX, + SDL_SCANCODE_TABLE_XFREE86_1, + SDL_SCANCODE_TABLE_XFREE86_2, + SDL_SCANCODE_TABLE_XVNC, +} SDL_ScancodeTable; + +extern const SDL_Scancode *SDL_GetScancodeTable(SDL_ScancodeTable table, int *num_entries); +extern SDL_Scancode SDL_GetScancodeFromTable(SDL_ScancodeTable table, int keycode); diff --git a/contrib/SDL-3.2.8/src/events/SDL_touch.c b/contrib/SDL-3.2.8/src/events/SDL_touch.c new file mode 100644 index 0000000..ec4acb1 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_touch.c @@ -0,0 +1,500 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// General touch handling code for SDL + +#include "SDL_events_c.h" +#include "../video/SDL_sysvideo.h" + +static int SDL_num_touch = 0; +static SDL_Touch **SDL_touchDevices = NULL; + +// for mapping touch events to mice +static bool finger_touching = false; +static SDL_FingerID track_fingerid; +static SDL_TouchID track_touchid; + +// Public functions +bool SDL_InitTouch(void) +{ + return true; +} + +bool SDL_TouchDevicesAvailable(void) +{ + return SDL_num_touch > 0; +} + +SDL_TouchID *SDL_GetTouchDevices(int *count) +{ + if (count) { + *count = 0; + } + + const int total = SDL_num_touch; + SDL_TouchID *result = (SDL_TouchID *) SDL_malloc(sizeof (SDL_TouchID) * (total + 1)); + if (result) { + for (int i = 0; i < total; i++) { + result[i] = SDL_touchDevices[i]->id; + } + result[total] = 0; + if (count) { + *count = SDL_num_touch; + } + } + + return result; +} + +static int SDL_GetTouchIndex(SDL_TouchID id) +{ + int index; + SDL_Touch *touch; + + for (index = 0; index < SDL_num_touch; ++index) { + touch = SDL_touchDevices[index]; + if (touch->id == id) { + return index; + } + } + return -1; +} + +SDL_Touch *SDL_GetTouch(SDL_TouchID id) +{ + int index = SDL_GetTouchIndex(id); + if (index < 0 || index >= SDL_num_touch) { + if (SDL_GetVideoDevice()->ResetTouch != NULL) { + SDL_SetError("Unknown touch id %d, resetting", (int)id); + (SDL_GetVideoDevice()->ResetTouch)(SDL_GetVideoDevice()); + } else { + SDL_SetError("Unknown touch device id %d, cannot reset", (int)id); + } + return NULL; + } + return SDL_touchDevices[index]; +} + +const char *SDL_GetTouchDeviceName(SDL_TouchID id) +{ + SDL_Touch *touch = SDL_GetTouch(id); + if (!touch) { + return NULL; + } + return SDL_GetPersistentString(touch->name); +} + +SDL_TouchDeviceType SDL_GetTouchDeviceType(SDL_TouchID id) +{ + SDL_Touch *touch = SDL_GetTouch(id); + return touch ? touch->type : SDL_TOUCH_DEVICE_INVALID; +} + +static int SDL_GetFingerIndex(const SDL_Touch *touch, SDL_FingerID fingerid) +{ + int index; + for (index = 0; index < touch->num_fingers; ++index) { + if (touch->fingers[index]->id == fingerid) { + return index; + } + } + return -1; +} + +static SDL_Finger *SDL_GetFinger(const SDL_Touch *touch, SDL_FingerID id) +{ + int index = SDL_GetFingerIndex(touch, id); + if (index < 0 || index >= touch->num_fingers) { + return NULL; + } + return touch->fingers[index]; +} + +SDL_Finger **SDL_GetTouchFingers(SDL_TouchID touchID, int *count) +{ + SDL_Finger **fingers; + SDL_Finger *finger_data; + + if (count) { + *count = 0; + } + + SDL_Touch *touch = SDL_GetTouch(touchID); + if (!touch) { + return NULL; + } + + // Create a snapshot of the current finger state + fingers = (SDL_Finger **)SDL_malloc((touch->num_fingers + 1) * sizeof(*fingers) + touch->num_fingers * sizeof(**fingers)); + if (!fingers) { + return NULL; + } + finger_data = (SDL_Finger *)(fingers + (touch->num_fingers + 1)); + + for (int i = 0; i < touch->num_fingers; ++i) { + fingers[i] = &finger_data[i]; + SDL_copyp(fingers[i], touch->fingers[i]); + } + fingers[touch->num_fingers] = NULL; + + if (count) { + *count = touch->num_fingers; + } + return fingers; +} + +int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name) +{ + SDL_Touch **touchDevices; + int index; + + SDL_assert(touchID != 0); + + index = SDL_GetTouchIndex(touchID); + if (index >= 0) { + return index; + } + + // Add the touch to the list of touch + touchDevices = (SDL_Touch **)SDL_realloc(SDL_touchDevices, + (SDL_num_touch + 1) * sizeof(*touchDevices)); + if (!touchDevices) { + return -1; + } + + SDL_touchDevices = touchDevices; + index = SDL_num_touch; + + SDL_touchDevices[index] = (SDL_Touch *)SDL_malloc(sizeof(*SDL_touchDevices[index])); + if (!SDL_touchDevices[index]) { + return -1; + } + + // Added touch to list + ++SDL_num_touch; + + // we're setting the touch properties + SDL_touchDevices[index]->id = touchID; + SDL_touchDevices[index]->type = type; + SDL_touchDevices[index]->num_fingers = 0; + SDL_touchDevices[index]->max_fingers = 0; + SDL_touchDevices[index]->fingers = NULL; + SDL_touchDevices[index]->name = SDL_strdup(name ? name : ""); + + return index; +} + +static bool SDL_AddFinger(SDL_Touch *touch, SDL_FingerID fingerid, float x, float y, float pressure) +{ + SDL_Finger *finger; + + SDL_assert(fingerid != 0); + + if (touch->num_fingers == touch->max_fingers) { + SDL_Finger **new_fingers; + new_fingers = (SDL_Finger **)SDL_realloc(touch->fingers, (touch->max_fingers + 1) * sizeof(*touch->fingers)); + if (!new_fingers) { + return false; + } + touch->fingers = new_fingers; + touch->fingers[touch->max_fingers] = (SDL_Finger *)SDL_malloc(sizeof(*finger)); + if (!touch->fingers[touch->max_fingers]) { + return false; + } + touch->max_fingers++; + } + + finger = touch->fingers[touch->num_fingers++]; + finger->id = fingerid; + finger->x = x; + finger->y = y; + finger->pressure = pressure; + return true; +} + +static void SDL_DelFinger(SDL_Touch *touch, SDL_FingerID fingerid) +{ + int index = SDL_GetFingerIndex(touch, fingerid); + if (index < 0) { + return; + } + + --touch->num_fingers; + if (index < (touch->num_fingers)) { + // Move the deleted finger to just past the end of the active fingers array and shift the active fingers by one. + // This ensures that the descriptor for the now-deleted finger is located at `touch->fingers[touch->num_fingers]` + // and is ready for use in SDL_AddFinger. + SDL_Finger *deleted_finger = touch->fingers[index]; + SDL_memmove(&touch->fingers[index], &touch->fingers[index + 1], (touch->num_fingers - index) * sizeof(touch->fingers[index])); + touch->fingers[touch->num_fingers] = deleted_finger; + } +} + +void SDL_SendTouch(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, SDL_EventType type, float x, float y, float pressure) +{ + SDL_Finger *finger; + bool down = (type == SDL_EVENT_FINGER_DOWN); + + SDL_Touch *touch = SDL_GetTouch(id); + if (!touch) { + return; + } + + SDL_Mouse *mouse = SDL_GetMouse(); + + // SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events + // SDL_HINT_VITA_TOUCH_MOUSE_DEVICE: controlling which touchpad should generate synthetic mouse events, PSVita-only + { + // FIXME: maybe we should only restrict to a few SDL_TouchDeviceType + if ((id != SDL_MOUSE_TOUCHID) && (id != SDL_PEN_TOUCHID)) { +#ifdef SDL_PLATFORM_VITA + if (mouse->touch_mouse_events && ((mouse->vita_touch_mouse_device == id) || (mouse->vita_touch_mouse_device == 3))) { +#else + if (mouse->touch_mouse_events) { +#endif + if (window) { + if (down) { + if (finger_touching == false) { + float pos_x = (x * (float)window->w); + float pos_y = (y * (float)window->h); + if (pos_x < 0) { + pos_x = 0; + } + if (pos_x > (float)(window->w - 1)) { + pos_x = (float)(window->w - 1); + } + if (pos_y < 0.0f) { + pos_y = 0.0f; + } + if (pos_y > (float)(window->h - 1)) { + pos_y = (float)(window->h - 1); + } + SDL_SendMouseMotion(timestamp, window, SDL_TOUCH_MOUSEID, false, pos_x, pos_y); + SDL_SendMouseButton(timestamp, window, SDL_TOUCH_MOUSEID, SDL_BUTTON_LEFT, true); + } + } else { + if (finger_touching == true && track_touchid == id && track_fingerid == fingerid) { + SDL_SendMouseButton(timestamp, window, SDL_TOUCH_MOUSEID, SDL_BUTTON_LEFT, false); + } + } + } + if (down) { + if (finger_touching == false) { + finger_touching = true; + track_touchid = id; + track_fingerid = fingerid; + } + } else { + if (finger_touching == true && track_touchid == id && track_fingerid == fingerid) { + finger_touching = false; + } + } + } + } + } + + // SDL_HINT_MOUSE_TOUCH_EVENTS: if not set, discard synthetic touch events coming from platform layer + if (!mouse->mouse_touch_events && (id == SDL_MOUSE_TOUCHID)) { + return; + } else if (!mouse->pen_touch_events && (id == SDL_PEN_TOUCHID)) { + return; + } + + finger = SDL_GetFinger(touch, fingerid); + if (down) { + if (finger) { + /* This finger is already down. + Assume the finger-up for the previous touch was lost, and send it. */ + SDL_SendTouch(timestamp, id, fingerid, window, SDL_EVENT_FINGER_CANCELED, x, y, pressure); + } + + if (!SDL_AddFinger(touch, fingerid, x, y, pressure)) { + return; + } + + if (SDL_EventEnabled(type)) { + SDL_Event event; + event.type = type; + event.common.timestamp = timestamp; + event.tfinger.touchID = id; + event.tfinger.fingerID = fingerid; + event.tfinger.x = x; + event.tfinger.y = y; + event.tfinger.dx = 0; + event.tfinger.dy = 0; + event.tfinger.pressure = pressure; + event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0; + SDL_PushEvent(&event); + } + } else { + if (!finger) { + // This finger is already up + return; + } + + if (SDL_EventEnabled(type)) { + SDL_Event event; + event.type = type; + event.common.timestamp = timestamp; + event.tfinger.touchID = id; + event.tfinger.fingerID = fingerid; + // I don't trust the coordinates passed on fingerUp + event.tfinger.x = finger->x; + event.tfinger.y = finger->y; + event.tfinger.dx = 0; + event.tfinger.dy = 0; + event.tfinger.pressure = pressure; + event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0; + SDL_PushEvent(&event); + } + + SDL_DelFinger(touch, fingerid); + } +} + +void SDL_SendTouchMotion(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, + float x, float y, float pressure) +{ + SDL_Touch *touch; + SDL_Finger *finger; + float xrel, yrel, prel; + + touch = SDL_GetTouch(id); + if (!touch) { + return; + } + + SDL_Mouse *mouse = SDL_GetMouse(); + + // SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events + { + if ((id != SDL_MOUSE_TOUCHID) && (id != SDL_PEN_TOUCHID)) { + if (mouse->touch_mouse_events) { + if (window) { + if (finger_touching == true && track_touchid == id && track_fingerid == fingerid) { + float pos_x = (x * (float)window->w); + float pos_y = (y * (float)window->h); + if (pos_x < 0.0f) { + pos_x = 0.0f; + } + if (pos_x > (float)(window->w - 1)) { + pos_x = (float)(window->w - 1); + } + if (pos_y < 0.0f) { + pos_y = 0.0f; + } + if (pos_y > (float)(window->h - 1)) { + pos_y = (float)(window->h - 1); + } + SDL_SendMouseMotion(timestamp, window, SDL_TOUCH_MOUSEID, false, pos_x, pos_y); + } + } + } + } + } + + // SDL_HINT_MOUSE_TOUCH_EVENTS: if not set, discard synthetic touch events coming from platform layer + if (mouse->mouse_touch_events == 0) { + if (id == SDL_MOUSE_TOUCHID) { + return; + } + } + + finger = SDL_GetFinger(touch, fingerid); + if (!finger) { + SDL_SendTouch(timestamp, id, fingerid, window, SDL_EVENT_FINGER_DOWN, x, y, pressure); + return; + } + + xrel = x - finger->x; + yrel = y - finger->y; + prel = pressure - finger->pressure; + + // Drop events that don't change state + if (xrel == 0.0f && yrel == 0.0f && prel == 0.0f) { +#if 0 + printf("Touch event didn't change state - dropped!\n"); +#endif + return; + } + + // Update internal touch coordinates + finger->x = x; + finger->y = y; + finger->pressure = pressure; + + // Post the event, if desired + if (SDL_EventEnabled(SDL_EVENT_FINGER_MOTION)) { + SDL_Event event; + event.type = SDL_EVENT_FINGER_MOTION; + event.common.timestamp = timestamp; + event.tfinger.touchID = id; + event.tfinger.fingerID = fingerid; + event.tfinger.x = x; + event.tfinger.y = y; + event.tfinger.dx = xrel; + event.tfinger.dy = yrel; + event.tfinger.pressure = pressure; + event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0; + SDL_PushEvent(&event); + } +} + +void SDL_DelTouch(SDL_TouchID id) +{ + int i, index; + SDL_Touch *touch; + + if (SDL_num_touch == 0) { + // We've already cleaned up, we won't find this device + return; + } + + index = SDL_GetTouchIndex(id); + touch = SDL_GetTouch(id); + if (!touch) { + return; + } + + for (i = 0; i < touch->max_fingers; ++i) { + SDL_free(touch->fingers[i]); + } + SDL_free(touch->fingers); + SDL_free(touch->name); + SDL_free(touch); + + SDL_num_touch--; + SDL_touchDevices[index] = SDL_touchDevices[SDL_num_touch]; +} + +void SDL_QuitTouch(void) +{ + int i; + + for (i = SDL_num_touch; i--;) { + SDL_DelTouch(SDL_touchDevices[i]->id); + } + SDL_assert(SDL_num_touch == 0); + + SDL_free(SDL_touchDevices); + SDL_touchDevices = NULL; +} diff --git a/contrib/SDL-3.2.8/src/events/SDL_touch_c.h b/contrib/SDL-3.2.8/src/events/SDL_touch_c.h new file mode 100644 index 0000000..db2d64b --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_touch_c.h @@ -0,0 +1,60 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_touch_c_h_ +#define SDL_touch_c_h_ + +typedef struct SDL_Touch +{ + SDL_TouchID id; + SDL_TouchDeviceType type; + int num_fingers; + int max_fingers; + SDL_Finger **fingers; + char *name; +} SDL_Touch; + +// Initialize the touch subsystem +extern bool SDL_InitTouch(void); + +// Returns true if _any_ connected touch devices are known to SDL +extern bool SDL_TouchDevicesAvailable(void); + +// Add a touch, returning the index of the touch, or -1 if there was an error. +extern int SDL_AddTouch(SDL_TouchID id, SDL_TouchDeviceType type, const char *name); + +// Get the touch with a given id +extern SDL_Touch *SDL_GetTouch(SDL_TouchID id); + +// Send a touch down/up event for a touch +extern void SDL_SendTouch(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, SDL_EventType type, float x, float y, float pressure); + +// Send a touch motion event for a touch +extern void SDL_SendTouchMotion(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, float x, float y, float pressure); + +// Remove a touch +extern void SDL_DelTouch(SDL_TouchID id); + +// Shutdown the touch subsystem +extern void SDL_QuitTouch(void); + +#endif // SDL_touch_c_h_ diff --git a/contrib/SDL-3.2.8/src/events/SDL_windowevents.c b/contrib/SDL-3.2.8/src/events/SDL_windowevents.c new file mode 100644 index 0000000..e20cd3a --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_windowevents.c @@ -0,0 +1,300 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// Window event handling code for SDL + +#include "SDL_events_c.h" +#include "SDL_eventwatch_c.h" +#include "SDL_mouse_c.h" +#include "../tray/SDL_tray_utils.h" + + +#define NUM_WINDOW_EVENT_WATCH_PRIORITIES (SDL_WINDOW_EVENT_WATCH_NORMAL + 1) + +static SDL_EventWatchList SDL_window_event_watchers[NUM_WINDOW_EVENT_WATCH_PRIORITIES]; + +void SDL_InitWindowEventWatch(void) +{ + for (int i = 0; i < SDL_arraysize(SDL_window_event_watchers); ++i) { + SDL_InitEventWatchList(&SDL_window_event_watchers[i]); + } +} + +void SDL_QuitWindowEventWatch(void) +{ + for (int i = 0; i < SDL_arraysize(SDL_window_event_watchers); ++i) { + SDL_QuitEventWatchList(&SDL_window_event_watchers[i]); + } +} + +void SDL_AddWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata) +{ + SDL_AddEventWatchList(&SDL_window_event_watchers[priority], filter, userdata); +} + +void SDL_RemoveWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata) +{ + SDL_RemoveEventWatchList(&SDL_window_event_watchers[priority], filter, userdata); +} + +static bool SDLCALL RemoveSupercededWindowEvents(void *userdata, SDL_Event *event) +{ + SDL_Event *new_event = (SDL_Event *)userdata; + + if (event->type == new_event->type && + event->window.windowID == new_event->window.windowID) { + // We're about to post a new move event, drop the old one + return false; + } + return true; +} + +bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data1, int data2) +{ + bool posted = false; + + if (!window) { + return false; + } + SDL_assert(SDL_ObjectValid(window, SDL_OBJECT_TYPE_WINDOW)); + + if (window->is_destroying && windowevent != SDL_EVENT_WINDOW_DESTROYED) { + return false; + } + switch (windowevent) { + case SDL_EVENT_WINDOW_SHOWN: + if (!(window->flags & SDL_WINDOW_HIDDEN)) { + return false; + } + window->flags &= ~(SDL_WINDOW_HIDDEN | SDL_WINDOW_MINIMIZED); + break; + case SDL_EVENT_WINDOW_HIDDEN: + if (window->flags & SDL_WINDOW_HIDDEN) { + return false; + } + window->flags |= SDL_WINDOW_HIDDEN; + break; + case SDL_EVENT_WINDOW_EXPOSED: + window->flags &= ~SDL_WINDOW_OCCLUDED; + break; + case SDL_EVENT_WINDOW_MOVED: + window->undefined_x = false; + window->undefined_y = false; + window->last_position_pending = false; + if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { + window->windowed.x = data1; + window->windowed.y = data2; + + if (!(window->flags & SDL_WINDOW_MAXIMIZED) && !window->tiled) { + window->floating.x = data1; + window->floating.y = data2; + } + } + if (data1 == window->x && data2 == window->y) { + return false; + } + window->x = data1; + window->y = data2; + break; + case SDL_EVENT_WINDOW_RESIZED: + window->last_size_pending = false; + if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { + window->windowed.w = data1; + window->windowed.h = data2; + + if (!(window->flags & SDL_WINDOW_MAXIMIZED) && !window->tiled) { + window->floating.w = data1; + window->floating.h = data2; + } + } + if (data1 == window->w && data2 == window->h) { + SDL_CheckWindowPixelSizeChanged(window); + return false; + } + window->w = data1; + window->h = data2; + break; + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: + if (data1 == window->last_pixel_w && data2 == window->last_pixel_h) { + return false; + } + window->last_pixel_w = data1; + window->last_pixel_h = data2; + break; + case SDL_EVENT_WINDOW_MINIMIZED: + if (window->flags & SDL_WINDOW_MINIMIZED) { + return false; + } + window->flags &= ~SDL_WINDOW_MAXIMIZED; + window->flags |= SDL_WINDOW_MINIMIZED; + break; + case SDL_EVENT_WINDOW_MAXIMIZED: + if (window->flags & SDL_WINDOW_MAXIMIZED) { + return false; + } + window->flags &= ~SDL_WINDOW_MINIMIZED; + window->flags |= SDL_WINDOW_MAXIMIZED; + break; + case SDL_EVENT_WINDOW_RESTORED: + if (!(window->flags & (SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED))) { + return false; + } + window->flags &= ~(SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED); + break; + case SDL_EVENT_WINDOW_MOUSE_ENTER: + if (window->flags & SDL_WINDOW_MOUSE_FOCUS) { + return false; + } + window->flags |= SDL_WINDOW_MOUSE_FOCUS; + break; + case SDL_EVENT_WINDOW_MOUSE_LEAVE: + if (!(window->flags & SDL_WINDOW_MOUSE_FOCUS)) { + return false; + } + window->flags &= ~SDL_WINDOW_MOUSE_FOCUS; + break; + case SDL_EVENT_WINDOW_FOCUS_GAINED: + if (window->flags & SDL_WINDOW_INPUT_FOCUS) { + return false; + } + window->flags |= SDL_WINDOW_INPUT_FOCUS; + break; + case SDL_EVENT_WINDOW_FOCUS_LOST: + if (!(window->flags & SDL_WINDOW_INPUT_FOCUS)) { + return false; + } + window->flags &= ~SDL_WINDOW_INPUT_FOCUS; + break; + case SDL_EVENT_WINDOW_DISPLAY_CHANGED: + if (data1 == 0 || (SDL_DisplayID)data1 == window->last_displayID) { + return false; + } + window->last_displayID = (SDL_DisplayID)data1; + break; + case SDL_EVENT_WINDOW_OCCLUDED: + if (window->flags & SDL_WINDOW_OCCLUDED) { + return false; + } + window->flags |= SDL_WINDOW_OCCLUDED; + break; + case SDL_EVENT_WINDOW_ENTER_FULLSCREEN: + if (window->flags & SDL_WINDOW_FULLSCREEN) { + return false; + } + window->flags |= SDL_WINDOW_FULLSCREEN; + break; + case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN: + if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { + return false; + } + window->flags &= ~SDL_WINDOW_FULLSCREEN; + break; + default: + break; + } + + // Post the event, if desired + SDL_Event event; + event.type = windowevent; + event.common.timestamp = 0; + event.window.data1 = data1; + event.window.data2 = data2; + event.window.windowID = window->id; + + SDL_DispatchEventWatchList(&SDL_window_event_watchers[SDL_WINDOW_EVENT_WATCH_EARLY], &event); + SDL_DispatchEventWatchList(&SDL_window_event_watchers[SDL_WINDOW_EVENT_WATCH_NORMAL], &event); + + if (SDL_EventEnabled(windowevent)) { + // Fixes queue overflow with move/resize events that aren't processed + if (windowevent == SDL_EVENT_WINDOW_MOVED || + windowevent == SDL_EVENT_WINDOW_RESIZED || + windowevent == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED || + windowevent == SDL_EVENT_WINDOW_SAFE_AREA_CHANGED || + windowevent == SDL_EVENT_WINDOW_EXPOSED || + windowevent == SDL_EVENT_WINDOW_OCCLUDED) { + SDL_FilterEvents(RemoveSupercededWindowEvents, &event); + } + posted = SDL_PushEvent(&event); + } + + switch (windowevent) { + case SDL_EVENT_WINDOW_SHOWN: + SDL_OnWindowShown(window); + break; + case SDL_EVENT_WINDOW_HIDDEN: + SDL_OnWindowHidden(window); + break; + case SDL_EVENT_WINDOW_MOVED: + SDL_OnWindowMoved(window); + break; + case SDL_EVENT_WINDOW_RESIZED: + SDL_OnWindowResized(window); + break; + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: + SDL_OnWindowPixelSizeChanged(window); + break; + case SDL_EVENT_WINDOW_MINIMIZED: + SDL_OnWindowMinimized(window); + break; + case SDL_EVENT_WINDOW_MAXIMIZED: + SDL_OnWindowMaximized(window); + break; + case SDL_EVENT_WINDOW_RESTORED: + SDL_OnWindowRestored(window); + break; + case SDL_EVENT_WINDOW_MOUSE_ENTER: + SDL_OnWindowEnter(window); + break; + case SDL_EVENT_WINDOW_MOUSE_LEAVE: + SDL_OnWindowLeave(window); + break; + case SDL_EVENT_WINDOW_FOCUS_GAINED: + SDL_OnWindowFocusGained(window); + break; + case SDL_EVENT_WINDOW_FOCUS_LOST: + SDL_OnWindowFocusLost(window); + break; + case SDL_EVENT_WINDOW_DISPLAY_CHANGED: + SDL_OnWindowDisplayChanged(window); + break; + default: + break; + } + + if (windowevent == SDL_EVENT_WINDOW_CLOSE_REQUESTED && !window->parent && !SDL_HasActiveTrays()) { + int toplevel_count = 0; + SDL_Window *n; + for (n = SDL_GetVideoDevice()->windows; n; n = n->next) { + if (!n->parent && !(n->flags & SDL_WINDOW_HIDDEN)) { + ++toplevel_count; + } + } + + if (toplevel_count <= 1) { + if (SDL_GetHintBoolean(SDL_HINT_QUIT_ON_LAST_WINDOW_CLOSE, true)) { + SDL_SendQuit(); // This is the last toplevel window in the list so send the SDL_EVENT_QUIT event + } + } + } + + return posted; +} diff --git a/contrib/SDL-3.2.8/src/events/SDL_windowevents_c.h b/contrib/SDL-3.2.8/src/events/SDL_windowevents_c.h new file mode 100644 index 0000000..7204305 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/SDL_windowevents_c.h @@ -0,0 +1,39 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_windowevents_c_h_ +#define SDL_windowevents_c_h_ + +typedef enum +{ + SDL_WINDOW_EVENT_WATCH_EARLY, + SDL_WINDOW_EVENT_WATCH_NORMAL +} SDL_WindowEventWatchPriority; + +extern void SDL_InitWindowEventWatch(void); +extern void SDL_QuitWindowEventWatch(void); +extern void SDL_AddWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata); +extern void SDL_RemoveWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata); + +extern bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data1, int data2); + +#endif // SDL_windowevents_c_h_ diff --git a/contrib/SDL-3.2.8/src/events/blank_cursor.h b/contrib/SDL-3.2.8/src/events/blank_cursor.h new file mode 100644 index 0000000..d8d9b4d --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/blank_cursor.h @@ -0,0 +1,31 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * A default blank 8x8 cursor */ + +#define BLANK_CWIDTH 8 +#define BLANK_CHEIGHT 8 +#define BLANK_CHOTX 0 +#define BLANK_CHOTY 0 + +static const unsigned char blank_cdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static const unsigned char blank_cmask[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; diff --git a/contrib/SDL-3.2.8/src/events/default_cursor.h b/contrib/SDL-3.2.8/src/events/default_cursor.h new file mode 100644 index 0000000..9a76f94 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/default_cursor.h @@ -0,0 +1,113 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Default cursor - it happens to be the Mac cursor, but could be anything */ + +#define DEFAULT_CWIDTH 16 +#define DEFAULT_CHEIGHT 16 +#define DEFAULT_CHOTX 0 +#define DEFAULT_CHOTY 0 + +// Added a real MacOS cursor, at the request of Luc-Olivier de Charrière +#define USE_MACOS_CURSOR + +#ifdef USE_MACOS_CURSOR + +static const unsigned char default_cdata[] = { + 0x00, 0x00, + 0x40, 0x00, + 0x60, 0x00, + 0x70, 0x00, + 0x78, 0x00, + 0x7C, 0x00, + 0x7E, 0x00, + 0x7F, 0x00, + 0x7F, 0x80, + 0x7C, 0x00, + 0x6C, 0x00, + 0x46, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x00, 0x00 +}; + +static const unsigned char default_cmask[] = { + 0xC0, 0x00, + 0xE0, 0x00, + 0xF0, 0x00, + 0xF8, 0x00, + 0xFC, 0x00, + 0xFE, 0x00, + 0xFF, 0x00, + 0xFF, 0x80, + 0xFF, 0xC0, + 0xFF, 0xE0, + 0xFE, 0x00, + 0xEF, 0x00, + 0xCF, 0x00, + 0x87, 0x80, + 0x07, 0x80, + 0x03, 0x00 +}; + +#else + +static const unsigned char default_cdata[] = { + 0x00, 0x00, + 0x40, 0x00, + 0x60, 0x00, + 0x70, 0x00, + 0x78, 0x00, + 0x7C, 0x00, + 0x7E, 0x00, + 0x7F, 0x00, + 0x7F, 0x80, + 0x7C, 0x00, + 0x6C, 0x00, + 0x46, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x00, 0x00 +}; + +static const unsigned char default_cmask[] = { + 0x40, 0x00, + 0xE0, 0x00, + 0xF0, 0x00, + 0xF8, 0x00, + 0xFC, 0x00, + 0xFE, 0x00, + 0xFF, 0x00, + 0xFF, 0x80, + 0xFF, 0xC0, + 0xFF, 0x80, + 0xFE, 0x00, + 0xEF, 0x00, + 0x4F, 0x00, + 0x07, 0x80, + 0x07, 0x80, + 0x03, 0x00 +}; + +#endif // USE_MACOS_CURSOR diff --git a/contrib/SDL-3.2.8/src/events/imKStoUCS.c b/contrib/SDL-3.2.8/src/events/imKStoUCS.c new file mode 100644 index 0000000..503abb0 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/imKStoUCS.c @@ -0,0 +1,349 @@ +/* +Copyright (C) 2003-2006,2008 Jamey Sharp, Josh Triplett +Copyright © 2009 Red Hat, Inc. +Copyright 1990-1992,1999,2000,2004,2009,2010 Oracle and/or its affiliates. +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include "SDL_internal.h" + +#if defined(SDL_VIDEO_DRIVER_X11) || defined(SDL_VIDEO_DRIVER_WAYLAND) +#include "imKStoUCS.h" + +static unsigned short const keysym_to_unicode_1a1_1ff[] = { + 0x0104, 0x02d8, 0x0141, 0x0000, 0x013d, 0x015a, 0x0000, /* 0x01a0-0x01a7 */ + 0x0000, 0x0160, 0x015e, 0x0164, 0x0179, 0x0000, 0x017d, 0x017b, /* 0x01a8-0x01af */ + 0x0000, 0x0105, 0x02db, 0x0142, 0x0000, 0x013e, 0x015b, 0x02c7, /* 0x01b0-0x01b7 */ + 0x0000, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c, /* 0x01b8-0x01bf */ + 0x0154, 0x0000, 0x0000, 0x0102, 0x0000, 0x0139, 0x0106, 0x0000, /* 0x01c0-0x01c7 */ + 0x010c, 0x0000, 0x0118, 0x0000, 0x011a, 0x0000, 0x0000, 0x010e, /* 0x01c8-0x01cf */ + 0x0110, 0x0143, 0x0147, 0x0000, 0x0000, 0x0150, 0x0000, 0x0000, /* 0x01d0-0x01d7 */ + 0x0158, 0x016e, 0x0000, 0x0170, 0x0000, 0x0000, 0x0162, 0x0000, /* 0x01d8-0x01df */ + 0x0155, 0x0000, 0x0000, 0x0103, 0x0000, 0x013a, 0x0107, 0x0000, /* 0x01e0-0x01e7 */ + 0x010d, 0x0000, 0x0119, 0x0000, 0x011b, 0x0000, 0x0000, 0x010f, /* 0x01e8-0x01ef */ + 0x0111, 0x0144, 0x0148, 0x0000, 0x0000, 0x0151, 0x0000, 0x0000, /* 0x01f0-0x01f7 */ + 0x0159, 0x016f, 0x0000, 0x0171, 0x0000, 0x0000, 0x0163, 0x02d9 /* 0x01f8-0x01ff */ +}; + +static unsigned short const keysym_to_unicode_2a1_2fe[] = { + 0x0126, 0x0000, 0x0000, 0x0000, 0x0000, 0x0124, 0x0000, /* 0x02a0-0x02a7 */ + 0x0000, 0x0130, 0x0000, 0x011e, 0x0134, 0x0000, 0x0000, 0x0000, /* 0x02a8-0x02af */ + 0x0000, 0x0127, 0x0000, 0x0000, 0x0000, 0x0000, 0x0125, 0x0000, /* 0x02b0-0x02b7 */ + 0x0000, 0x0131, 0x0000, 0x011f, 0x0135, 0x0000, 0x0000, 0x0000, /* 0x02b8-0x02bf */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x010a, 0x0108, 0x0000, /* 0x02c0-0x02c7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x02c8-0x02cf */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0120, 0x0000, 0x0000, /* 0x02d0-0x02d7 */ + 0x011c, 0x0000, 0x0000, 0x0000, 0x0000, 0x016c, 0x015c, 0x0000, /* 0x02d8-0x02df */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x010b, 0x0109, 0x0000, /* 0x02e0-0x02e7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x02e8-0x02ef */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0121, 0x0000, 0x0000, /* 0x02f0-0x02f7 */ + 0x011d, 0x0000, 0x0000, 0x0000, 0x0000, 0x016d, 0x015d /* 0x02f8-0x02ff */ +}; + +static unsigned short const keysym_to_unicode_3a2_3fe[] = { + 0x0138, 0x0156, 0x0000, 0x0128, 0x013b, 0x0000, /* 0x03a0-0x03a7 */ + 0x0000, 0x0000, 0x0112, 0x0122, 0x0166, 0x0000, 0x0000, 0x0000, /* 0x03a8-0x03af */ + 0x0000, 0x0000, 0x0000, 0x0157, 0x0000, 0x0129, 0x013c, 0x0000, /* 0x03b0-0x03b7 */ + 0x0000, 0x0000, 0x0113, 0x0123, 0x0167, 0x014a, 0x0000, 0x014b, /* 0x03b8-0x03bf */ + 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012e, /* 0x03c0-0x03c7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0116, 0x0000, 0x0000, 0x012a, /* 0x03c8-0x03cf */ + 0x0000, 0x0145, 0x014c, 0x0136, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x03d0-0x03d7 */ + 0x0000, 0x0172, 0x0000, 0x0000, 0x0000, 0x0168, 0x016a, 0x0000, /* 0x03d8-0x03df */ + 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012f, /* 0x03e0-0x03e7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0117, 0x0000, 0x0000, 0x012b, /* 0x03e8-0x03ef */ + 0x0000, 0x0146, 0x014d, 0x0137, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x03f0-0x03f7 */ + 0x0000, 0x0173, 0x0000, 0x0000, 0x0000, 0x0169, 0x016b /* 0x03f8-0x03ff */ +}; + +static unsigned short const keysym_to_unicode_4a1_4df[] = { + 0x3002, 0x3008, 0x3009, 0x3001, 0x30fb, 0x30f2, 0x30a1, /* 0x04a0-0x04a7 */ + 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, 0x30c3, /* 0x04a8-0x04af */ + 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, 0x30ad, /* 0x04b0-0x04b7 */ + 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9, 0x30bb, 0x30bd, /* 0x04b8-0x04bf */ + 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca, 0x30cb, 0x30cc, /* 0x04c0-0x04c7 */ + 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de, /* 0x04c8-0x04cf */ + 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9, /* 0x04d0-0x04d7 */ + 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c /* 0x04d8-0x04df */ +}; + +static unsigned short const keysym_to_unicode_590_5fe[] = { + 0x06f0, 0x06f1, 0x06f2, 0x06f3, 0x06f4, 0x06f5, 0x06f6, 0x06f7, /* 0x0590-0x0597 */ + 0x06f8, 0x06f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x0598-0x059f */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x066a, 0x0670, 0x0679, /* 0x05a0-0x05a7 */ + + 0x067e, 0x0686, 0x0688, 0x0691, 0x060c, 0x0000, 0x06d4, 0x0000, /* 0x05ac-0x05af */ + 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, /* 0x05b0-0x05b7 */ + 0x0668, 0x0669, 0x0000, 0x061b, 0x0000, 0x0000, 0x0000, 0x061f, /* 0x05b8-0x05bf */ + 0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, /* 0x05c0-0x05c7 */ + 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f, /* 0x05c8-0x05cf */ + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, /* 0x05d0-0x05d7 */ + 0x0638, 0x0639, 0x063a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x05d8-0x05df */ + 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, /* 0x05e0-0x05e7 */ + 0x0648, 0x0649, 0x064a, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f, /* 0x05e8-0x05ef */ + 0x0650, 0x0651, 0x0652, 0x0653, 0x0654, 0x0655, 0x0698, 0x06a4, /* 0x05f0-0x05f7 */ + 0x06a9, 0x06af, 0x06ba, 0x06be, 0x06cc, 0x06d2, 0x06c1 /* 0x05f8-0x05fe */ +}; + +static unsigned short keysym_to_unicode_680_6ff[] = { + 0x0492, 0x0496, 0x049a, 0x049c, 0x04a2, 0x04ae, 0x04b0, 0x04b2, /* 0x0680-0x0687 */ + 0x04b6, 0x04b8, 0x04ba, 0x0000, 0x04d8, 0x04e2, 0x04e8, 0x04ee, /* 0x0688-0x068f */ + 0x0493, 0x0497, 0x049b, 0x049d, 0x04a3, 0x04af, 0x04b1, 0x04b3, /* 0x0690-0x0697 */ + 0x04b7, 0x04b9, 0x04bb, 0x0000, 0x04d9, 0x04e3, 0x04e9, 0x04ef, /* 0x0698-0x069f */ + 0x0000, 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457, /* 0x06a0-0x06a7 */ + 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x0491, 0x045e, 0x045f, /* 0x06a8-0x06af */ + 0x2116, 0x0402, 0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407, /* 0x06b0-0x06b7 */ + 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x0490, 0x040e, 0x040f, /* 0x06b8-0x06bf */ + 0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, /* 0x06c0-0x06c7 */ + 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, /* 0x06c8-0x06cf */ + 0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, /* 0x06d0-0x06d7 */ + 0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a, /* 0x06d8-0x06df */ + 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, /* 0x06e0-0x06e7 */ + 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, /* 0x06e8-0x06ef */ + 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, /* 0x06f0-0x06f7 */ + 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a /* 0x06f8-0x06ff */ +}; + +static unsigned short const keysym_to_unicode_7a1_7f9[] = { + 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c, /* 0x07a0-0x07a7 */ + 0x038e, 0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015, /* 0x07a8-0x07af */ + 0x0000, 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc, /* 0x07b0-0x07b7 */ + 0x03cd, 0x03cb, 0x03b0, 0x03ce, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x07b8-0x07bf */ + 0x0000, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, /* 0x07c0-0x07c7 */ + 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, /* 0x07c8-0x07cf */ + 0x03a0, 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5, 0x03a6, 0x03a7, /* 0x07d0-0x07d7 */ + 0x03a8, 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x07d8-0x07df */ + 0x0000, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, /* 0x07e0-0x07e7 */ + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, /* 0x07e8-0x07ef */ + 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, /* 0x07f0-0x07f7 */ + 0x03c8, 0x03c9 /* 0x07f8-0x07ff */ +}; + +static unsigned short const keysym_to_unicode_8a4_8fe[] = { + 0x2320, 0x2321, 0x0000, 0x231c, /* 0x08a0-0x08a7 */ + 0x231d, 0x231e, 0x231f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08a8-0x08af */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08b0-0x08b7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x2264, 0x2260, 0x2265, 0x222b, /* 0x08b8-0x08bf */ + 0x2234, 0x0000, 0x221e, 0x0000, 0x0000, 0x2207, 0x0000, 0x0000, /* 0x08c0-0x08c7 */ + 0x2245, 0x2246, 0x0000, 0x0000, 0x0000, 0x0000, 0x21d2, 0x0000, /* 0x08c8-0x08cf */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x221a, 0x0000, /* 0x08d0-0x08d7 */ + 0x0000, 0x0000, 0x2282, 0x2283, 0x2229, 0x222a, 0x2227, 0x2228, /* 0x08d8-0x08df */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08e0-0x08e7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2202, /* 0x08e8-0x08ef */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000, /* 0x08f0-0x08f7 */ + 0x0000, 0x0000, 0x0000, 0x2190, 0x2191, 0x2192, 0x2193 /* 0x08f8-0x08ff */ +}; + +static unsigned short const keysym_to_unicode_9df_9f8[] = { + 0x2422, /* 0x09d8-0x09df */ + 0x2666, 0x25a6, 0x2409, 0x240c, 0x240d, 0x240a, 0x0000, 0x0000, /* 0x09e0-0x09e7 */ + 0x240a, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x2500, /* 0x09e8-0x09ef */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x251c, 0x2524, 0x2534, 0x252c, /* 0x09f0-0x09f7 */ + 0x2502 /* 0x09f8-0x09ff */ +}; + +static unsigned short const keysym_to_unicode_aa1_afe[] = { + 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009, /* 0x0aa0-0x0aa7 */ + 0x200a, 0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025, /* 0x0aa8-0x0aaf */ + 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, /* 0x0ab0-0x0ab7 */ + 0x2105, 0x0000, 0x0000, 0x2012, 0x2039, 0x2024, 0x203a, 0x0000, /* 0x0ab8-0x0abf */ + 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e, 0x0000, /* 0x0ac0-0x0ac7 */ + 0x0000, 0x2122, 0x2120, 0x0000, 0x25c1, 0x25b7, 0x25cb, 0x25ad, /* 0x0ac8-0x0acf */ + 0x2018, 0x2019, 0x201c, 0x201d, 0x211e, 0x2030, 0x2032, 0x2033, /* 0x0ad0-0x0ad7 */ + 0x0000, 0x271d, 0x0000, 0x220e, 0x25c2, 0x2023, 0x25cf, 0x25ac, /* 0x0ad8-0x0adf */ + 0x25e6, 0x25ab, 0x25ae, 0x25b5, 0x25bf, 0x2606, 0x2022, 0x25aa, /* 0x0ae0-0x0ae7 */ + 0x25b4, 0x25be, 0x261a, 0x261b, 0x2663, 0x2666, 0x2665, 0x0000, /* 0x0ae8-0x0aef */ + 0x2720, 0x2020, 0x2021, 0x2713, 0x2612, 0x266f, 0x266d, 0x2642, /* 0x0af0-0x0af7 */ + 0x2640, 0x2121, 0x2315, 0x2117, 0x2038, 0x201a, 0x201e /* 0x0af8-0x0aff */ +}; + +/* none of the APL keysyms match the Unicode characters */ + +static unsigned short const keysym_to_unicode_cdf_cfa[] = { + 0x2017, /* 0x0cd8-0x0cdf */ + 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, /* 0x0ce0-0x0ce7 */ + 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, /* 0x0ce8-0x0cef */ + 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, /* 0x0cf0-0x0cf7 */ + 0x05e8, 0x05e9, 0x05ea /* 0x0cf8-0x0cff */ +}; + +static unsigned short const keysym_to_unicode_da1_df9[] = { + 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07, /* 0x0da0-0x0da7 */ + 0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f, /* 0x0da8-0x0daf */ + 0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17, /* 0x0db0-0x0db7 */ + 0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f, /* 0x0db8-0x0dbf */ + 0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27, /* 0x0dc0-0x0dc7 */ + 0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f, /* 0x0dc8-0x0dcf */ + 0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37, /* 0x0dd0-0x0dd7 */ + 0x0e38, 0x0e39, 0x0e3a, 0x0000, 0x0000, 0x0000, 0x0e3e, 0x0e3f, /* 0x0dd8-0x0ddf */ + 0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47, /* 0x0de0-0x0de7 */ + 0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0000, 0x0000, /* 0x0de8-0x0def */ + 0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57, /* 0x0df0-0x0df7 */ + 0x0e58, 0x0e59 /* 0x0df8-0x0dff */ +}; + +static unsigned short const keysym_to_unicode_ea0_eff[] = { + 0x0000, 0x1101, 0x1101, 0x11aa, 0x1102, 0x11ac, 0x11ad, 0x1103, /* 0x0ea0-0x0ea7 */ + 0x1104, 0x1105, 0x11b0, 0x11b1, 0x11b2, 0x11b3, 0x11b4, 0x11b5, /* 0x0ea8-0x0eaf */ + 0x11b6, 0x1106, 0x1107, 0x1108, 0x11b9, 0x1109, 0x110a, 0x110b, /* 0x0eb0-0x0eb7 */ + 0x110c, 0x110d, 0x110e, 0x110f, 0x1110, 0x1111, 0x1112, 0x1161, /* 0x0eb8-0x0ebf */ + 0x1162, 0x1163, 0x1164, 0x1165, 0x1166, 0x1167, 0x1168, 0x1169, /* 0x0ec0-0x0ec7 */ + 0x116a, 0x116b, 0x116c, 0x116d, 0x116e, 0x116f, 0x1170, 0x1171, /* 0x0ec8-0x0ecf */ + 0x1172, 0x1173, 0x1174, 0x1175, 0x11a8, 0x11a9, 0x11aa, 0x11ab, /* 0x0ed0-0x0ed7 */ + 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, 0x11b3, /* 0x0ed8-0x0edf */ + 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb, /* 0x0ee0-0x0ee7 */ + 0x11bc, 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x0000, /* 0x0ee8-0x0eef */ + 0x0000, 0x0000, 0x1140, 0x0000, 0x0000, 0x1159, 0x119e, 0x0000, /* 0x0ef0-0x0ef7 */ + 0x11eb, 0x0000, 0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9, /* 0x0ef8-0x0eff */ +}; + +static unsigned short keysym_to_unicode_12a1_12fe[] = { + 0x1e02, 0x1e03, 0x0000, 0x0000, 0x0000, 0x1e0a, 0x0000, /* 0x12a0-0x12a7 */ + 0x1e80, 0x0000, 0x1e82, 0x1e0b, 0x1ef2, 0x0000, 0x0000, 0x0000, /* 0x12a8-0x12af */ + 0x1e1e, 0x1e1f, 0x0000, 0x0000, 0x1e40, 0x1e41, 0x0000, 0x1e56, /* 0x12b0-0x12b7 */ + 0x1e81, 0x1e57, 0x1e83, 0x1e60, 0x1ef3, 0x1e84, 0x1e85, 0x1e61, /* 0x12b8-0x12bf */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12c0-0x12c7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12c8-0x12cf */ + 0x0174, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e6a, /* 0x12d0-0x12d7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0176, 0x0000, /* 0x12d8-0x12df */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12e0-0x12e7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12e8-0x12ef */ + 0x0175, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e6b, /* 0x12f0-0x12f7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0177 /* 0x12f0-0x12ff */ +}; + +static unsigned short const keysym_to_unicode_13bc_13be[] = { + 0x0152, 0x0153, 0x0178 /* 0x13b8-0x13bf */ +}; + +static unsigned short keysym_to_unicode_14a1_14ff[] = { + 0x2741, 0x00a7, 0x0589, 0x0029, 0x0028, 0x00bb, 0x00ab, /* 0x14a0-0x14a7 */ + 0x2014, 0x002e, 0x055d, 0x002c, 0x2013, 0x058a, 0x2026, 0x055c, /* 0x14a8-0x14af */ + 0x055b, 0x055e, 0x0531, 0x0561, 0x0532, 0x0562, 0x0533, 0x0563, /* 0x14b0-0x14b7 */ + 0x0534, 0x0564, 0x0535, 0x0565, 0x0536, 0x0566, 0x0537, 0x0567, /* 0x14b8-0x14bf */ + 0x0538, 0x0568, 0x0539, 0x0569, 0x053a, 0x056a, 0x053b, 0x056b, /* 0x14c0-0x14c7 */ + 0x053c, 0x056c, 0x053d, 0x056d, 0x053e, 0x056e, 0x053f, 0x056f, /* 0x14c8-0x14cf */ + 0x0540, 0x0570, 0x0541, 0x0571, 0x0542, 0x0572, 0x0543, 0x0573, /* 0x14d0-0x14d7 */ + 0x0544, 0x0574, 0x0545, 0x0575, 0x0546, 0x0576, 0x0547, 0x0577, /* 0x14d8-0x14df */ + 0x0548, 0x0578, 0x0549, 0x0579, 0x054a, 0x057a, 0x054b, 0x057b, /* 0x14e0-0x14e7 */ + 0x054c, 0x057c, 0x054d, 0x057d, 0x054e, 0x057e, 0x054f, 0x057f, /* 0x14e8-0x14ef */ + 0x0550, 0x0580, 0x0551, 0x0581, 0x0552, 0x0582, 0x0553, 0x0583, /* 0x14f0-0x14f7 */ + 0x0554, 0x0584, 0x0555, 0x0585, 0x0556, 0x0586, 0x2019, 0x0027, /* 0x14f8-0x14ff */ +}; + +static unsigned short keysym_to_unicode_15d0_15f6[] = { + 0x10d0, 0x10d1, 0x10d2, 0x10d3, 0x10d4, 0x10d5, 0x10d6, 0x10d7, /* 0x15d0-0x15d7 */ + 0x10d8, 0x10d9, 0x10da, 0x10db, 0x10dc, 0x10dd, 0x10de, 0x10df, /* 0x15d8-0x15df */ + 0x10e0, 0x10e1, 0x10e2, 0x10e3, 0x10e4, 0x10e5, 0x10e6, 0x10e7, /* 0x15e0-0x15e7 */ + 0x10e8, 0x10e9, 0x10ea, 0x10eb, 0x10ec, 0x10ed, 0x10ee, 0x10ef, /* 0x15e8-0x15ef */ + 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6 /* 0x15f0-0x15f7 */ +}; + +static unsigned short keysym_to_unicode_16a0_16f6[] = { + 0x0000, 0x0000, 0xf0a2, 0x1e8a, 0x0000, 0xf0a5, 0x012c, 0xf0a7, /* 0x16a0-0x16a7 */ + 0xf0a8, 0x01b5, 0x01e6, 0x0000, 0x0000, 0x0000, 0x0000, 0x019f, /* 0x16a8-0x16af */ + 0x0000, 0x0000, 0xf0b2, 0x1e8b, 0x01d1, 0xf0b5, 0x012d, 0xf0b7, /* 0x16b0-0x16b7 */ + 0xf0b8, 0x01b6, 0x01e7, 0x0000, 0x0000, 0x01d2, 0x0000, 0x0275, /* 0x16b8-0x16bf */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x018f, 0x0000, /* 0x16c0-0x16c7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16c8-0x16cf */ + 0x0000, 0x1e36, 0xf0d2, 0xf0d3, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16d0-0x16d7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16d8-0x16df */ + 0x0000, 0x1e37, 0xf0e2, 0xf0e3, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16e0-0x16e7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16e8-0x16ef */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0259 /* 0x16f0-0x16f6 */ +}; + +static unsigned short const keysym_to_unicode_1e9f_1eff[] = { + 0x0303, + 0x1ea0, 0x1ea1, 0x1ea2, 0x1ea3, 0x1ea4, 0x1ea5, 0x1ea6, 0x1ea7, /* 0x1ea0-0x1ea7 */ + 0x1ea8, 0x1ea9, 0x1eaa, 0x1eab, 0x1eac, 0x1ead, 0x1eae, 0x1eaf, /* 0x1ea8-0x1eaf */ + 0x1eb0, 0x1eb1, 0x1eb2, 0x1eb3, 0x1eb4, 0x1eb5, 0x1eb6, 0x1eb7, /* 0x1eb0-0x1eb7 */ + 0x1eb8, 0x1eb9, 0x1eba, 0x1ebb, 0x1ebc, 0x1ebd, 0x1ebe, 0x1ebf, /* 0x1eb8-0x1ebf */ + 0x1ec0, 0x1ec1, 0x1ec2, 0x1ec3, 0x1ec4, 0x1ec5, 0x1ec6, 0x1ec7, /* 0x1ec0-0x1ec7 */ + 0x1ec8, 0x1ec9, 0x1eca, 0x1ecb, 0x1ecc, 0x1ecd, 0x1ece, 0x1ecf, /* 0x1ec8-0x1ecf */ + 0x1ed0, 0x1ed1, 0x1ed2, 0x1ed3, 0x1ed4, 0x1ed5, 0x1ed6, 0x1ed7, /* 0x1ed0-0x1ed7 */ + 0x1ed8, 0x1ed9, 0x1eda, 0x1edb, 0x1edc, 0x1edd, 0x1ede, 0x1edf, /* 0x1ed8-0x1edf */ + 0x1ee0, 0x1ee1, 0x1ee2, 0x1ee3, 0x1ee4, 0x1ee5, 0x1ee6, 0x1ee7, /* 0x1ee0-0x1ee7 */ + 0x1ee8, 0x1ee9, 0x1eea, 0x1eeb, 0x1eec, 0x1eed, 0x1eee, 0x1eef, /* 0x1ee8-0x1eef */ + 0x1ef0, 0x1ef1, 0x0300, 0x0301, 0x1ef4, 0x1ef5, 0x1ef6, 0x1ef7, /* 0x1ef0-0x1ef7 */ + 0x1ef8, 0x1ef9, 0x01a0, 0x01a1, 0x01af, 0x01b0, 0x0309, 0x0323 /* 0x1ef8-0x1eff */ +}; + +static unsigned short const keysym_to_unicode_20a0_20ac[] = { + 0x20a0, 0x20a1, 0x20a2, 0x20a3, 0x20a4, 0x20a5, 0x20a6, 0x20a7, /* 0x20a0-0x20a7 */ + 0x20a8, 0x20a9, 0x20aa, 0x20ab, 0x20ac /* 0x20a8-0x20af */ +}; + +unsigned int +SDL_KeySymToUcs4(Uint32 keysym) +{ + /* 'Unicode keysym' */ + if ((keysym & 0xff000000) == 0x01000000) + return (keysym & 0x00ffffff); + + if (keysym > 0 && keysym < 0x100) + return keysym; + else if (keysym > 0x1a0 && keysym < 0x200) + return keysym_to_unicode_1a1_1ff[keysym - 0x1a1]; + else if (keysym > 0x2a0 && keysym < 0x2ff) + return keysym_to_unicode_2a1_2fe[keysym - 0x2a1]; + else if (keysym > 0x3a1 && keysym < 0x3ff) + return keysym_to_unicode_3a2_3fe[keysym - 0x3a2]; + else if (keysym > 0x4a0 && keysym < 0x4e0) + return keysym_to_unicode_4a1_4df[keysym - 0x4a1]; + else if (keysym > 0x589 && keysym < 0x5ff) + return keysym_to_unicode_590_5fe[keysym - 0x590]; + else if (keysym > 0x67f && keysym < 0x700) + return keysym_to_unicode_680_6ff[keysym - 0x680]; + else if (keysym > 0x7a0 && keysym < 0x7fa) + return keysym_to_unicode_7a1_7f9[keysym - 0x7a1]; + else if (keysym > 0x8a3 && keysym < 0x8ff) + return keysym_to_unicode_8a4_8fe[keysym - 0x8a4]; + else if (keysym > 0x9de && keysym < 0x9f9) + return keysym_to_unicode_9df_9f8[keysym - 0x9df]; + else if (keysym > 0xaa0 && keysym < 0xaff) + return keysym_to_unicode_aa1_afe[keysym - 0xaa1]; + else if (keysym > 0xcde && keysym < 0xcfb) + return keysym_to_unicode_cdf_cfa[keysym - 0xcdf]; + else if (keysym > 0xda0 && keysym < 0xdfa) + return keysym_to_unicode_da1_df9[keysym - 0xda1]; + else if (keysym > 0xe9f && keysym < 0xf00) + return keysym_to_unicode_ea0_eff[keysym - 0xea0]; + else if (keysym > 0x12a0 && keysym < 0x12ff) + return keysym_to_unicode_12a1_12fe[keysym - 0x12a1]; + else if (keysym > 0x13bb && keysym < 0x13bf) + return keysym_to_unicode_13bc_13be[keysym - 0x13bc]; + else if (keysym > 0x14a0 && keysym < 0x1500) + return keysym_to_unicode_14a1_14ff[keysym - 0x14a1]; + else if (keysym > 0x15cf && keysym < 0x15f7) + return keysym_to_unicode_15d0_15f6[keysym - 0x15d0]; + else if (keysym > 0x169f && keysym < 0x16f7) + return keysym_to_unicode_16a0_16f6[keysym - 0x16a0]; + else if (keysym > 0x1e9e && keysym < 0x1f00) + return keysym_to_unicode_1e9f_1eff[keysym - 0x1e9f]; + else if (keysym > 0x209f && keysym < 0x20ad) + return keysym_to_unicode_20a0_20ac[keysym - 0x20a0]; + else + return 0; +} + +#endif /* SDL_VIDEO_DRIVER_X11 */ + diff --git a/contrib/SDL-3.2.8/src/events/imKStoUCS.h b/contrib/SDL-3.2.8/src/events/imKStoUCS.h new file mode 100644 index 0000000..4182c1b --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/imKStoUCS.h @@ -0,0 +1,32 @@ +#ifndef _imKStoUCS_h +#define _imKStoUCS_h + +/* +Copyright (C) 2003-2006,2008 Jamey Sharp, Josh Triplett +Copyright © 2009 Red Hat, Inc. +Copyright 1990-1992,1999,2000,2004,2009,2010 Oracle and/or its affiliates. +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +extern unsigned int SDL_KeySymToUcs4(Uint32 keysym); + +#endif /* _imKStoUCS_h */ diff --git a/contrib/SDL-3.2.8/src/events/scancodes_darwin.h b/contrib/SDL-3.2.8/src/events/scancodes_darwin.h new file mode 100644 index 0000000..c3a2d4c --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/scancodes_darwin.h @@ -0,0 +1,159 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* Mac virtual key code to SDL scancode mapping table + Sources: + - Inside Macintosh: Text + - Apple USB keyboard driver source + - experimentation on various ADB and USB ISO keyboards and one ADB ANSI keyboard +*/ +/* *INDENT-OFF* */ // clang-format off +static const SDL_Scancode darwin_scancode_table[] = { + /* 0 */ SDL_SCANCODE_A, + /* 1 */ SDL_SCANCODE_S, + /* 2 */ SDL_SCANCODE_D, + /* 3 */ SDL_SCANCODE_F, + /* 4 */ SDL_SCANCODE_H, + /* 5 */ SDL_SCANCODE_G, + /* 6 */ SDL_SCANCODE_Z, + /* 7 */ SDL_SCANCODE_X, + /* 8 */ SDL_SCANCODE_C, + /* 9 */ SDL_SCANCODE_V, + /* 10 */ SDL_SCANCODE_NONUSBACKSLASH, // SDL_SCANCODE_NONUSBACKSLASH on ANSI and JIS keyboards (if this key would exist there), SDL_SCANCODE_GRAVE on ISO. (The USB keyboard driver actually translates these usage codes to different virtual key codes depending on whether the keyboard is ISO/ANSI/JIS. That's why you have to help it identify the keyboard type when you plug in a PC USB keyboard. It's a historical thing - ADB keyboards are wired this way.) + /* 11 */ SDL_SCANCODE_B, + /* 12 */ SDL_SCANCODE_Q, + /* 13 */ SDL_SCANCODE_W, + /* 14 */ SDL_SCANCODE_E, + /* 15 */ SDL_SCANCODE_R, + /* 16 */ SDL_SCANCODE_Y, + /* 17 */ SDL_SCANCODE_T, + /* 18 */ SDL_SCANCODE_1, + /* 19 */ SDL_SCANCODE_2, + /* 20 */ SDL_SCANCODE_3, + /* 21 */ SDL_SCANCODE_4, + /* 22 */ SDL_SCANCODE_6, + /* 23 */ SDL_SCANCODE_5, + /* 24 */ SDL_SCANCODE_EQUALS, + /* 25 */ SDL_SCANCODE_9, + /* 26 */ SDL_SCANCODE_7, + /* 27 */ SDL_SCANCODE_MINUS, + /* 28 */ SDL_SCANCODE_8, + /* 29 */ SDL_SCANCODE_0, + /* 30 */ SDL_SCANCODE_RIGHTBRACKET, + /* 31 */ SDL_SCANCODE_O, + /* 32 */ SDL_SCANCODE_U, + /* 33 */ SDL_SCANCODE_LEFTBRACKET, + /* 34 */ SDL_SCANCODE_I, + /* 35 */ SDL_SCANCODE_P, + /* 36 */ SDL_SCANCODE_RETURN, + /* 37 */ SDL_SCANCODE_L, + /* 38 */ SDL_SCANCODE_J, + /* 39 */ SDL_SCANCODE_APOSTROPHE, + /* 40 */ SDL_SCANCODE_K, + /* 41 */ SDL_SCANCODE_SEMICOLON, + /* 42 */ SDL_SCANCODE_BACKSLASH, + /* 43 */ SDL_SCANCODE_COMMA, + /* 44 */ SDL_SCANCODE_SLASH, + /* 45 */ SDL_SCANCODE_N, + /* 46 */ SDL_SCANCODE_M, + /* 47 */ SDL_SCANCODE_PERIOD, + /* 48 */ SDL_SCANCODE_TAB, + /* 49 */ SDL_SCANCODE_SPACE, + /* 50 */ SDL_SCANCODE_GRAVE, // SDL_SCANCODE_GRAVE on ANSI and JIS keyboards, SDL_SCANCODE_NONUSBACKSLASH on ISO (see comment about virtual key code 10 above) + /* 51 */ SDL_SCANCODE_BACKSPACE, + /* 52 */ SDL_SCANCODE_KP_ENTER, // keyboard enter on portables + /* 53 */ SDL_SCANCODE_ESCAPE, + /* 54 */ SDL_SCANCODE_RGUI, + /* 55 */ SDL_SCANCODE_LGUI, + /* 56 */ SDL_SCANCODE_LSHIFT, + /* 57 */ SDL_SCANCODE_CAPSLOCK, + /* 58 */ SDL_SCANCODE_LALT, + /* 59 */ SDL_SCANCODE_LCTRL, + /* 60 */ SDL_SCANCODE_RSHIFT, + /* 61 */ SDL_SCANCODE_RALT, + /* 62 */ SDL_SCANCODE_RCTRL, + /* 63 */ SDL_SCANCODE_RGUI, // fn on portables, acts as a hardware-level modifier already, so we don't generate events for it, also XK_Meta_R + /* 64 */ SDL_SCANCODE_F17, + /* 65 */ SDL_SCANCODE_KP_PERIOD, + /* 66 */ SDL_SCANCODE_UNKNOWN, // unknown (unused?) + /* 67 */ SDL_SCANCODE_KP_MULTIPLY, + /* 68 */ SDL_SCANCODE_UNKNOWN, // unknown (unused?) + /* 69 */ SDL_SCANCODE_KP_PLUS, + /* 70 */ SDL_SCANCODE_UNKNOWN, // unknown (unused?) + /* 71 */ SDL_SCANCODE_NUMLOCKCLEAR, + /* 72 */ SDL_SCANCODE_VOLUMEUP, + /* 73 */ SDL_SCANCODE_VOLUMEDOWN, + /* 74 */ SDL_SCANCODE_MUTE, + /* 75 */ SDL_SCANCODE_KP_DIVIDE, + /* 76 */ SDL_SCANCODE_KP_ENTER, // keypad enter on external keyboards, fn-return on portables + /* 77 */ SDL_SCANCODE_UNKNOWN, // unknown (unused?) + /* 78 */ SDL_SCANCODE_KP_MINUS, + /* 79 */ SDL_SCANCODE_F18, + /* 80 */ SDL_SCANCODE_F19, + /* 81 */ SDL_SCANCODE_KP_EQUALS, + /* 82 */ SDL_SCANCODE_KP_0, + /* 83 */ SDL_SCANCODE_KP_1, + /* 84 */ SDL_SCANCODE_KP_2, + /* 85 */ SDL_SCANCODE_KP_3, + /* 86 */ SDL_SCANCODE_KP_4, + /* 87 */ SDL_SCANCODE_KP_5, + /* 88 */ SDL_SCANCODE_KP_6, + /* 89 */ SDL_SCANCODE_KP_7, + /* 90 */ SDL_SCANCODE_UNKNOWN, // unknown (unused?) + /* 91 */ SDL_SCANCODE_KP_8, + /* 92 */ SDL_SCANCODE_KP_9, + /* 93 */ SDL_SCANCODE_INTERNATIONAL3, // Cosmo_USB2ADB.c says "Yen (JIS)" + /* 94 */ SDL_SCANCODE_INTERNATIONAL1, // Cosmo_USB2ADB.c says "Ro (JIS)" + /* 95 */ SDL_SCANCODE_KP_COMMA, // Cosmo_USB2ADB.c says ", JIS only" + /* 96 */ SDL_SCANCODE_F5, + /* 97 */ SDL_SCANCODE_F6, + /* 98 */ SDL_SCANCODE_F7, + /* 99 */ SDL_SCANCODE_F3, + /* 100 */ SDL_SCANCODE_F8, + /* 101 */ SDL_SCANCODE_F9, + /* 102 */ SDL_SCANCODE_LANG2, // Cosmo_USB2ADB.c says "Eisu" + /* 103 */ SDL_SCANCODE_F11, + /* 104 */ SDL_SCANCODE_LANG1, // Cosmo_USB2ADB.c says "Kana" + /* 105 */ SDL_SCANCODE_PRINTSCREEN, // On ADB keyboards, this key is labeled "F13/print screen". Problem: USB has different usage codes for these two functions. On Apple USB keyboards, the key is labeled "F13" and sends the F13 usage code (SDL_SCANCODE_F13). I decided to use SDL_SCANCODE_PRINTSCREEN here nevertheless since SDL applications are more likely to assume the presence of a print screen key than an F13 key. + /* 106 */ SDL_SCANCODE_F16, + /* 107 */ SDL_SCANCODE_SCROLLLOCK, // F14/scroll lock, see comment about F13/print screen above + /* 108 */ SDL_SCANCODE_UNKNOWN, // unknown (unused?) + /* 109 */ SDL_SCANCODE_F10, + /* 110 */ SDL_SCANCODE_APPLICATION, // windows contextual menu key, fn-enter on portables + /* 111 */ SDL_SCANCODE_F12, + /* 112 */ SDL_SCANCODE_UNKNOWN, // unknown (unused?) + /* 113 */ SDL_SCANCODE_PAUSE, // F15/pause, see comment about F13/print screen above + /* 114 */ SDL_SCANCODE_INSERT, // the key is actually labeled "help" on Apple keyboards, and works as such in Mac OS, but it sends the "insert" usage code even on Apple USB keyboards + /* 115 */ SDL_SCANCODE_HOME, + /* 116 */ SDL_SCANCODE_PAGEUP, + /* 117 */ SDL_SCANCODE_DELETE, + /* 118 */ SDL_SCANCODE_F4, + /* 119 */ SDL_SCANCODE_END, + /* 120 */ SDL_SCANCODE_F2, + /* 121 */ SDL_SCANCODE_PAGEDOWN, + /* 122 */ SDL_SCANCODE_F1, + /* 123 */ SDL_SCANCODE_LEFT, + /* 124 */ SDL_SCANCODE_RIGHT, + /* 125 */ SDL_SCANCODE_DOWN, + /* 126 */ SDL_SCANCODE_UP, + /* 127 */ SDL_SCANCODE_POWER +}; +/* *INDENT-ON* */ // clang-format on diff --git a/contrib/SDL-3.2.8/src/events/scancodes_linux.h b/contrib/SDL-3.2.8/src/events/scancodes_linux.h new file mode 100644 index 0000000..2deeb9a --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/scancodes_linux.h @@ -0,0 +1,848 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +/* Linux virtual key code to SDL_Keycode mapping table + Sources: + - Linux kernel source input.h +*/ +/* *INDENT-OFF* */ // clang-format off +static SDL_Scancode const linux_scancode_table[] = { + /* 0, 0x000 */ SDL_SCANCODE_UNKNOWN, // KEY_RESERVED + /* 1, 0x001 */ SDL_SCANCODE_ESCAPE, // KEY_ESC + /* 2, 0x002 */ SDL_SCANCODE_1, // KEY_1 + /* 3, 0x003 */ SDL_SCANCODE_2, // KEY_2 + /* 4, 0x004 */ SDL_SCANCODE_3, // KEY_3 + /* 5, 0x005 */ SDL_SCANCODE_4, // KEY_4 + /* 6, 0x006 */ SDL_SCANCODE_5, // KEY_5 + /* 7, 0x007 */ SDL_SCANCODE_6, // KEY_6 + /* 8, 0x008 */ SDL_SCANCODE_7, // KEY_7 + /* 9, 0x009 */ SDL_SCANCODE_8, // KEY_8 + /* 10, 0x00a */ SDL_SCANCODE_9, // KEY_9 + /* 11, 0x00b */ SDL_SCANCODE_0, // KEY_0 + /* 12, 0x00c */ SDL_SCANCODE_MINUS, // KEY_MINUS + /* 13, 0x00d */ SDL_SCANCODE_EQUALS, // KEY_EQUAL + /* 14, 0x00e */ SDL_SCANCODE_BACKSPACE, // KEY_BACKSPACE + /* 15, 0x00f */ SDL_SCANCODE_TAB, // KEY_TAB + /* 16, 0x010 */ SDL_SCANCODE_Q, // KEY_Q + /* 17, 0x011 */ SDL_SCANCODE_W, // KEY_W + /* 18, 0x012 */ SDL_SCANCODE_E, // KEY_E + /* 19, 0x013 */ SDL_SCANCODE_R, // KEY_R + /* 20, 0x014 */ SDL_SCANCODE_T, // KEY_T + /* 21, 0x015 */ SDL_SCANCODE_Y, // KEY_Y + /* 22, 0x016 */ SDL_SCANCODE_U, // KEY_U + /* 23, 0x017 */ SDL_SCANCODE_I, // KEY_I + /* 24, 0x018 */ SDL_SCANCODE_O, // KEY_O + /* 25, 0x019 */ SDL_SCANCODE_P, // KEY_P + /* 26, 0x01a */ SDL_SCANCODE_LEFTBRACKET, // KEY_LEFTBRACE + /* 27, 0x01b */ SDL_SCANCODE_RIGHTBRACKET, // KEY_RIGHTBRACE + /* 28, 0x01c */ SDL_SCANCODE_RETURN, // KEY_ENTER + /* 29, 0x01d */ SDL_SCANCODE_LCTRL, // KEY_LEFTCTRL + /* 30, 0x01e */ SDL_SCANCODE_A, // KEY_A + /* 31, 0x01f */ SDL_SCANCODE_S, // KEY_S + /* 32, 0x020 */ SDL_SCANCODE_D, // KEY_D + /* 33, 0x021 */ SDL_SCANCODE_F, // KEY_F + /* 34, 0x022 */ SDL_SCANCODE_G, // KEY_G + /* 35, 0x023 */ SDL_SCANCODE_H, // KEY_H + /* 36, 0x024 */ SDL_SCANCODE_J, // KEY_J + /* 37, 0x025 */ SDL_SCANCODE_K, // KEY_K + /* 38, 0x026 */ SDL_SCANCODE_L, // KEY_L + /* 39, 0x027 */ SDL_SCANCODE_SEMICOLON, // KEY_SEMICOLON + /* 40, 0x028 */ SDL_SCANCODE_APOSTROPHE, // KEY_APOSTROPHE + /* 41, 0x029 */ SDL_SCANCODE_GRAVE, // KEY_GRAVE + /* 42, 0x02a */ SDL_SCANCODE_LSHIFT, // KEY_LEFTSHIFT + /* 43, 0x02b */ SDL_SCANCODE_BACKSLASH, // KEY_BACKSLASH + /* 44, 0x02c */ SDL_SCANCODE_Z, // KEY_Z + /* 45, 0x02d */ SDL_SCANCODE_X, // KEY_X + /* 46, 0x02e */ SDL_SCANCODE_C, // KEY_C + /* 47, 0x02f */ SDL_SCANCODE_V, // KEY_V + /* 48, 0x030 */ SDL_SCANCODE_B, // KEY_B + /* 49, 0x031 */ SDL_SCANCODE_N, // KEY_N + /* 50, 0x032 */ SDL_SCANCODE_M, // KEY_M + /* 51, 0x033 */ SDL_SCANCODE_COMMA, // KEY_COMMA + /* 52, 0x034 */ SDL_SCANCODE_PERIOD, // KEY_DOT + /* 53, 0x035 */ SDL_SCANCODE_SLASH, // KEY_SLASH + /* 54, 0x036 */ SDL_SCANCODE_RSHIFT, // KEY_RIGHTSHIFT + /* 55, 0x037 */ SDL_SCANCODE_KP_MULTIPLY, // KEY_KPASTERISK + /* 56, 0x038 */ SDL_SCANCODE_LALT, // KEY_LEFTALT + /* 57, 0x039 */ SDL_SCANCODE_SPACE, // KEY_SPACE + /* 58, 0x03a */ SDL_SCANCODE_CAPSLOCK, // KEY_CAPSLOCK + /* 59, 0x03b */ SDL_SCANCODE_F1, // KEY_F1 + /* 60, 0x03c */ SDL_SCANCODE_F2, // KEY_F2 + /* 61, 0x03d */ SDL_SCANCODE_F3, // KEY_F3 + /* 62, 0x03e */ SDL_SCANCODE_F4, // KEY_F4 + /* 63, 0x03f */ SDL_SCANCODE_F5, // KEY_F5 + /* 64, 0x040 */ SDL_SCANCODE_F6, // KEY_F6 + /* 65, 0x041 */ SDL_SCANCODE_F7, // KEY_F7 + /* 66, 0x042 */ SDL_SCANCODE_F8, // KEY_F8 + /* 67, 0x043 */ SDL_SCANCODE_F9, // KEY_F9 + /* 68, 0x044 */ SDL_SCANCODE_F10, // KEY_F10 + /* 69, 0x045 */ SDL_SCANCODE_NUMLOCKCLEAR, // KEY_NUMLOCK + /* 70, 0x046 */ SDL_SCANCODE_SCROLLLOCK, // KEY_SCROLLLOCK + /* 71, 0x047 */ SDL_SCANCODE_KP_7, // KEY_KP7 + /* 72, 0x048 */ SDL_SCANCODE_KP_8, // KEY_KP8 + /* 73, 0x049 */ SDL_SCANCODE_KP_9, // KEY_KP9 + /* 74, 0x04a */ SDL_SCANCODE_KP_MINUS, // KEY_KPMINUS + /* 75, 0x04b */ SDL_SCANCODE_KP_4, // KEY_KP4 + /* 76, 0x04c */ SDL_SCANCODE_KP_5, // KEY_KP5 + /* 77, 0x04d */ SDL_SCANCODE_KP_6, // KEY_KP6 + /* 78, 0x04e */ SDL_SCANCODE_KP_PLUS, // KEY_KPPLUS + /* 79, 0x04f */ SDL_SCANCODE_KP_1, // KEY_KP1 + /* 80, 0x050 */ SDL_SCANCODE_KP_2, // KEY_KP2 + /* 81, 0x051 */ SDL_SCANCODE_KP_3, // KEY_KP3 + /* 82, 0x052 */ SDL_SCANCODE_KP_0, // KEY_KP0 + /* 83, 0x053 */ SDL_SCANCODE_KP_PERIOD, // KEY_KPDOT + /* 84, 0x054 */ SDL_SCANCODE_UNKNOWN, + /* 85, 0x055 */ SDL_SCANCODE_LANG5, // KEY_ZENKAKUHANKAKU + /* 86, 0x056 */ SDL_SCANCODE_NONUSBACKSLASH, // KEY_102ND + /* 87, 0x057 */ SDL_SCANCODE_F11, // KEY_F11 + /* 88, 0x058 */ SDL_SCANCODE_F12, // KEY_F12 + /* 89, 0x059 */ SDL_SCANCODE_INTERNATIONAL1, // KEY_RO + /* 90, 0x05a */ SDL_SCANCODE_LANG3, // KEY_KATAKANA + /* 91, 0x05b */ SDL_SCANCODE_LANG4, // KEY_HIRAGANA + /* 92, 0x05c */ SDL_SCANCODE_INTERNATIONAL4, // KEY_HENKAN + /* 93, 0x05d */ SDL_SCANCODE_INTERNATIONAL2, // KEY_KATAKANAHIRAGANA + /* 94, 0x05e */ SDL_SCANCODE_INTERNATIONAL5, // KEY_MUHENKAN + /* 95, 0x05f */ SDL_SCANCODE_INTERNATIONAL5, // KEY_KPJPCOMMA + /* 96, 0x060 */ SDL_SCANCODE_KP_ENTER, // KEY_KPENTER + /* 97, 0x061 */ SDL_SCANCODE_RCTRL, // KEY_RIGHTCTRL + /* 98, 0x062 */ SDL_SCANCODE_KP_DIVIDE, // KEY_KPSLASH + /* 99, 0x063 */ SDL_SCANCODE_SYSREQ, // KEY_SYSRQ + /* 100, 0x064 */ SDL_SCANCODE_RALT, // KEY_RIGHTALT + /* 101, 0x065 */ SDL_SCANCODE_UNKNOWN, // KEY_LINEFEED + /* 102, 0x066 */ SDL_SCANCODE_HOME, // KEY_HOME + /* 103, 0x067 */ SDL_SCANCODE_UP, // KEY_UP + /* 104, 0x068 */ SDL_SCANCODE_PAGEUP, // KEY_PAGEUP + /* 105, 0x069 */ SDL_SCANCODE_LEFT, // KEY_LEFT + /* 106, 0x06a */ SDL_SCANCODE_RIGHT, // KEY_RIGHT + /* 107, 0x06b */ SDL_SCANCODE_END, // KEY_END + /* 108, 0x06c */ SDL_SCANCODE_DOWN, // KEY_DOWN + /* 109, 0x06d */ SDL_SCANCODE_PAGEDOWN, // KEY_PAGEDOWN + /* 110, 0x06e */ SDL_SCANCODE_INSERT, // KEY_INSERT + /* 111, 0x06f */ SDL_SCANCODE_DELETE, // KEY_DELETE + /* 112, 0x070 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO + /* 113, 0x071 */ SDL_SCANCODE_MUTE, // KEY_MUTE + /* 114, 0x072 */ SDL_SCANCODE_VOLUMEDOWN, // KEY_VOLUMEDOWN + /* 115, 0x073 */ SDL_SCANCODE_VOLUMEUP, // KEY_VOLUMEUP + /* 116, 0x074 */ SDL_SCANCODE_POWER, // KEY_POWER + /* 117, 0x075 */ SDL_SCANCODE_KP_EQUALS, // KEY_KPEQUAL + /* 118, 0x076 */ SDL_SCANCODE_KP_PLUSMINUS, // KEY_KPPLUSMINUS + /* 119, 0x077 */ SDL_SCANCODE_PAUSE, // KEY_PAUSE + /* 120, 0x078 */ SDL_SCANCODE_UNKNOWN, // KEY_SCALE + /* 121, 0x079 */ SDL_SCANCODE_KP_COMMA, // KEY_KPCOMMA + /* 122, 0x07a */ SDL_SCANCODE_LANG1, // KEY_HANGEUL + /* 123, 0x07b */ SDL_SCANCODE_LANG2, // KEY_HANJA + /* 124, 0x07c */ SDL_SCANCODE_INTERNATIONAL3, // KEY_YEN + /* 125, 0x07d */ SDL_SCANCODE_LGUI, // KEY_LEFTMETA + /* 126, 0x07e */ SDL_SCANCODE_RGUI, // KEY_RIGHTMETA + /* 127, 0x07f */ SDL_SCANCODE_APPLICATION, // KEY_COMPOSE + /* 128, 0x080 */ SDL_SCANCODE_STOP, // KEY_STOP + /* 129, 0x081 */ SDL_SCANCODE_AGAIN, // KEY_AGAIN + /* 130, 0x082 */ SDL_SCANCODE_AC_PROPERTIES, // KEY_PROPS + /* 131, 0x083 */ SDL_SCANCODE_UNDO, // KEY_UNDO + /* 132, 0x084 */ SDL_SCANCODE_UNKNOWN, // KEY_FRONT + /* 133, 0x085 */ SDL_SCANCODE_COPY, // KEY_COPY + /* 134, 0x086 */ SDL_SCANCODE_AC_OPEN, // KEY_OPEN + /* 135, 0x087 */ SDL_SCANCODE_PASTE, // KEY_PASTE + /* 136, 0x088 */ SDL_SCANCODE_FIND, // KEY_FIND + /* 137, 0x089 */ SDL_SCANCODE_CUT, // KEY_CUT + /* 138, 0x08a */ SDL_SCANCODE_HELP, // KEY_HELP + /* 139, 0x08b */ SDL_SCANCODE_MENU, // KEY_MENU + /* 140, 0x08c */ SDL_SCANCODE_UNKNOWN, // KEY_CALC + /* 141, 0x08d */ SDL_SCANCODE_UNKNOWN, // KEY_SETUP + /* 142, 0x08e */ SDL_SCANCODE_SLEEP, // KEY_SLEEP + /* 143, 0x08f */ SDL_SCANCODE_WAKE, // KEY_WAKEUP + /* 144, 0x090 */ SDL_SCANCODE_UNKNOWN, // KEY_FILE + /* 145, 0x091 */ SDL_SCANCODE_UNKNOWN, // KEY_SENDFILE + /* 146, 0x092 */ SDL_SCANCODE_UNKNOWN, // KEY_DELETEFILE + /* 147, 0x093 */ SDL_SCANCODE_UNKNOWN, // KEY_XFER + /* 148, 0x094 */ SDL_SCANCODE_UNKNOWN, // KEY_PROG1 + /* 149, 0x095 */ SDL_SCANCODE_UNKNOWN, // KEY_PROG2 + /* 150, 0x096 */ SDL_SCANCODE_UNKNOWN, // KEY_WWW + /* 151, 0x097 */ SDL_SCANCODE_UNKNOWN, // KEY_MSDOS + /* 152, 0x098 */ SDL_SCANCODE_UNKNOWN, // KEY_COFFEE + /* 153, 0x099 */ SDL_SCANCODE_UNKNOWN, // KEY_ROTATE_DISPLAY + /* 154, 0x09a */ SDL_SCANCODE_UNKNOWN, // KEY_CYCLEWINDOWS + /* 155, 0x09b */ SDL_SCANCODE_UNKNOWN, // KEY_MAIL + /* 156, 0x09c */ SDL_SCANCODE_AC_BOOKMARKS, // KEY_BOOKMARKS + /* 157, 0x09d */ SDL_SCANCODE_UNKNOWN, // KEY_COMPUTER + /* 158, 0x09e */ SDL_SCANCODE_AC_BACK, // KEY_BACK + /* 159, 0x09f */ SDL_SCANCODE_AC_FORWARD, // KEY_FORWARD + /* 160, 0x0a0 */ SDL_SCANCODE_UNKNOWN, // KEY_CLOSECD + /* 161, 0x0a1 */ SDL_SCANCODE_MEDIA_EJECT, // KEY_EJECTCD + /* 162, 0x0a2 */ SDL_SCANCODE_MEDIA_EJECT, // KEY_EJECTCLOSECD + /* 163, 0x0a3 */ SDL_SCANCODE_MEDIA_NEXT_TRACK, // KEY_NEXTSONG + /* 164, 0x0a4 */ SDL_SCANCODE_MEDIA_PLAY_PAUSE, // KEY_PLAYPAUSE + /* 165, 0x0a5 */ SDL_SCANCODE_MEDIA_PREVIOUS_TRACK, // KEY_PREVIOUSSONG + /* 166, 0x0a6 */ SDL_SCANCODE_MEDIA_STOP, // KEY_STOPCD + /* 167, 0x0a7 */ SDL_SCANCODE_MEDIA_RECORD, // KEY_RECORD + /* 168, 0x0a8 */ SDL_SCANCODE_MEDIA_REWIND, // KEY_REWIND + /* 169, 0x0a9 */ SDL_SCANCODE_UNKNOWN, // KEY_PHONE + /* 170, 0x0aa */ SDL_SCANCODE_UNKNOWN, // KEY_ISO + /* 171, 0x0ab */ SDL_SCANCODE_UNKNOWN, // KEY_CONFIG + /* 172, 0x0ac */ SDL_SCANCODE_AC_HOME, // KEY_HOMEPAGE + /* 173, 0x0ad */ SDL_SCANCODE_AC_REFRESH, // KEY_REFRESH + /* 174, 0x0ae */ SDL_SCANCODE_AC_EXIT, // KEY_EXIT + /* 175, 0x0af */ SDL_SCANCODE_UNKNOWN, // KEY_MOVE + /* 176, 0x0b0 */ SDL_SCANCODE_UNKNOWN, // KEY_EDIT + /* 177, 0x0b1 */ SDL_SCANCODE_UNKNOWN, // KEY_SCROLLUP + /* 178, 0x0b2 */ SDL_SCANCODE_UNKNOWN, // KEY_SCROLLDOWN + /* 179, 0x0b3 */ SDL_SCANCODE_KP_LEFTPAREN, // KEY_KPLEFTPAREN + /* 180, 0x0b4 */ SDL_SCANCODE_KP_RIGHTPAREN, // KEY_KPRIGHTPAREN + /* 181, 0x0b5 */ SDL_SCANCODE_AC_NEW, // KEY_NEW + /* 182, 0x0b6 */ SDL_SCANCODE_AGAIN, // KEY_REDO + /* 183, 0x0b7 */ SDL_SCANCODE_F13, // KEY_F13 + /* 184, 0x0b8 */ SDL_SCANCODE_F14, // KEY_F14 + /* 185, 0x0b9 */ SDL_SCANCODE_F15, // KEY_F15 + /* 186, 0x0ba */ SDL_SCANCODE_F16, // KEY_F16 + /* 187, 0x0bb */ SDL_SCANCODE_F17, // KEY_F17 + /* 188, 0x0bc */ SDL_SCANCODE_F18, // KEY_F18 + /* 189, 0x0bd */ SDL_SCANCODE_F19, // KEY_F19 + /* 190, 0x0be */ SDL_SCANCODE_F20, // KEY_F20 + /* 191, 0x0bf */ SDL_SCANCODE_F21, // KEY_F21 + /* 192, 0x0c0 */ SDL_SCANCODE_F22, // KEY_F22 + /* 193, 0x0c1 */ SDL_SCANCODE_F23, // KEY_F23 + /* 194, 0x0c2 */ SDL_SCANCODE_F24, // KEY_F24 + /* 195, 0x0c3 */ SDL_SCANCODE_UNKNOWN, + /* 196, 0x0c4 */ SDL_SCANCODE_UNKNOWN, + /* 197, 0x0c5 */ SDL_SCANCODE_UNKNOWN, + /* 198, 0x0c6 */ SDL_SCANCODE_UNKNOWN, + /* 199, 0x0c7 */ SDL_SCANCODE_UNKNOWN, + /* 200, 0x0c8 */ SDL_SCANCODE_MEDIA_PLAY, // KEY_PLAYCD + /* 201, 0x0c9 */ SDL_SCANCODE_MEDIA_PAUSE, // KEY_PAUSECD + /* 202, 0x0ca */ SDL_SCANCODE_UNKNOWN, // KEY_PROG3 + /* 203, 0x0cb */ SDL_SCANCODE_UNKNOWN, // KEY_PROG4 + /* 204, 0x0cc */ SDL_SCANCODE_UNKNOWN, // KEY_ALL_APPLICATIONS + /* 205, 0x0cd */ SDL_SCANCODE_UNKNOWN, // KEY_SUSPEND + /* 206, 0x0ce */ SDL_SCANCODE_AC_CLOSE, // KEY_CLOSE + /* 207, 0x0cf */ SDL_SCANCODE_MEDIA_PLAY, // KEY_PLAY + /* 208, 0x0d0 */ SDL_SCANCODE_MEDIA_FAST_FORWARD, // KEY_FASTFORWARD + /* 209, 0x0d1 */ SDL_SCANCODE_UNKNOWN, // KEY_BASSBOOST + /* 210, 0x0d2 */ SDL_SCANCODE_PRINTSCREEN, // KEY_PRINT + /* 211, 0x0d3 */ SDL_SCANCODE_UNKNOWN, // KEY_HP + /* 212, 0x0d4 */ SDL_SCANCODE_UNKNOWN, // KEY_CAMERA + /* 213, 0x0d5 */ SDL_SCANCODE_UNKNOWN, // KEY_SOUND + /* 214, 0x0d6 */ SDL_SCANCODE_UNKNOWN, // KEY_QUESTION + /* 215, 0x0d7 */ SDL_SCANCODE_UNKNOWN, // KEY_EMAIL + /* 216, 0x0d8 */ SDL_SCANCODE_UNKNOWN, // KEY_CHAT + /* 217, 0x0d9 */ SDL_SCANCODE_AC_SEARCH, // KEY_SEARCH + /* 218, 0x0da */ SDL_SCANCODE_UNKNOWN, // KEY_CONNECT + /* 219, 0x0db */ SDL_SCANCODE_UNKNOWN, // KEY_FINANCE + /* 220, 0x0dc */ SDL_SCANCODE_UNKNOWN, // KEY_SPORT + /* 221, 0x0dd */ SDL_SCANCODE_UNKNOWN, // KEY_SHOP + /* 222, 0x0de */ SDL_SCANCODE_ALTERASE, // KEY_ALTERASE + /* 223, 0x0df */ SDL_SCANCODE_CANCEL, // KEY_CANCEL + /* 224, 0x0e0 */ SDL_SCANCODE_UNKNOWN, // KEY_BRIGHTNESSDOWN + /* 225, 0x0e1 */ SDL_SCANCODE_UNKNOWN, // KEY_BRIGHTNESSUP + /* 226, 0x0e2 */ SDL_SCANCODE_MEDIA_SELECT, // KEY_MEDIA + /* 227, 0x0e3 */ SDL_SCANCODE_UNKNOWN, // KEY_SWITCHVIDEOMODE + /* 228, 0x0e4 */ SDL_SCANCODE_UNKNOWN, // KEY_KBDILLUMTOGGLE + /* 229, 0x0e5 */ SDL_SCANCODE_UNKNOWN, // KEY_KBDILLUMDOWN + /* 230, 0x0e6 */ SDL_SCANCODE_UNKNOWN, // KEY_KBDILLUMUP + /* 231, 0x0e7 */ SDL_SCANCODE_UNKNOWN, // KEY_SEND + /* 232, 0x0e8 */ SDL_SCANCODE_UNKNOWN, // KEY_REPLY + /* 233, 0x0e9 */ SDL_SCANCODE_UNKNOWN, // KEY_FORWARDMAIL + /* 234, 0x0ea */ SDL_SCANCODE_AC_SAVE, // KEY_SAVE + /* 235, 0x0eb */ SDL_SCANCODE_UNKNOWN, // KEY_DOCUMENTS + /* 236, 0x0ec */ SDL_SCANCODE_UNKNOWN, // KEY_BATTERY + /* 237, 0x0ed */ SDL_SCANCODE_UNKNOWN, // KEY_BLUETOOTH + /* 238, 0x0ee */ SDL_SCANCODE_UNKNOWN, // KEY_WLAN + /* 239, 0x0ef */ SDL_SCANCODE_UNKNOWN, // KEY_UWB + /* 240, 0x0f0 */ SDL_SCANCODE_UNKNOWN, // KEY_UNKNOWN + /* 241, 0x0f1 */ SDL_SCANCODE_UNKNOWN, // KEY_VIDEO_NEXT + /* 242, 0x0f2 */ SDL_SCANCODE_UNKNOWN, // KEY_VIDEO_PREV + /* 243, 0x0f3 */ SDL_SCANCODE_UNKNOWN, // KEY_BRIGHTNESS_CYCLE + /* 244, 0x0f4 */ SDL_SCANCODE_UNKNOWN, // KEY_BRIGHTNESS_AUTO + /* 245, 0x0f5 */ SDL_SCANCODE_UNKNOWN, // KEY_DISPLAY_OFF + /* 246, 0x0f6 */ SDL_SCANCODE_UNKNOWN, // KEY_WWAN + /* 247, 0x0f7 */ SDL_SCANCODE_UNKNOWN, // KEY_RFKILL + /* 248, 0x0f8 */ SDL_SCANCODE_UNKNOWN, // KEY_MICMUTE + /* 249, 0x0f9 */ SDL_SCANCODE_UNKNOWN, + /* 250, 0x0fa */ SDL_SCANCODE_UNKNOWN, + /* 251, 0x0fb */ SDL_SCANCODE_UNKNOWN, + /* 252, 0x0fc */ SDL_SCANCODE_UNKNOWN, + /* 253, 0x0fd */ SDL_SCANCODE_UNKNOWN, + /* 254, 0x0fe */ SDL_SCANCODE_UNKNOWN, + /* 255, 0x0ff */ SDL_SCANCODE_UNKNOWN, + /* 256, 0x100 */ SDL_SCANCODE_UNKNOWN, + /* 257, 0x101 */ SDL_SCANCODE_UNKNOWN, + /* 258, 0x102 */ SDL_SCANCODE_UNKNOWN, + /* 259, 0x103 */ SDL_SCANCODE_UNKNOWN, + /* 260, 0x104 */ SDL_SCANCODE_UNKNOWN, + /* 261, 0x105 */ SDL_SCANCODE_UNKNOWN, + /* 262, 0x106 */ SDL_SCANCODE_UNKNOWN, + /* 263, 0x107 */ SDL_SCANCODE_UNKNOWN, + /* 264, 0x108 */ SDL_SCANCODE_UNKNOWN, + /* 265, 0x109 */ SDL_SCANCODE_UNKNOWN, + /* 266, 0x10a */ SDL_SCANCODE_UNKNOWN, + /* 267, 0x10b */ SDL_SCANCODE_UNKNOWN, + /* 268, 0x10c */ SDL_SCANCODE_UNKNOWN, + /* 269, 0x10d */ SDL_SCANCODE_UNKNOWN, + /* 270, 0x10e */ SDL_SCANCODE_UNKNOWN, + /* 271, 0x10f */ SDL_SCANCODE_UNKNOWN, + /* 272, 0x110 */ SDL_SCANCODE_UNKNOWN, + /* 273, 0x111 */ SDL_SCANCODE_UNKNOWN, + /* 274, 0x112 */ SDL_SCANCODE_UNKNOWN, + /* 275, 0x113 */ SDL_SCANCODE_UNKNOWN, + /* 276, 0x114 */ SDL_SCANCODE_UNKNOWN, + /* 277, 0x115 */ SDL_SCANCODE_UNKNOWN, + /* 278, 0x116 */ SDL_SCANCODE_UNKNOWN, + /* 279, 0x117 */ SDL_SCANCODE_UNKNOWN, + /* 280, 0x118 */ SDL_SCANCODE_UNKNOWN, + /* 281, 0x119 */ SDL_SCANCODE_UNKNOWN, + /* 282, 0x11a */ SDL_SCANCODE_UNKNOWN, + /* 283, 0x11b */ SDL_SCANCODE_UNKNOWN, + /* 284, 0x11c */ SDL_SCANCODE_UNKNOWN, + /* 285, 0x11d */ SDL_SCANCODE_UNKNOWN, + /* 286, 0x11e */ SDL_SCANCODE_UNKNOWN, + /* 287, 0x11f */ SDL_SCANCODE_UNKNOWN, + /* 288, 0x120 */ SDL_SCANCODE_UNKNOWN, + /* 289, 0x121 */ SDL_SCANCODE_UNKNOWN, + /* 290, 0x122 */ SDL_SCANCODE_UNKNOWN, + /* 291, 0x123 */ SDL_SCANCODE_UNKNOWN, + /* 292, 0x124 */ SDL_SCANCODE_UNKNOWN, + /* 293, 0x125 */ SDL_SCANCODE_UNKNOWN, + /* 294, 0x126 */ SDL_SCANCODE_UNKNOWN, + /* 295, 0x127 */ SDL_SCANCODE_UNKNOWN, + /* 296, 0x128 */ SDL_SCANCODE_UNKNOWN, + /* 297, 0x129 */ SDL_SCANCODE_UNKNOWN, + /* 298, 0x12a */ SDL_SCANCODE_UNKNOWN, + /* 299, 0x12b */ SDL_SCANCODE_UNKNOWN, + /* 300, 0x12c */ SDL_SCANCODE_UNKNOWN, + /* 301, 0x12d */ SDL_SCANCODE_UNKNOWN, + /* 302, 0x12e */ SDL_SCANCODE_UNKNOWN, + /* 303, 0x12f */ SDL_SCANCODE_UNKNOWN, + /* 304, 0x130 */ SDL_SCANCODE_UNKNOWN, + /* 305, 0x131 */ SDL_SCANCODE_UNKNOWN, + /* 306, 0x132 */ SDL_SCANCODE_UNKNOWN, + /* 307, 0x133 */ SDL_SCANCODE_UNKNOWN, + /* 308, 0x134 */ SDL_SCANCODE_UNKNOWN, + /* 309, 0x135 */ SDL_SCANCODE_UNKNOWN, + /* 310, 0x136 */ SDL_SCANCODE_UNKNOWN, + /* 311, 0x137 */ SDL_SCANCODE_UNKNOWN, + /* 312, 0x138 */ SDL_SCANCODE_UNKNOWN, + /* 313, 0x139 */ SDL_SCANCODE_UNKNOWN, + /* 314, 0x13a */ SDL_SCANCODE_UNKNOWN, + /* 315, 0x13b */ SDL_SCANCODE_UNKNOWN, + /* 316, 0x13c */ SDL_SCANCODE_UNKNOWN, + /* 317, 0x13d */ SDL_SCANCODE_UNKNOWN, + /* 318, 0x13e */ SDL_SCANCODE_UNKNOWN, + /* 319, 0x13f */ SDL_SCANCODE_UNKNOWN, + /* 320, 0x140 */ SDL_SCANCODE_UNKNOWN, + /* 321, 0x141 */ SDL_SCANCODE_UNKNOWN, + /* 322, 0x142 */ SDL_SCANCODE_UNKNOWN, + /* 323, 0x143 */ SDL_SCANCODE_UNKNOWN, + /* 324, 0x144 */ SDL_SCANCODE_UNKNOWN, + /* 325, 0x145 */ SDL_SCANCODE_UNKNOWN, + /* 326, 0x146 */ SDL_SCANCODE_UNKNOWN, + /* 327, 0x147 */ SDL_SCANCODE_UNKNOWN, + /* 328, 0x148 */ SDL_SCANCODE_UNKNOWN, + /* 329, 0x149 */ SDL_SCANCODE_UNKNOWN, + /* 330, 0x14a */ SDL_SCANCODE_UNKNOWN, + /* 331, 0x14b */ SDL_SCANCODE_UNKNOWN, + /* 332, 0x14c */ SDL_SCANCODE_UNKNOWN, + /* 333, 0x14d */ SDL_SCANCODE_UNKNOWN, + /* 334, 0x14e */ SDL_SCANCODE_UNKNOWN, + /* 335, 0x14f */ SDL_SCANCODE_UNKNOWN, + /* 336, 0x150 */ SDL_SCANCODE_UNKNOWN, + /* 337, 0x151 */ SDL_SCANCODE_UNKNOWN, + /* 338, 0x152 */ SDL_SCANCODE_UNKNOWN, + /* 339, 0x153 */ SDL_SCANCODE_UNKNOWN, + /* 340, 0x154 */ SDL_SCANCODE_UNKNOWN, + /* 341, 0x155 */ SDL_SCANCODE_UNKNOWN, + /* 342, 0x156 */ SDL_SCANCODE_UNKNOWN, + /* 343, 0x157 */ SDL_SCANCODE_UNKNOWN, + /* 344, 0x158 */ SDL_SCANCODE_UNKNOWN, + /* 345, 0x159 */ SDL_SCANCODE_UNKNOWN, + /* 346, 0x15a */ SDL_SCANCODE_UNKNOWN, + /* 347, 0x15b */ SDL_SCANCODE_UNKNOWN, + /* 348, 0x15c */ SDL_SCANCODE_UNKNOWN, + /* 349, 0x15d */ SDL_SCANCODE_UNKNOWN, + /* 350, 0x15e */ SDL_SCANCODE_UNKNOWN, + /* 351, 0x15f */ SDL_SCANCODE_UNKNOWN, + /* 352, 0x160 */ SDL_SCANCODE_UNKNOWN, // KEY_OK + /* 353, 0x161 */ SDL_SCANCODE_SELECT, // KEY_SELECT + /* 354, 0x162 */ SDL_SCANCODE_UNKNOWN, // KEY_GOTO + /* 355, 0x163 */ SDL_SCANCODE_CLEAR, // KEY_CLEAR + /* 356, 0x164 */ SDL_SCANCODE_UNKNOWN, // KEY_POWER2 + /* 357, 0x165 */ SDL_SCANCODE_UNKNOWN, // KEY_OPTION + /* 358, 0x166 */ SDL_SCANCODE_UNKNOWN, // KEY_INFO + /* 359, 0x167 */ SDL_SCANCODE_UNKNOWN, // KEY_TIME + /* 360, 0x168 */ SDL_SCANCODE_UNKNOWN, // KEY_VENDOR + /* 361, 0x169 */ SDL_SCANCODE_UNKNOWN, // KEY_ARCHIVE + /* 362, 0x16a */ SDL_SCANCODE_UNKNOWN, // KEY_PROGRAM + /* 363, 0x16b */ SDL_SCANCODE_UNKNOWN, // KEY_CHANNEL + /* 364, 0x16c */ SDL_SCANCODE_UNKNOWN, // KEY_FAVORITES + /* 365, 0x16d */ SDL_SCANCODE_UNKNOWN, // KEY_EPG + /* 366, 0x16e */ SDL_SCANCODE_UNKNOWN, // KEY_PVR + /* 367, 0x16f */ SDL_SCANCODE_UNKNOWN, // KEY_MHP + /* 368, 0x170 */ SDL_SCANCODE_UNKNOWN, // KEY_LANGUAGE + /* 369, 0x171 */ SDL_SCANCODE_UNKNOWN, // KEY_TITLE + /* 370, 0x172 */ SDL_SCANCODE_UNKNOWN, // KEY_SUBTITLE + /* 371, 0x173 */ SDL_SCANCODE_UNKNOWN, // KEY_ANGLE + /* 372, 0x174 */ SDL_SCANCODE_UNKNOWN, // KEY_FULL_SCREEN + /* 373, 0x175 */ SDL_SCANCODE_MODE, // KEY_MODE + /* 374, 0x176 */ SDL_SCANCODE_UNKNOWN, // KEY_KEYBOARD + /* 375, 0x177 */ SDL_SCANCODE_UNKNOWN, // KEY_ASPECT_RATIO + /* 376, 0x178 */ SDL_SCANCODE_UNKNOWN, // KEY_PC + /* 377, 0x179 */ SDL_SCANCODE_UNKNOWN, // KEY_TV + /* 378, 0x17a */ SDL_SCANCODE_UNKNOWN, // KEY_TV2 + /* 379, 0x17b */ SDL_SCANCODE_UNKNOWN, // KEY_VCR + /* 380, 0x17c */ SDL_SCANCODE_UNKNOWN, // KEY_VCR2 + /* 381, 0x17d */ SDL_SCANCODE_UNKNOWN, // KEY_SAT + /* 382, 0x17e */ SDL_SCANCODE_UNKNOWN, // KEY_SAT2 + /* 383, 0x17f */ SDL_SCANCODE_UNKNOWN, // KEY_CD + /* 384, 0x180 */ SDL_SCANCODE_UNKNOWN, // KEY_TAPE + /* 385, 0x181 */ SDL_SCANCODE_UNKNOWN, // KEY_RADIO + /* 386, 0x182 */ SDL_SCANCODE_UNKNOWN, // KEY_TUNER + /* 387, 0x183 */ SDL_SCANCODE_UNKNOWN, // KEY_PLAYER + /* 388, 0x184 */ SDL_SCANCODE_UNKNOWN, // KEY_TEXT + /* 389, 0x185 */ SDL_SCANCODE_UNKNOWN, // KEY_DVD + /* 390, 0x186 */ SDL_SCANCODE_UNKNOWN, // KEY_AUX + /* 391, 0x187 */ SDL_SCANCODE_UNKNOWN, // KEY_MP3 + /* 392, 0x188 */ SDL_SCANCODE_UNKNOWN, // KEY_AUDIO + /* 393, 0x189 */ SDL_SCANCODE_UNKNOWN, // KEY_VIDEO + /* 394, 0x18a */ SDL_SCANCODE_UNKNOWN, // KEY_DIRECTORY + /* 395, 0x18b */ SDL_SCANCODE_UNKNOWN, // KEY_LIST + /* 396, 0x18c */ SDL_SCANCODE_UNKNOWN, // KEY_MEMO + /* 397, 0x18d */ SDL_SCANCODE_UNKNOWN, // KEY_CALENDAR + /* 398, 0x18e */ SDL_SCANCODE_UNKNOWN, // KEY_RED + /* 399, 0x18f */ SDL_SCANCODE_UNKNOWN, // KEY_GREEN + /* 400, 0x190 */ SDL_SCANCODE_UNKNOWN, // KEY_YELLOW + /* 401, 0x191 */ SDL_SCANCODE_UNKNOWN, // KEY_BLUE + /* 402, 0x192 */ SDL_SCANCODE_CHANNEL_INCREMENT, // KEY_CHANNELUP + /* 403, 0x193 */ SDL_SCANCODE_CHANNEL_DECREMENT, // KEY_CHANNELDOWN +#if 0 // We don't have any mapped scancodes after this point (yet) + /* 404, 0x194 */ SDL_SCANCODE_UNKNOWN, // KEY_FIRST + /* 405, 0x195 */ SDL_SCANCODE_UNKNOWN, // KEY_LAST + /* 406, 0x196 */ SDL_SCANCODE_UNKNOWN, // KEY_AB + /* 407, 0x197 */ SDL_SCANCODE_UNKNOWN, // KEY_NEXT + /* 408, 0x198 */ SDL_SCANCODE_UNKNOWN, // KEY_RESTART + /* 409, 0x199 */ SDL_SCANCODE_UNKNOWN, // KEY_SLOW + /* 410, 0x19a */ SDL_SCANCODE_UNKNOWN, // KEY_SHUFFLE + /* 411, 0x19b */ SDL_SCANCODE_UNKNOWN, // KEY_BREAK + /* 412, 0x19c */ SDL_SCANCODE_UNKNOWN, // KEY_PREVIOUS + /* 413, 0x19d */ SDL_SCANCODE_UNKNOWN, // KEY_DIGITS + /* 414, 0x19e */ SDL_SCANCODE_UNKNOWN, // KEY_TEEN + /* 415, 0x19f */ SDL_SCANCODE_UNKNOWN, // KEY_TWEN + /* 416, 0x1a0 */ SDL_SCANCODE_UNKNOWN, // KEY_VIDEOPHONE + /* 417, 0x1a1 */ SDL_SCANCODE_UNKNOWN, // KEY_GAMES + /* 418, 0x1a2 */ SDL_SCANCODE_UNKNOWN, // KEY_ZOOMIN + /* 419, 0x1a3 */ SDL_SCANCODE_UNKNOWN, // KEY_ZOOMOUT + /* 420, 0x1a4 */ SDL_SCANCODE_UNKNOWN, // KEY_ZOOMRESET + /* 421, 0x1a5 */ SDL_SCANCODE_UNKNOWN, // KEY_WORDPROCESSOR + /* 422, 0x1a6 */ SDL_SCANCODE_UNKNOWN, // KEY_EDITOR + /* 423, 0x1a7 */ SDL_SCANCODE_UNKNOWN, // KEY_SPREADSHEET + /* 424, 0x1a8 */ SDL_SCANCODE_UNKNOWN, // KEY_GRAPHICSEDITOR + /* 425, 0x1a9 */ SDL_SCANCODE_UNKNOWN, // KEY_PRESENTATION + /* 426, 0x1aa */ SDL_SCANCODE_UNKNOWN, // KEY_DATABASE + /* 427, 0x1ab */ SDL_SCANCODE_UNKNOWN, // KEY_NEWS + /* 428, 0x1ac */ SDL_SCANCODE_UNKNOWN, // KEY_VOICEMAIL + /* 429, 0x1ad */ SDL_SCANCODE_UNKNOWN, // KEY_ADDRESSBOOK + /* 430, 0x1ae */ SDL_SCANCODE_UNKNOWN, // KEY_MESSENGER + /* 431, 0x1af */ SDL_SCANCODE_UNKNOWN, // KEY_DISPLAYTOGGLE + /* 432, 0x1b0 */ SDL_SCANCODE_UNKNOWN, // KEY_SPELLCHECK + /* 433, 0x1b1 */ SDL_SCANCODE_UNKNOWN, // KEY_LOGOFF + /* 434, 0x1b2 */ SDL_SCANCODE_UNKNOWN, // KEY_DOLLAR + /* 435, 0x1b3 */ SDL_SCANCODE_UNKNOWN, // KEY_EURO + /* 436, 0x1b4 */ SDL_SCANCODE_UNKNOWN, // KEY_FRAMEBACK + /* 437, 0x1b5 */ SDL_SCANCODE_UNKNOWN, // KEY_FRAMEFORWARD + /* 438, 0x1b6 */ SDL_SCANCODE_UNKNOWN, // KEY_CONTEXT_MENU + /* 439, 0x1b7 */ SDL_SCANCODE_UNKNOWN, // KEY_MEDIA_REPEAT + /* 440, 0x1b8 */ SDL_SCANCODE_UNKNOWN, // KEY_10CHANNELSUP + /* 441, 0x1b9 */ SDL_SCANCODE_UNKNOWN, // KEY_10CHANNELSDOWN + /* 442, 0x1ba */ SDL_SCANCODE_UNKNOWN, // KEY_IMAGES + /* 443, 0x1bb */ SDL_SCANCODE_UNKNOWN, + /* 444, 0x1bc */ SDL_SCANCODE_UNKNOWN, // KEY_NOTIFICATION_CENTER + /* 445, 0x1bd */ SDL_SCANCODE_UNKNOWN, // KEY_PICKUP_PHONE + /* 446, 0x1be */ SDL_SCANCODE_UNKNOWN, // KEY_HANGUP_PHONE + /* 447, 0x1bf */ SDL_SCANCODE_UNKNOWN, + /* 448, 0x1c0 */ SDL_SCANCODE_UNKNOWN, // KEY_DEL_EOL + /* 449, 0x1c1 */ SDL_SCANCODE_UNKNOWN, // KEY_DEL_EOS + /* 450, 0x1c2 */ SDL_SCANCODE_UNKNOWN, // KEY_INS_LINE + /* 451, 0x1c3 */ SDL_SCANCODE_UNKNOWN, // KEY_DEL_LINE + /* 452, 0x1c4 */ SDL_SCANCODE_UNKNOWN, + /* 453, 0x1c5 */ SDL_SCANCODE_UNKNOWN, + /* 454, 0x1c6 */ SDL_SCANCODE_UNKNOWN, + /* 455, 0x1c7 */ SDL_SCANCODE_UNKNOWN, + /* 456, 0x1c8 */ SDL_SCANCODE_UNKNOWN, + /* 457, 0x1c9 */ SDL_SCANCODE_UNKNOWN, + /* 458, 0x1ca */ SDL_SCANCODE_UNKNOWN, + /* 459, 0x1cb */ SDL_SCANCODE_UNKNOWN, + /* 460, 0x1cc */ SDL_SCANCODE_UNKNOWN, + /* 461, 0x1cd */ SDL_SCANCODE_UNKNOWN, + /* 462, 0x1ce */ SDL_SCANCODE_UNKNOWN, + /* 463, 0x1cf */ SDL_SCANCODE_UNKNOWN, + /* 464, 0x1d0 */ SDL_SCANCODE_UNKNOWN, // KEY_FN + /* 465, 0x1d1 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_ESC + /* 466, 0x1d2 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_F1 + /* 467, 0x1d3 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_F2 + /* 468, 0x1d4 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_F3 + /* 469, 0x1d5 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_F4 + /* 470, 0x1d6 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_F5 + /* 471, 0x1d7 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_F6 + /* 472, 0x1d8 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_F7 + /* 473, 0x1d9 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_F8 + /* 474, 0x1da */ SDL_SCANCODE_UNKNOWN, // KEY_FN_F9 + /* 475, 0x1db */ SDL_SCANCODE_UNKNOWN, // KEY_FN_F10 + /* 476, 0x1dc */ SDL_SCANCODE_UNKNOWN, // KEY_FN_F11 + /* 477, 0x1dd */ SDL_SCANCODE_UNKNOWN, // KEY_FN_F12 + /* 478, 0x1de */ SDL_SCANCODE_UNKNOWN, // KEY_FN_1 + /* 479, 0x1df */ SDL_SCANCODE_UNKNOWN, // KEY_FN_2 + /* 480, 0x1e0 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_D + /* 481, 0x1e1 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_E + /* 482, 0x1e2 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_F + /* 483, 0x1e3 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_S + /* 484, 0x1e4 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_B + /* 485, 0x1e5 */ SDL_SCANCODE_UNKNOWN, // KEY_FN_RIGHT_SHIFT + /* 486, 0x1e6 */ SDL_SCANCODE_UNKNOWN, + /* 487, 0x1e7 */ SDL_SCANCODE_UNKNOWN, + /* 488, 0x1e8 */ SDL_SCANCODE_UNKNOWN, + /* 489, 0x1e9 */ SDL_SCANCODE_UNKNOWN, + /* 490, 0x1ea */ SDL_SCANCODE_UNKNOWN, + /* 491, 0x1eb */ SDL_SCANCODE_UNKNOWN, + /* 492, 0x1ec */ SDL_SCANCODE_UNKNOWN, + /* 493, 0x1ed */ SDL_SCANCODE_UNKNOWN, + /* 494, 0x1ee */ SDL_SCANCODE_UNKNOWN, + /* 495, 0x1ef */ SDL_SCANCODE_UNKNOWN, + /* 496, 0x1f0 */ SDL_SCANCODE_UNKNOWN, + /* 497, 0x1f1 */ SDL_SCANCODE_UNKNOWN, // KEY_BRL_DOT1 + /* 498, 0x1f2 */ SDL_SCANCODE_UNKNOWN, // KEY_BRL_DOT2 + /* 499, 0x1f3 */ SDL_SCANCODE_UNKNOWN, // KEY_BRL_DOT3 + /* 500, 0x1f4 */ SDL_SCANCODE_UNKNOWN, // KEY_BRL_DOT4 + /* 501, 0x1f5 */ SDL_SCANCODE_UNKNOWN, // KEY_BRL_DOT5 + /* 502, 0x1f6 */ SDL_SCANCODE_UNKNOWN, // KEY_BRL_DOT6 + /* 503, 0x1f7 */ SDL_SCANCODE_UNKNOWN, // KEY_BRL_DOT7 + /* 504, 0x1f8 */ SDL_SCANCODE_UNKNOWN, // KEY_BRL_DOT8 + /* 505, 0x1f9 */ SDL_SCANCODE_UNKNOWN, // KEY_BRL_DOT9 + /* 506, 0x1fa */ SDL_SCANCODE_UNKNOWN, // KEY_BRL_DOT10 + /* 507, 0x1fb */ SDL_SCANCODE_UNKNOWN, + /* 508, 0x1fc */ SDL_SCANCODE_UNKNOWN, + /* 509, 0x1fd */ SDL_SCANCODE_UNKNOWN, + /* 510, 0x1fe */ SDL_SCANCODE_UNKNOWN, + /* 511, 0x1ff */ SDL_SCANCODE_UNKNOWN, + /* 512, 0x200 */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_0 + /* 513, 0x201 */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_1 + /* 514, 0x202 */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_2 + /* 515, 0x203 */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_3 + /* 516, 0x204 */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_4 + /* 517, 0x205 */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_5 + /* 518, 0x206 */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_6 + /* 519, 0x207 */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_7 + /* 520, 0x208 */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_8 + /* 521, 0x209 */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_9 + /* 522, 0x20a */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_STAR + /* 523, 0x20b */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_POUND + /* 524, 0x20c */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_A + /* 525, 0x20d */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_B + /* 526, 0x20e */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_C + /* 527, 0x20f */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_D + /* 528, 0x210 */ SDL_SCANCODE_UNKNOWN, // KEY_CAMERA_FOCUS + /* 529, 0x211 */ SDL_SCANCODE_UNKNOWN, // KEY_WPS_BUTTON + /* 530, 0x212 */ SDL_SCANCODE_UNKNOWN, // KEY_TOUCHPAD_TOGGLE + /* 531, 0x213 */ SDL_SCANCODE_UNKNOWN, // KEY_TOUCHPAD_ON + /* 532, 0x214 */ SDL_SCANCODE_UNKNOWN, // KEY_TOUCHPAD_OFF + /* 533, 0x215 */ SDL_SCANCODE_UNKNOWN, // KEY_CAMERA_ZOOMIN + /* 534, 0x216 */ SDL_SCANCODE_UNKNOWN, // KEY_CAMERA_ZOOMOUT + /* 535, 0x217 */ SDL_SCANCODE_UNKNOWN, // KEY_CAMERA_UP + /* 536, 0x218 */ SDL_SCANCODE_UNKNOWN, // KEY_CAMERA_DOWN + /* 537, 0x219 */ SDL_SCANCODE_UNKNOWN, // KEY_CAMERA_LEFT + /* 538, 0x21a */ SDL_SCANCODE_UNKNOWN, // KEY_CAMERA_RIGHT + /* 539, 0x21b */ SDL_SCANCODE_UNKNOWN, // KEY_ATTENDANT_ON + /* 540, 0x21c */ SDL_SCANCODE_UNKNOWN, // KEY_ATTENDANT_OFF + /* 541, 0x21d */ SDL_SCANCODE_UNKNOWN, // KEY_ATTENDANT_TOGGLE + /* 542, 0x21e */ SDL_SCANCODE_UNKNOWN, // KEY_LIGHTS_TOGGLE + /* 543, 0x21f */ SDL_SCANCODE_UNKNOWN, + /* 544, 0x220 */ SDL_SCANCODE_UNKNOWN, + /* 545, 0x221 */ SDL_SCANCODE_UNKNOWN, + /* 546, 0x222 */ SDL_SCANCODE_UNKNOWN, + /* 547, 0x223 */ SDL_SCANCODE_UNKNOWN, + /* 548, 0x224 */ SDL_SCANCODE_UNKNOWN, + /* 549, 0x225 */ SDL_SCANCODE_UNKNOWN, + /* 550, 0x226 */ SDL_SCANCODE_UNKNOWN, + /* 551, 0x227 */ SDL_SCANCODE_UNKNOWN, + /* 552, 0x228 */ SDL_SCANCODE_UNKNOWN, + /* 553, 0x229 */ SDL_SCANCODE_UNKNOWN, + /* 554, 0x22a */ SDL_SCANCODE_UNKNOWN, + /* 555, 0x22b */ SDL_SCANCODE_UNKNOWN, + /* 556, 0x22c */ SDL_SCANCODE_UNKNOWN, + /* 557, 0x22d */ SDL_SCANCODE_UNKNOWN, + /* 558, 0x22e */ SDL_SCANCODE_UNKNOWN, + /* 559, 0x22f */ SDL_SCANCODE_UNKNOWN, + /* 560, 0x230 */ SDL_SCANCODE_UNKNOWN, // KEY_ALS_TOGGLE + /* 561, 0x231 */ SDL_SCANCODE_UNKNOWN, // KEY_ROTATE_LOCK_TOGGLE + /* 562, 0x232 */ SDL_SCANCODE_UNKNOWN, + /* 563, 0x233 */ SDL_SCANCODE_UNKNOWN, + /* 564, 0x234 */ SDL_SCANCODE_UNKNOWN, + /* 565, 0x235 */ SDL_SCANCODE_UNKNOWN, + /* 566, 0x236 */ SDL_SCANCODE_UNKNOWN, + /* 567, 0x237 */ SDL_SCANCODE_UNKNOWN, + /* 568, 0x238 */ SDL_SCANCODE_UNKNOWN, + /* 569, 0x239 */ SDL_SCANCODE_UNKNOWN, + /* 570, 0x23a */ SDL_SCANCODE_UNKNOWN, + /* 571, 0x23b */ SDL_SCANCODE_UNKNOWN, + /* 572, 0x23c */ SDL_SCANCODE_UNKNOWN, + /* 573, 0x23d */ SDL_SCANCODE_UNKNOWN, + /* 574, 0x23e */ SDL_SCANCODE_UNKNOWN, + /* 575, 0x23f */ SDL_SCANCODE_UNKNOWN, + /* 576, 0x240 */ SDL_SCANCODE_UNKNOWN, // KEY_BUTTONCONFIG + /* 577, 0x241 */ SDL_SCANCODE_UNKNOWN, // KEY_TASKMANAGER + /* 578, 0x242 */ SDL_SCANCODE_UNKNOWN, // KEY_JOURNAL + /* 579, 0x243 */ SDL_SCANCODE_UNKNOWN, // KEY_CONTROLPANEL + /* 580, 0x244 */ SDL_SCANCODE_UNKNOWN, // KEY_APPSELECT + /* 581, 0x245 */ SDL_SCANCODE_UNKNOWN, // KEY_SCREENSAVER + /* 582, 0x246 */ SDL_SCANCODE_UNKNOWN, // KEY_VOICECOMMAND + /* 583, 0x247 */ SDL_SCANCODE_UNKNOWN, // KEY_ASSISTANT + /* 584, 0x248 */ SDL_SCANCODE_UNKNOWN, // KEY_KBD_LAYOUT_NEXT + /* 585, 0x249 */ SDL_SCANCODE_UNKNOWN, // KEY_EMOJI_PICKER + /* 586, 0x24a */ SDL_SCANCODE_UNKNOWN, // KEY_DICTATE + /* 587, 0x24b */ SDL_SCANCODE_UNKNOWN, + /* 588, 0x24c */ SDL_SCANCODE_UNKNOWN, + /* 589, 0x24d */ SDL_SCANCODE_UNKNOWN, + /* 590, 0x24e */ SDL_SCANCODE_UNKNOWN, + /* 591, 0x24f */ SDL_SCANCODE_UNKNOWN, + /* 592, 0x250 */ SDL_SCANCODE_UNKNOWN, // KEY_BRIGHTNESS_MIN + /* 593, 0x251 */ SDL_SCANCODE_UNKNOWN, // KEY_BRIGHTNESS_MAX + /* 594, 0x252 */ SDL_SCANCODE_UNKNOWN, + /* 595, 0x253 */ SDL_SCANCODE_UNKNOWN, + /* 596, 0x254 */ SDL_SCANCODE_UNKNOWN, + /* 597, 0x255 */ SDL_SCANCODE_UNKNOWN, + /* 598, 0x256 */ SDL_SCANCODE_UNKNOWN, + /* 599, 0x257 */ SDL_SCANCODE_UNKNOWN, + /* 600, 0x258 */ SDL_SCANCODE_UNKNOWN, + /* 601, 0x259 */ SDL_SCANCODE_UNKNOWN, + /* 602, 0x25a */ SDL_SCANCODE_UNKNOWN, + /* 603, 0x25b */ SDL_SCANCODE_UNKNOWN, + /* 604, 0x25c */ SDL_SCANCODE_UNKNOWN, + /* 605, 0x25d */ SDL_SCANCODE_UNKNOWN, + /* 606, 0x25e */ SDL_SCANCODE_UNKNOWN, + /* 607, 0x25f */ SDL_SCANCODE_UNKNOWN, + /* 608, 0x260 */ SDL_SCANCODE_UNKNOWN, // KEY_KBDINPUTASSIST_PREV + /* 609, 0x261 */ SDL_SCANCODE_UNKNOWN, // KEY_KBDINPUTASSIST_NEXT + /* 610, 0x262 */ SDL_SCANCODE_UNKNOWN, // KEY_KBDINPUTASSIST_PREVGROUP + /* 611, 0x263 */ SDL_SCANCODE_UNKNOWN, // KEY_KBDINPUTASSIST_NEXTGROUP + /* 612, 0x264 */ SDL_SCANCODE_UNKNOWN, // KEY_KBDINPUTASSIST_ACCEPT + /* 613, 0x265 */ SDL_SCANCODE_UNKNOWN, // KEY_KBDINPUTASSIST_CANCEL + /* 614, 0x266 */ SDL_SCANCODE_UNKNOWN, // KEY_RIGHT_UP + /* 615, 0x267 */ SDL_SCANCODE_UNKNOWN, // KEY_RIGHT_DOWN + /* 616, 0x268 */ SDL_SCANCODE_UNKNOWN, // KEY_LEFT_UP + /* 617, 0x269 */ SDL_SCANCODE_UNKNOWN, // KEY_LEFT_DOWN + /* 618, 0x26a */ SDL_SCANCODE_UNKNOWN, // KEY_ROOT_MENU + /* 619, 0x26b */ SDL_SCANCODE_UNKNOWN, // KEY_MEDIA_TOP_MENU + /* 620, 0x26c */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_11 + /* 621, 0x26d */ SDL_SCANCODE_UNKNOWN, // KEY_NUMERIC_12 + /* 622, 0x26e */ SDL_SCANCODE_UNKNOWN, // KEY_AUDIO_DESC + /* 623, 0x26f */ SDL_SCANCODE_UNKNOWN, // KEY_3D_MODE + /* 624, 0x270 */ SDL_SCANCODE_UNKNOWN, // KEY_NEXT_FAVORITE + /* 625, 0x271 */ SDL_SCANCODE_UNKNOWN, // KEY_STOP_RECORD + /* 626, 0x272 */ SDL_SCANCODE_UNKNOWN, // KEY_PAUSE_RECORD + /* 627, 0x273 */ SDL_SCANCODE_UNKNOWN, // KEY_VOD + /* 628, 0x274 */ SDL_SCANCODE_UNKNOWN, // KEY_UNMUTE + /* 629, 0x275 */ SDL_SCANCODE_UNKNOWN, // KEY_FASTREVERSE + /* 630, 0x276 */ SDL_SCANCODE_UNKNOWN, // KEY_SLOWREVERSE + /* 631, 0x277 */ SDL_SCANCODE_UNKNOWN, // KEY_DATA + /* 632, 0x278 */ SDL_SCANCODE_UNKNOWN, // KEY_ONSCREEN_KEYBOARD + /* 633, 0x279 */ SDL_SCANCODE_UNKNOWN, // KEY_PRIVACY_SCREEN_TOGGLE + /* 634, 0x27a */ SDL_SCANCODE_UNKNOWN, // KEY_SELECTIVE_SCREENSHOT + /* 635, 0x27b */ SDL_SCANCODE_UNKNOWN, + /* 636, 0x27c */ SDL_SCANCODE_UNKNOWN, + /* 637, 0x27d */ SDL_SCANCODE_UNKNOWN, + /* 638, 0x27e */ SDL_SCANCODE_UNKNOWN, + /* 639, 0x27f */ SDL_SCANCODE_UNKNOWN, + /* 640, 0x280 */ SDL_SCANCODE_UNKNOWN, + /* 641, 0x281 */ SDL_SCANCODE_UNKNOWN, + /* 642, 0x282 */ SDL_SCANCODE_UNKNOWN, + /* 643, 0x283 */ SDL_SCANCODE_UNKNOWN, + /* 644, 0x284 */ SDL_SCANCODE_UNKNOWN, + /* 645, 0x285 */ SDL_SCANCODE_UNKNOWN, + /* 646, 0x286 */ SDL_SCANCODE_UNKNOWN, + /* 647, 0x287 */ SDL_SCANCODE_UNKNOWN, + /* 648, 0x288 */ SDL_SCANCODE_UNKNOWN, + /* 649, 0x289 */ SDL_SCANCODE_UNKNOWN, + /* 650, 0x28a */ SDL_SCANCODE_UNKNOWN, + /* 651, 0x28b */ SDL_SCANCODE_UNKNOWN, + /* 652, 0x28c */ SDL_SCANCODE_UNKNOWN, + /* 653, 0x28d */ SDL_SCANCODE_UNKNOWN, + /* 654, 0x28e */ SDL_SCANCODE_UNKNOWN, + /* 655, 0x28f */ SDL_SCANCODE_UNKNOWN, + /* 656, 0x290 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO1 + /* 657, 0x291 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO2 + /* 658, 0x292 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO3 + /* 659, 0x293 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO4 + /* 660, 0x294 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO5 + /* 661, 0x295 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO6 + /* 662, 0x296 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO7 + /* 663, 0x297 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO8 + /* 664, 0x298 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO9 + /* 665, 0x299 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO10 + /* 666, 0x29a */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO11 + /* 667, 0x29b */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO12 + /* 668, 0x29c */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO13 + /* 669, 0x29d */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO14 + /* 670, 0x29e */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO15 + /* 671, 0x29f */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO16 + /* 672, 0x2a0 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO17 + /* 673, 0x2a1 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO18 + /* 674, 0x2a2 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO19 + /* 675, 0x2a3 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO20 + /* 676, 0x2a4 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO21 + /* 677, 0x2a5 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO22 + /* 678, 0x2a6 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO23 + /* 679, 0x2a7 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO24 + /* 680, 0x2a8 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO25 + /* 681, 0x2a9 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO26 + /* 682, 0x2aa */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO27 + /* 683, 0x2ab */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO28 + /* 684, 0x2ac */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO29 + /* 685, 0x2ad */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO30 + /* 686, 0x2ae */ SDL_SCANCODE_UNKNOWN, + /* 687, 0x2af */ SDL_SCANCODE_UNKNOWN, + /* 688, 0x2b0 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO_RECORD_START + /* 689, 0x2b1 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO_RECORD_STOP + /* 690, 0x2b2 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO_PRESET_CYCLE + /* 691, 0x2b3 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO_PRESET1 + /* 692, 0x2b4 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO_PRESET2 + /* 693, 0x2b5 */ SDL_SCANCODE_UNKNOWN, // KEY_MACRO_PRESET3 + /* 694, 0x2b6 */ SDL_SCANCODE_UNKNOWN, + /* 695, 0x2b7 */ SDL_SCANCODE_UNKNOWN, + /* 696, 0x2b8 */ SDL_SCANCODE_UNKNOWN, // KEY_KBD_LCD_MENU1 + /* 697, 0x2b9 */ SDL_SCANCODE_UNKNOWN, // KEY_KBD_LCD_MENU2 + /* 698, 0x2ba */ SDL_SCANCODE_UNKNOWN, // KEY_KBD_LCD_MENU3 + /* 699, 0x2bb */ SDL_SCANCODE_UNKNOWN, // KEY_KBD_LCD_MENU4 + /* 700, 0x2bc */ SDL_SCANCODE_UNKNOWN, // KEY_KBD_LCD_MENU5 + /* 701, 0x2bd */ SDL_SCANCODE_UNKNOWN, + /* 702, 0x2be */ SDL_SCANCODE_UNKNOWN, + /* 703, 0x2bf */ SDL_SCANCODE_UNKNOWN, + /* 704, 0x2c0 */ SDL_SCANCODE_UNKNOWN, + /* 705, 0x2c1 */ SDL_SCANCODE_UNKNOWN, + /* 706, 0x2c2 */ SDL_SCANCODE_UNKNOWN, + /* 707, 0x2c3 */ SDL_SCANCODE_UNKNOWN, + /* 708, 0x2c4 */ SDL_SCANCODE_UNKNOWN, + /* 709, 0x2c5 */ SDL_SCANCODE_UNKNOWN, + /* 710, 0x2c6 */ SDL_SCANCODE_UNKNOWN, + /* 711, 0x2c7 */ SDL_SCANCODE_UNKNOWN, + /* 712, 0x2c8 */ SDL_SCANCODE_UNKNOWN, + /* 713, 0x2c9 */ SDL_SCANCODE_UNKNOWN, + /* 714, 0x2ca */ SDL_SCANCODE_UNKNOWN, + /* 715, 0x2cb */ SDL_SCANCODE_UNKNOWN, + /* 716, 0x2cc */ SDL_SCANCODE_UNKNOWN, + /* 717, 0x2cd */ SDL_SCANCODE_UNKNOWN, + /* 718, 0x2ce */ SDL_SCANCODE_UNKNOWN, + /* 719, 0x2cf */ SDL_SCANCODE_UNKNOWN, + /* 720, 0x2d0 */ SDL_SCANCODE_UNKNOWN, + /* 721, 0x2d1 */ SDL_SCANCODE_UNKNOWN, + /* 722, 0x2d2 */ SDL_SCANCODE_UNKNOWN, + /* 723, 0x2d3 */ SDL_SCANCODE_UNKNOWN, + /* 724, 0x2d4 */ SDL_SCANCODE_UNKNOWN, + /* 725, 0x2d5 */ SDL_SCANCODE_UNKNOWN, + /* 726, 0x2d6 */ SDL_SCANCODE_UNKNOWN, + /* 727, 0x2d7 */ SDL_SCANCODE_UNKNOWN, + /* 728, 0x2d8 */ SDL_SCANCODE_UNKNOWN, + /* 729, 0x2d9 */ SDL_SCANCODE_UNKNOWN, + /* 730, 0x2da */ SDL_SCANCODE_UNKNOWN, + /* 731, 0x2db */ SDL_SCANCODE_UNKNOWN, + /* 732, 0x2dc */ SDL_SCANCODE_UNKNOWN, + /* 733, 0x2dd */ SDL_SCANCODE_UNKNOWN, + /* 734, 0x2de */ SDL_SCANCODE_UNKNOWN, + /* 735, 0x2df */ SDL_SCANCODE_UNKNOWN, + /* 736, 0x2e0 */ SDL_SCANCODE_UNKNOWN, + /* 737, 0x2e1 */ SDL_SCANCODE_UNKNOWN, + /* 738, 0x2e2 */ SDL_SCANCODE_UNKNOWN, + /* 739, 0x2e3 */ SDL_SCANCODE_UNKNOWN, + /* 740, 0x2e4 */ SDL_SCANCODE_UNKNOWN, + /* 741, 0x2e5 */ SDL_SCANCODE_UNKNOWN, + /* 742, 0x2e6 */ SDL_SCANCODE_UNKNOWN, + /* 743, 0x2e7 */ SDL_SCANCODE_UNKNOWN, + /* 744, 0x2e8 */ SDL_SCANCODE_UNKNOWN, + /* 745, 0x2e9 */ SDL_SCANCODE_UNKNOWN, + /* 746, 0x2ea */ SDL_SCANCODE_UNKNOWN, + /* 747, 0x2eb */ SDL_SCANCODE_UNKNOWN, + /* 748, 0x2ec */ SDL_SCANCODE_UNKNOWN, + /* 749, 0x2ed */ SDL_SCANCODE_UNKNOWN, + /* 750, 0x2ee */ SDL_SCANCODE_UNKNOWN, + /* 751, 0x2ef */ SDL_SCANCODE_UNKNOWN, + /* 752, 0x2f0 */ SDL_SCANCODE_UNKNOWN, + /* 753, 0x2f1 */ SDL_SCANCODE_UNKNOWN, + /* 754, 0x2f2 */ SDL_SCANCODE_UNKNOWN, + /* 755, 0x2f3 */ SDL_SCANCODE_UNKNOWN, + /* 756, 0x2f4 */ SDL_SCANCODE_UNKNOWN, + /* 757, 0x2f5 */ SDL_SCANCODE_UNKNOWN, + /* 758, 0x2f6 */ SDL_SCANCODE_UNKNOWN, + /* 759, 0x2f7 */ SDL_SCANCODE_UNKNOWN, + /* 760, 0x2f8 */ SDL_SCANCODE_UNKNOWN, + /* 761, 0x2f9 */ SDL_SCANCODE_UNKNOWN, + /* 762, 0x2fa */ SDL_SCANCODE_UNKNOWN, + /* 763, 0x2fb */ SDL_SCANCODE_UNKNOWN, + /* 764, 0x2fc */ SDL_SCANCODE_UNKNOWN, + /* 765, 0x2fd */ SDL_SCANCODE_UNKNOWN, + /* 766, 0x2fe */ SDL_SCANCODE_UNKNOWN, + /* 767, 0x2ff */ SDL_SCANCODE_UNKNOWN, // KEY_MAX +#endif // 0 +}; + +#if 0 // A shell script to update the Linux key names in this file +#!/bin/bash + +function get_keyname +{ + value=$(echo "$1" | awk '{print $3}') + grep -F KEY_ /usr/include/linux/input-event-codes.h | while read line; do + read -ra fields <<<"$line" + if [ "${fields[2]}" = "$value" ]; then + echo "${fields[1]}" + return + fi + done +} + +grep -F SDL_SCANCODE scancodes_linux.h | while read line; do + if [ $(echo "$line" | awk '{print NF}') -eq 5 ]; then + name=$(get_keyname "$line") + if [ "$name" != "" ]; then + echo " $line /* $name */" + continue + fi + fi + echo " $line" +done +#endif // end script + +#if 0 // A shell script to get comments from the Linux header for these keys +#!/bin/bash + +function get_comment +{ + name=$(echo "$1" | awk '{print $7}') + if [ "$name" != "" ]; then + grep -E "$name\s" /usr/include/linux/input-event-codes.h | grep -F "/*" | sed 's,[^/]*/,/,' + fi +} + +grep -F SDL_SCANCODE scancodes_linux.h | while read line; do + comment=$(get_comment "$line") + if [ "$comment" != "" ]; then + echo " $line $comment" + fi +done +#endif // end script + + +/* *INDENT-ON* */ // clang-format on diff --git a/contrib/SDL-3.2.8/src/events/scancodes_windows.h b/contrib/SDL-3.2.8/src/events/scancodes_windows.h new file mode 100644 index 0000000..6f35114 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/scancodes_windows.h @@ -0,0 +1,286 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +/* + * Windows scancode to SDL scancode mapping table + * https://learn.microsoft.com/windows/win32/inputdev/about-keyboard-input#scan-codes */ + +/* *INDENT-OFF* */ // clang-format off +static const SDL_Scancode windows_scancode_table[] = { + /*0x00*/ SDL_SCANCODE_UNKNOWN, + /*0x01*/ SDL_SCANCODE_ESCAPE, + /*0x02*/ SDL_SCANCODE_1, + /*0x03*/ SDL_SCANCODE_2, + /*0x04*/ SDL_SCANCODE_3, + /*0x05*/ SDL_SCANCODE_4, + /*0x06*/ SDL_SCANCODE_5, + /*0x07*/ SDL_SCANCODE_6, + /*0x08*/ SDL_SCANCODE_7, + /*0x09*/ SDL_SCANCODE_8, + /*0x0a*/ SDL_SCANCODE_9, + /*0x0b*/ SDL_SCANCODE_0, + /*0x0c*/ SDL_SCANCODE_MINUS, + /*0x0d*/ SDL_SCANCODE_EQUALS, + /*0x0e*/ SDL_SCANCODE_BACKSPACE, + /*0x0f*/ SDL_SCANCODE_TAB, + /*0x10*/ SDL_SCANCODE_Q, + /*0x11*/ SDL_SCANCODE_W, + /*0x12*/ SDL_SCANCODE_E, + /*0x13*/ SDL_SCANCODE_R, + /*0x14*/ SDL_SCANCODE_T, + /*0x15*/ SDL_SCANCODE_Y, + /*0x16*/ SDL_SCANCODE_U, + /*0x17*/ SDL_SCANCODE_I, + /*0x18*/ SDL_SCANCODE_O, + /*0x19*/ SDL_SCANCODE_P, + /*0x1a*/ SDL_SCANCODE_LEFTBRACKET, + /*0x1b*/ SDL_SCANCODE_RIGHTBRACKET, + /*0x1c*/ SDL_SCANCODE_RETURN, + /*0x1d*/ SDL_SCANCODE_LCTRL, + /*0x1e*/ SDL_SCANCODE_A, + /*0x1f*/ SDL_SCANCODE_S, + /*0x20*/ SDL_SCANCODE_D, + /*0x21*/ SDL_SCANCODE_F, + /*0x22*/ SDL_SCANCODE_G, + /*0x23*/ SDL_SCANCODE_H, + /*0x24*/ SDL_SCANCODE_J, + /*0x25*/ SDL_SCANCODE_K, + /*0x26*/ SDL_SCANCODE_L, + /*0x27*/ SDL_SCANCODE_SEMICOLON, + /*0x28*/ SDL_SCANCODE_APOSTROPHE, + /*0x29*/ SDL_SCANCODE_GRAVE, + /*0x2a*/ SDL_SCANCODE_LSHIFT, + /*0x2b*/ SDL_SCANCODE_BACKSLASH, + /*0x2c*/ SDL_SCANCODE_Z, + /*0x2d*/ SDL_SCANCODE_X, + /*0x2e*/ SDL_SCANCODE_C, + /*0x2f*/ SDL_SCANCODE_V, + /*0x30*/ SDL_SCANCODE_B, + /*0x31*/ SDL_SCANCODE_N, + /*0x32*/ SDL_SCANCODE_M, + /*0x33*/ SDL_SCANCODE_COMMA, + /*0x34*/ SDL_SCANCODE_PERIOD, + /*0x35*/ SDL_SCANCODE_SLASH, + /*0x36*/ SDL_SCANCODE_RSHIFT, + /*0x37*/ SDL_SCANCODE_KP_MULTIPLY, + /*0x38*/ SDL_SCANCODE_LALT, + /*0x39*/ SDL_SCANCODE_SPACE, + /*0x3a*/ SDL_SCANCODE_CAPSLOCK, + /*0x3b*/ SDL_SCANCODE_F1, + /*0x3c*/ SDL_SCANCODE_F2, + /*0x3d*/ SDL_SCANCODE_F3, + /*0x3e*/ SDL_SCANCODE_F4, + /*0x3f*/ SDL_SCANCODE_F5, + /*0x40*/ SDL_SCANCODE_F6, + /*0x41*/ SDL_SCANCODE_F7, + /*0x42*/ SDL_SCANCODE_F8, + /*0x43*/ SDL_SCANCODE_F9, + /*0x44*/ SDL_SCANCODE_F10, + /*0x45*/ SDL_SCANCODE_NUMLOCKCLEAR, + /*0x46*/ SDL_SCANCODE_SCROLLLOCK, + /*0x47*/ SDL_SCANCODE_KP_7, + /*0x48*/ SDL_SCANCODE_KP_8, + /*0x49*/ SDL_SCANCODE_KP_9, + /*0x4a*/ SDL_SCANCODE_KP_MINUS, + /*0x4b*/ SDL_SCANCODE_KP_4, + /*0x4c*/ SDL_SCANCODE_KP_5, + /*0x4d*/ SDL_SCANCODE_KP_6, + /*0x4e*/ SDL_SCANCODE_KP_PLUS, + /*0x4f*/ SDL_SCANCODE_KP_1, + /*0x50*/ SDL_SCANCODE_KP_2, + /*0x51*/ SDL_SCANCODE_KP_3, + /*0x52*/ SDL_SCANCODE_KP_0, + /*0x53*/ SDL_SCANCODE_KP_PERIOD, + /*0x54*/ SDL_SCANCODE_UNKNOWN, + /*0x55*/ SDL_SCANCODE_UNKNOWN, + /*0x56*/ SDL_SCANCODE_NONUSBACKSLASH, + /*0x57*/ SDL_SCANCODE_F11, + /*0x58*/ SDL_SCANCODE_F12, + /*0x59*/ SDL_SCANCODE_KP_EQUALS, + /*0x5a*/ SDL_SCANCODE_UNKNOWN, + /*0x5b*/ SDL_SCANCODE_UNKNOWN, + /*0x5c*/ SDL_SCANCODE_INTERNATIONAL6, + /*0x5d*/ SDL_SCANCODE_UNKNOWN, + /*0x5e*/ SDL_SCANCODE_UNKNOWN, + /*0x5f*/ SDL_SCANCODE_UNKNOWN, + /*0x60*/ SDL_SCANCODE_UNKNOWN, + /*0x61*/ SDL_SCANCODE_UNKNOWN, + /*0x62*/ SDL_SCANCODE_UNKNOWN, + /*0x63*/ SDL_SCANCODE_UNKNOWN, + /*0x64*/ SDL_SCANCODE_F13, + /*0x65*/ SDL_SCANCODE_F14, + /*0x66*/ SDL_SCANCODE_F15, + /*0x67*/ SDL_SCANCODE_F16, + /*0x68*/ SDL_SCANCODE_F17, + /*0x69*/ SDL_SCANCODE_F18, + /*0x6a*/ SDL_SCANCODE_F19, + /*0x6b*/ SDL_SCANCODE_F20, + /*0x6c*/ SDL_SCANCODE_F21, + /*0x6d*/ SDL_SCANCODE_F22, + /*0x6e*/ SDL_SCANCODE_F23, + /*0x6f*/ SDL_SCANCODE_UNKNOWN, + /*0x70*/ SDL_SCANCODE_INTERNATIONAL2, + /*0x71*/ SDL_SCANCODE_LANG2, + /*0x72*/ SDL_SCANCODE_LANG1, + /*0x73*/ SDL_SCANCODE_INTERNATIONAL1, + /*0x74*/ SDL_SCANCODE_UNKNOWN, + /*0x75*/ SDL_SCANCODE_UNKNOWN, + /*0x76*/ SDL_SCANCODE_F24, + /*0x77*/ SDL_SCANCODE_LANG4, + /*0x78*/ SDL_SCANCODE_LANG3, + /*0x79*/ SDL_SCANCODE_INTERNATIONAL4, + /*0x7a*/ SDL_SCANCODE_UNKNOWN, + /*0x7b*/ SDL_SCANCODE_INTERNATIONAL5, + /*0x7c*/ SDL_SCANCODE_UNKNOWN, + /*0x7d*/ SDL_SCANCODE_INTERNATIONAL3, + /*0x7e*/ SDL_SCANCODE_KP_COMMA, + /*0x7f*/ SDL_SCANCODE_UNKNOWN, + /*0xe000*/ SDL_SCANCODE_UNKNOWN, + /*0xe001*/ SDL_SCANCODE_UNKNOWN, + /*0xe002*/ SDL_SCANCODE_UNKNOWN, + /*0xe003*/ SDL_SCANCODE_UNKNOWN, + /*0xe004*/ SDL_SCANCODE_UNKNOWN, + /*0xe005*/ SDL_SCANCODE_UNKNOWN, + /*0xe006*/ SDL_SCANCODE_UNKNOWN, + /*0xe007*/ SDL_SCANCODE_UNKNOWN, + /*0xe008*/ SDL_SCANCODE_UNKNOWN, + /*0xe009*/ SDL_SCANCODE_UNKNOWN, + /*0xe00a*/ SDL_SCANCODE_PASTE, + /*0xe00b*/ SDL_SCANCODE_UNKNOWN, + /*0xe00c*/ SDL_SCANCODE_UNKNOWN, + /*0xe00d*/ SDL_SCANCODE_UNKNOWN, + /*0xe00e*/ SDL_SCANCODE_UNKNOWN, + /*0xe00f*/ SDL_SCANCODE_UNKNOWN, + /*0xe010*/ SDL_SCANCODE_MEDIA_PREVIOUS_TRACK, + /*0xe011*/ SDL_SCANCODE_UNKNOWN, + /*0xe012*/ SDL_SCANCODE_UNKNOWN, + /*0xe013*/ SDL_SCANCODE_UNKNOWN, + /*0xe014*/ SDL_SCANCODE_UNKNOWN, + /*0xe015*/ SDL_SCANCODE_UNKNOWN, + /*0xe016*/ SDL_SCANCODE_UNKNOWN, + /*0xe017*/ SDL_SCANCODE_CUT, + /*0xe018*/ SDL_SCANCODE_COPY, + /*0xe019*/ SDL_SCANCODE_MEDIA_NEXT_TRACK, + /*0xe01a*/ SDL_SCANCODE_UNKNOWN, + /*0xe01b*/ SDL_SCANCODE_UNKNOWN, + /*0xe01c*/ SDL_SCANCODE_KP_ENTER, + /*0xe01d*/ SDL_SCANCODE_RCTRL, + /*0xe01e*/ SDL_SCANCODE_UNKNOWN, + /*0xe01f*/ SDL_SCANCODE_UNKNOWN, + /*0xe020*/ SDL_SCANCODE_MUTE, + /*0xe021*/ SDL_SCANCODE_UNKNOWN, // LaunchApp2 + /*0xe022*/ SDL_SCANCODE_MEDIA_PLAY_PAUSE, + /*0xe023*/ SDL_SCANCODE_UNKNOWN, + /*0xe024*/ SDL_SCANCODE_MEDIA_STOP, + /*0xe025*/ SDL_SCANCODE_UNKNOWN, + /*0xe026*/ SDL_SCANCODE_UNKNOWN, + /*0xe027*/ SDL_SCANCODE_UNKNOWN, + /*0xe028*/ SDL_SCANCODE_UNKNOWN, + /*0xe029*/ SDL_SCANCODE_UNKNOWN, + /*0xe02a*/ SDL_SCANCODE_UNKNOWN, + /*0xe02b*/ SDL_SCANCODE_UNKNOWN, + /*0xe02c*/ SDL_SCANCODE_MEDIA_EJECT, + /*0xe02d*/ SDL_SCANCODE_UNKNOWN, + /*0xe02e*/ SDL_SCANCODE_VOLUMEDOWN, + /*0xe02f*/ SDL_SCANCODE_UNKNOWN, + /*0xe030*/ SDL_SCANCODE_VOLUMEUP, + /*0xe031*/ SDL_SCANCODE_UNKNOWN, + /*0xe032*/ SDL_SCANCODE_AC_HOME, + /*0xe033*/ SDL_SCANCODE_UNKNOWN, + /*0xe034*/ SDL_SCANCODE_UNKNOWN, + /*0xe035*/ SDL_SCANCODE_KP_DIVIDE, + /*0xe036*/ SDL_SCANCODE_UNKNOWN, + /*0xe037*/ SDL_SCANCODE_PRINTSCREEN, + /*0xe038*/ SDL_SCANCODE_RALT, + /*0xe039*/ SDL_SCANCODE_UNKNOWN, + /*0xe03a*/ SDL_SCANCODE_UNKNOWN, + /*0xe03b*/ SDL_SCANCODE_HELP, + /*0xe03c*/ SDL_SCANCODE_UNKNOWN, + /*0xe03d*/ SDL_SCANCODE_UNKNOWN, + /*0xe03e*/ SDL_SCANCODE_UNKNOWN, + /*0xe03f*/ SDL_SCANCODE_UNKNOWN, + /*0xe040*/ SDL_SCANCODE_UNKNOWN, + /*0xe041*/ SDL_SCANCODE_UNKNOWN, + /*0xe042*/ SDL_SCANCODE_UNKNOWN, + /*0xe043*/ SDL_SCANCODE_UNKNOWN, + /*0xe044*/ SDL_SCANCODE_UNKNOWN, + /*0xe045*/ SDL_SCANCODE_NUMLOCKCLEAR, + /*0xe046*/ SDL_SCANCODE_PAUSE, + /*0xe047*/ SDL_SCANCODE_HOME, + /*0xe048*/ SDL_SCANCODE_UP, + /*0xe049*/ SDL_SCANCODE_PAGEUP, + /*0xe04a*/ SDL_SCANCODE_UNKNOWN, + /*0xe04b*/ SDL_SCANCODE_LEFT, + /*0xe04c*/ SDL_SCANCODE_UNKNOWN, + /*0xe04d*/ SDL_SCANCODE_RIGHT, + /*0xe04e*/ SDL_SCANCODE_UNKNOWN, + /*0xe04f*/ SDL_SCANCODE_END, + /*0xe050*/ SDL_SCANCODE_DOWN, + /*0xe051*/ SDL_SCANCODE_PAGEDOWN, + /*0xe052*/ SDL_SCANCODE_INSERT, + /*0xe053*/ SDL_SCANCODE_DELETE, + /*0xe054*/ SDL_SCANCODE_UNKNOWN, + /*0xe055*/ SDL_SCANCODE_UNKNOWN, + /*0xe056*/ SDL_SCANCODE_UNKNOWN, + /*0xe057*/ SDL_SCANCODE_UNKNOWN, + /*0xe058*/ SDL_SCANCODE_UNKNOWN, + /*0xe059*/ SDL_SCANCODE_UNKNOWN, + /*0xe05a*/ SDL_SCANCODE_UNKNOWN, + /*0xe05b*/ SDL_SCANCODE_LGUI, + /*0xe05c*/ SDL_SCANCODE_RGUI, + /*0xe05d*/ SDL_SCANCODE_APPLICATION, + /*0xe05e*/ SDL_SCANCODE_POWER, + /*0xe05f*/ SDL_SCANCODE_SLEEP, + /*0xe060*/ SDL_SCANCODE_UNKNOWN, + /*0xe061*/ SDL_SCANCODE_UNKNOWN, + /*0xe062*/ SDL_SCANCODE_UNKNOWN, + /*0xe063*/ SDL_SCANCODE_UNKNOWN, + /*0xe064*/ SDL_SCANCODE_UNKNOWN, + /*0xe065*/ SDL_SCANCODE_AC_SEARCH, + /*0xe066*/ SDL_SCANCODE_AC_BOOKMARKS, + /*0xe067*/ SDL_SCANCODE_AC_REFRESH, + /*0xe068*/ SDL_SCANCODE_AC_STOP, + /*0xe069*/ SDL_SCANCODE_AC_FORWARD, + /*0xe06a*/ SDL_SCANCODE_AC_BACK, + /*0xe06b*/ SDL_SCANCODE_UNKNOWN, // LaunchApp1 + /*0xe06c*/ SDL_SCANCODE_UNKNOWN, // LaunchMail + /*0xe06d*/ SDL_SCANCODE_MEDIA_SELECT, + /*0xe06e*/ SDL_SCANCODE_UNKNOWN, + /*0xe06f*/ SDL_SCANCODE_UNKNOWN, + /*0xe070*/ SDL_SCANCODE_UNKNOWN, + /*0xe071*/ SDL_SCANCODE_UNKNOWN, + /*0xe072*/ SDL_SCANCODE_UNKNOWN, + /*0xe073*/ SDL_SCANCODE_UNKNOWN, + /*0xe074*/ SDL_SCANCODE_UNKNOWN, + /*0xe075*/ SDL_SCANCODE_UNKNOWN, + /*0xe076*/ SDL_SCANCODE_UNKNOWN, + /*0xe077*/ SDL_SCANCODE_UNKNOWN, + /*0xe078*/ SDL_SCANCODE_UNKNOWN, + /*0xe079*/ SDL_SCANCODE_UNKNOWN, + /*0xe07a*/ SDL_SCANCODE_UNKNOWN, + /*0xe07b*/ SDL_SCANCODE_UNKNOWN, + /*0xe07c*/ SDL_SCANCODE_UNKNOWN, + /*0xe07d*/ SDL_SCANCODE_UNKNOWN, + /*0xe07e*/ SDL_SCANCODE_UNKNOWN, + /*0xe07f*/ SDL_SCANCODE_UNKNOWN +}; +/* *INDENT-ON* */ // clang-format on diff --git a/contrib/SDL-3.2.8/src/events/scancodes_xfree86.h b/contrib/SDL-3.2.8/src/events/scancodes_xfree86.h new file mode 100644 index 0000000..5e51bb1 --- /dev/null +++ b/contrib/SDL-3.2.8/src/events/scancodes_xfree86.h @@ -0,0 +1,520 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef scancodes_xfree86_h_ +#define scancodes_xfree86_h_ + +/* XFree86 key code to SDL scancode mapping table + Sources: + - atKeyNames.h from XFree86 source code +*/ +/* *INDENT-OFF* */ // clang-format off +static const SDL_Scancode xfree86_scancode_table[] = { + /* 0 */ SDL_SCANCODE_UNKNOWN, + /* 1 */ SDL_SCANCODE_ESCAPE, + /* 2 */ SDL_SCANCODE_1, + /* 3 */ SDL_SCANCODE_2, + /* 4 */ SDL_SCANCODE_3, + /* 5 */ SDL_SCANCODE_4, + /* 6 */ SDL_SCANCODE_5, + /* 7 */ SDL_SCANCODE_6, + /* 8 */ SDL_SCANCODE_7, + /* 9 */ SDL_SCANCODE_8, + /* 10 */ SDL_SCANCODE_9, + /* 11 */ SDL_SCANCODE_0, + /* 12 */ SDL_SCANCODE_MINUS, + /* 13 */ SDL_SCANCODE_EQUALS, + /* 14 */ SDL_SCANCODE_BACKSPACE, + /* 15 */ SDL_SCANCODE_TAB, + /* 16 */ SDL_SCANCODE_Q, + /* 17 */ SDL_SCANCODE_W, + /* 18 */ SDL_SCANCODE_E, + /* 19 */ SDL_SCANCODE_R, + /* 20 */ SDL_SCANCODE_T, + /* 21 */ SDL_SCANCODE_Y, + /* 22 */ SDL_SCANCODE_U, + /* 23 */ SDL_SCANCODE_I, + /* 24 */ SDL_SCANCODE_O, + /* 25 */ SDL_SCANCODE_P, + /* 26 */ SDL_SCANCODE_LEFTBRACKET, + /* 27 */ SDL_SCANCODE_RIGHTBRACKET, + /* 28 */ SDL_SCANCODE_RETURN, + /* 29 */ SDL_SCANCODE_LCTRL, + /* 30 */ SDL_SCANCODE_A, + /* 31 */ SDL_SCANCODE_S, + /* 32 */ SDL_SCANCODE_D, + /* 33 */ SDL_SCANCODE_F, + /* 34 */ SDL_SCANCODE_G, + /* 35 */ SDL_SCANCODE_H, + /* 36 */ SDL_SCANCODE_J, + /* 37 */ SDL_SCANCODE_K, + /* 38 */ SDL_SCANCODE_L, + /* 39 */ SDL_SCANCODE_SEMICOLON, + /* 40 */ SDL_SCANCODE_APOSTROPHE, + /* 41 */ SDL_SCANCODE_GRAVE, + /* 42 */ SDL_SCANCODE_LSHIFT, + /* 43 */ SDL_SCANCODE_BACKSLASH, + /* 44 */ SDL_SCANCODE_Z, + /* 45 */ SDL_SCANCODE_X, + /* 46 */ SDL_SCANCODE_C, + /* 47 */ SDL_SCANCODE_V, + /* 48 */ SDL_SCANCODE_B, + /* 49 */ SDL_SCANCODE_N, + /* 50 */ SDL_SCANCODE_M, + /* 51 */ SDL_SCANCODE_COMMA, + /* 52 */ SDL_SCANCODE_PERIOD, + /* 53 */ SDL_SCANCODE_SLASH, + /* 54 */ SDL_SCANCODE_RSHIFT, + /* 55 */ SDL_SCANCODE_KP_MULTIPLY, + /* 56 */ SDL_SCANCODE_LALT, + /* 57 */ SDL_SCANCODE_SPACE, + /* 58 */ SDL_SCANCODE_CAPSLOCK, + /* 59 */ SDL_SCANCODE_F1, + /* 60 */ SDL_SCANCODE_F2, + /* 61 */ SDL_SCANCODE_F3, + /* 62 */ SDL_SCANCODE_F4, + /* 63 */ SDL_SCANCODE_F5, + /* 64 */ SDL_SCANCODE_F6, + /* 65 */ SDL_SCANCODE_F7, + /* 66 */ SDL_SCANCODE_F8, + /* 67 */ SDL_SCANCODE_F9, + /* 68 */ SDL_SCANCODE_F10, + /* 69 */ SDL_SCANCODE_NUMLOCKCLEAR, + /* 70 */ SDL_SCANCODE_SCROLLLOCK, + /* 71 */ SDL_SCANCODE_KP_7, + /* 72 */ SDL_SCANCODE_KP_8, + /* 73 */ SDL_SCANCODE_KP_9, + /* 74 */ SDL_SCANCODE_KP_MINUS, + /* 75 */ SDL_SCANCODE_KP_4, + /* 76 */ SDL_SCANCODE_KP_5, + /* 77 */ SDL_SCANCODE_KP_6, + /* 78 */ SDL_SCANCODE_KP_PLUS, + /* 79 */ SDL_SCANCODE_KP_1, + /* 80 */ SDL_SCANCODE_KP_2, + /* 81 */ SDL_SCANCODE_KP_3, + /* 82 */ SDL_SCANCODE_KP_0, + /* 83 */ SDL_SCANCODE_KP_PERIOD, + /* 84 */ SDL_SCANCODE_SYSREQ, + /* 85 */ SDL_SCANCODE_MODE, + /* 86 */ SDL_SCANCODE_NONUSBACKSLASH, + /* 87 */ SDL_SCANCODE_F11, + /* 88 */ SDL_SCANCODE_F12, + /* 89 */ SDL_SCANCODE_HOME, + /* 90 */ SDL_SCANCODE_UP, + /* 91 */ SDL_SCANCODE_PAGEUP, + /* 92 */ SDL_SCANCODE_LEFT, + /* 93 */ SDL_SCANCODE_UNKNOWN, // on PowerBook G4 / KEY_Begin + /* 94 */ SDL_SCANCODE_RIGHT, + /* 95 */ SDL_SCANCODE_END, + /* 96 */ SDL_SCANCODE_DOWN, + /* 97 */ SDL_SCANCODE_PAGEDOWN, + /* 98 */ SDL_SCANCODE_INSERT, + /* 99 */ SDL_SCANCODE_DELETE, + /* 100 */ SDL_SCANCODE_KP_ENTER, + /* 101 */ SDL_SCANCODE_RCTRL, + /* 102 */ SDL_SCANCODE_PAUSE, + /* 103 */ SDL_SCANCODE_PRINTSCREEN, + /* 104 */ SDL_SCANCODE_KP_DIVIDE, + /* 105 */ SDL_SCANCODE_RALT, + /* 106 */ SDL_SCANCODE_UNKNOWN, // BREAK + /* 107 */ SDL_SCANCODE_LGUI, + /* 108 */ SDL_SCANCODE_RGUI, + /* 109 */ SDL_SCANCODE_APPLICATION, + /* 110 */ SDL_SCANCODE_F13, + /* 111 */ SDL_SCANCODE_F14, + /* 112 */ SDL_SCANCODE_F15, + /* 113 */ SDL_SCANCODE_F16, + /* 114 */ SDL_SCANCODE_F17, + /* 115 */ SDL_SCANCODE_INTERNATIONAL1, // \_ + /* 116 */ SDL_SCANCODE_UNKNOWN, /* is translated to XK_ISO_Level3_Shift by my X server, but I have no keyboard that generates this code, so I don't know what the correct SDL_SCANCODE_* for it is */ + /* 117 */ SDL_SCANCODE_UNKNOWN, + /* 118 */ SDL_SCANCODE_KP_EQUALS, + /* 119 */ SDL_SCANCODE_UNKNOWN, + /* 120 */ SDL_SCANCODE_UNKNOWN, + /* 121 */ SDL_SCANCODE_INTERNATIONAL4, // Henkan_Mode + /* 122 */ SDL_SCANCODE_UNKNOWN, + /* 123 */ SDL_SCANCODE_INTERNATIONAL5, // Muhenkan + /* 124 */ SDL_SCANCODE_UNKNOWN, + /* 125 */ SDL_SCANCODE_INTERNATIONAL3, // Yen + /* 126 */ SDL_SCANCODE_UNKNOWN, + /* 127 */ SDL_SCANCODE_UNKNOWN, + /* 128 */ SDL_SCANCODE_UNKNOWN, + /* 129 */ SDL_SCANCODE_UNKNOWN, + /* 130 */ SDL_SCANCODE_UNKNOWN, + /* 131 */ SDL_SCANCODE_UNKNOWN, + /* 132 */ SDL_SCANCODE_POWER, + /* 133 */ SDL_SCANCODE_MUTE, + /* 134 */ SDL_SCANCODE_VOLUMEDOWN, + /* 135 */ SDL_SCANCODE_VOLUMEUP, + /* 136 */ SDL_SCANCODE_HELP, + /* 137 */ SDL_SCANCODE_STOP, + /* 138 */ SDL_SCANCODE_AGAIN, + /* 139 */ SDL_SCANCODE_UNKNOWN, // PROPS + /* 140 */ SDL_SCANCODE_UNDO, + /* 141 */ SDL_SCANCODE_UNKNOWN, // FRONT + /* 142 */ SDL_SCANCODE_COPY, + /* 143 */ SDL_SCANCODE_UNKNOWN, // OPEN + /* 144 */ SDL_SCANCODE_PASTE, + /* 145 */ SDL_SCANCODE_FIND, + /* 146 */ SDL_SCANCODE_CUT, +}; + +// This is largely identical to the Linux keycode mapping +static const SDL_Scancode xfree86_scancode_table2[] = { + /* 0, 0x000 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 1, 0x001 */ SDL_SCANCODE_ESCAPE, // Escape + /* 2, 0x002 */ SDL_SCANCODE_1, // 1 + /* 3, 0x003 */ SDL_SCANCODE_2, // 2 + /* 4, 0x004 */ SDL_SCANCODE_3, // 3 + /* 5, 0x005 */ SDL_SCANCODE_4, // 4 + /* 6, 0x006 */ SDL_SCANCODE_5, // 5 + /* 7, 0x007 */ SDL_SCANCODE_6, // 6 + /* 8, 0x008 */ SDL_SCANCODE_7, // 7 + /* 9, 0x009 */ SDL_SCANCODE_8, // 8 + /* 10, 0x00a */ SDL_SCANCODE_9, // 9 + /* 11, 0x00b */ SDL_SCANCODE_0, // 0 + /* 12, 0x00c */ SDL_SCANCODE_MINUS, // minus + /* 13, 0x00d */ SDL_SCANCODE_EQUALS, // equal + /* 14, 0x00e */ SDL_SCANCODE_BACKSPACE, // BackSpace + /* 15, 0x00f */ SDL_SCANCODE_TAB, // Tab + /* 16, 0x010 */ SDL_SCANCODE_Q, // q + /* 17, 0x011 */ SDL_SCANCODE_W, // w + /* 18, 0x012 */ SDL_SCANCODE_E, // e + /* 19, 0x013 */ SDL_SCANCODE_R, // r + /* 20, 0x014 */ SDL_SCANCODE_T, // t + /* 21, 0x015 */ SDL_SCANCODE_Y, // y + /* 22, 0x016 */ SDL_SCANCODE_U, // u + /* 23, 0x017 */ SDL_SCANCODE_I, // i + /* 24, 0x018 */ SDL_SCANCODE_O, // o + /* 25, 0x019 */ SDL_SCANCODE_P, // p + /* 26, 0x01a */ SDL_SCANCODE_LEFTBRACKET, // bracketleft + /* 27, 0x01b */ SDL_SCANCODE_RIGHTBRACKET, // bracketright + /* 28, 0x01c */ SDL_SCANCODE_RETURN, // Return + /* 29, 0x01d */ SDL_SCANCODE_LCTRL, // Control_L + /* 30, 0x01e */ SDL_SCANCODE_A, // a + /* 31, 0x01f */ SDL_SCANCODE_S, // s + /* 32, 0x020 */ SDL_SCANCODE_D, // d + /* 33, 0x021 */ SDL_SCANCODE_F, // f + /* 34, 0x022 */ SDL_SCANCODE_G, // g + /* 35, 0x023 */ SDL_SCANCODE_H, // h + /* 36, 0x024 */ SDL_SCANCODE_J, // j + /* 37, 0x025 */ SDL_SCANCODE_K, // k + /* 38, 0x026 */ SDL_SCANCODE_L, // l + /* 39, 0x027 */ SDL_SCANCODE_SEMICOLON, // semicolon + /* 40, 0x028 */ SDL_SCANCODE_APOSTROPHE, // apostrophe + /* 41, 0x029 */ SDL_SCANCODE_GRAVE, // grave + /* 42, 0x02a */ SDL_SCANCODE_LSHIFT, // Shift_L + /* 43, 0x02b */ SDL_SCANCODE_BACKSLASH, // backslash + /* 44, 0x02c */ SDL_SCANCODE_Z, // z + /* 45, 0x02d */ SDL_SCANCODE_X, // x + /* 46, 0x02e */ SDL_SCANCODE_C, // c + /* 47, 0x02f */ SDL_SCANCODE_V, // v + /* 48, 0x030 */ SDL_SCANCODE_B, // b + /* 49, 0x031 */ SDL_SCANCODE_N, // n + /* 50, 0x032 */ SDL_SCANCODE_M, // m + /* 51, 0x033 */ SDL_SCANCODE_COMMA, // comma + /* 52, 0x034 */ SDL_SCANCODE_PERIOD, // period + /* 53, 0x035 */ SDL_SCANCODE_SLASH, // slash + /* 54, 0x036 */ SDL_SCANCODE_RSHIFT, // Shift_R + /* 55, 0x037 */ SDL_SCANCODE_KP_MULTIPLY, // KP_Multiply + /* 56, 0x038 */ SDL_SCANCODE_LALT, // Alt_L + /* 57, 0x039 */ SDL_SCANCODE_SPACE, // space + /* 58, 0x03a */ SDL_SCANCODE_CAPSLOCK, // Caps_Lock + /* 59, 0x03b */ SDL_SCANCODE_F1, // F1 + /* 60, 0x03c */ SDL_SCANCODE_F2, // F2 + /* 61, 0x03d */ SDL_SCANCODE_F3, // F3 + /* 62, 0x03e */ SDL_SCANCODE_F4, // F4 + /* 63, 0x03f */ SDL_SCANCODE_F5, // F5 + /* 64, 0x040 */ SDL_SCANCODE_F6, // F6 + /* 65, 0x041 */ SDL_SCANCODE_F7, // F7 + /* 66, 0x042 */ SDL_SCANCODE_F8, // F8 + /* 67, 0x043 */ SDL_SCANCODE_F9, // F9 + /* 68, 0x044 */ SDL_SCANCODE_F10, // F10 + /* 69, 0x045 */ SDL_SCANCODE_NUMLOCKCLEAR, // Num_Lock + /* 70, 0x046 */ SDL_SCANCODE_SCROLLLOCK, // Scroll_Lock + /* 71, 0x047 */ SDL_SCANCODE_KP_7, // KP_Home + /* 72, 0x048 */ SDL_SCANCODE_KP_8, // KP_Up + /* 73, 0x049 */ SDL_SCANCODE_KP_9, // KP_Prior + /* 74, 0x04a */ SDL_SCANCODE_KP_MINUS, // KP_Subtract + /* 75, 0x04b */ SDL_SCANCODE_KP_4, // KP_Left + /* 76, 0x04c */ SDL_SCANCODE_KP_5, // KP_Begin + /* 77, 0x04d */ SDL_SCANCODE_KP_6, // KP_Right + /* 78, 0x04e */ SDL_SCANCODE_KP_PLUS, // KP_Add + /* 79, 0x04f */ SDL_SCANCODE_KP_1, // KP_End + /* 80, 0x050 */ SDL_SCANCODE_KP_2, // KP_Down + /* 81, 0x051 */ SDL_SCANCODE_KP_3, // KP_Next + /* 82, 0x052 */ SDL_SCANCODE_KP_0, // KP_Insert + /* 83, 0x053 */ SDL_SCANCODE_KP_PERIOD, // KP_Delete + /* 84, 0x054 */ SDL_SCANCODE_RALT, // ISO_Level3_Shift + /* 85, 0x055 */ SDL_SCANCODE_MODE, // ???? + /* 86, 0x056 */ SDL_SCANCODE_NONUSBACKSLASH, // less + /* 87, 0x057 */ SDL_SCANCODE_F11, // F11 + /* 88, 0x058 */ SDL_SCANCODE_F12, // F12 + /* 89, 0x059 */ SDL_SCANCODE_INTERNATIONAL1, // \_ + /* 90, 0x05a */ SDL_SCANCODE_LANG3, // Katakana + /* 91, 0x05b */ SDL_SCANCODE_LANG4, // Hiragana + /* 92, 0x05c */ SDL_SCANCODE_INTERNATIONAL4, // Henkan_Mode + /* 93, 0x05d */ SDL_SCANCODE_INTERNATIONAL2, // Hiragana_Katakana + /* 94, 0x05e */ SDL_SCANCODE_INTERNATIONAL5, // Muhenkan + /* 95, 0x05f */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 96, 0x060 */ SDL_SCANCODE_KP_ENTER, // KP_Enter + /* 97, 0x061 */ SDL_SCANCODE_RCTRL, // Control_R + /* 98, 0x062 */ SDL_SCANCODE_KP_DIVIDE, // KP_Divide + /* 99, 0x063 */ SDL_SCANCODE_PRINTSCREEN, // Print + /* 100, 0x064 */ SDL_SCANCODE_RALT, // ISO_Level3_Shift, ALTGR, RALT + /* 101, 0x065 */ SDL_SCANCODE_UNKNOWN, // Linefeed + /* 102, 0x066 */ SDL_SCANCODE_HOME, // Home + /* 103, 0x067 */ SDL_SCANCODE_UP, // Up + /* 104, 0x068 */ SDL_SCANCODE_PAGEUP, // Prior + /* 105, 0x069 */ SDL_SCANCODE_LEFT, // Left + /* 106, 0x06a */ SDL_SCANCODE_RIGHT, // Right + /* 107, 0x06b */ SDL_SCANCODE_END, // End + /* 108, 0x06c */ SDL_SCANCODE_DOWN, // Down + /* 109, 0x06d */ SDL_SCANCODE_PAGEDOWN, // Next + /* 110, 0x06e */ SDL_SCANCODE_INSERT, // Insert + /* 111, 0x06f */ SDL_SCANCODE_DELETE, // Delete + /* 112, 0x070 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 113, 0x071 */ SDL_SCANCODE_MUTE, // XF86AudioMute + /* 114, 0x072 */ SDL_SCANCODE_VOLUMEDOWN, // XF86AudioLowerVolume + /* 115, 0x073 */ SDL_SCANCODE_VOLUMEUP, // XF86AudioRaiseVolume + /* 116, 0x074 */ SDL_SCANCODE_POWER, // XF86PowerOff + /* 117, 0x075 */ SDL_SCANCODE_KP_EQUALS, // KP_Equal + /* 118, 0x076 */ SDL_SCANCODE_KP_PLUSMINUS, // plusminus + /* 119, 0x077 */ SDL_SCANCODE_PAUSE, // Pause + /* 120, 0x078 */ SDL_SCANCODE_UNKNOWN, // XF86LaunchA + /* 121, 0x079 */ SDL_SCANCODE_KP_PERIOD, // KP_Decimal + /* 122, 0x07a */ SDL_SCANCODE_LANG1, // Hangul + /* 123, 0x07b */ SDL_SCANCODE_LANG2, // Hangul_Hanja + /* 124, 0x07c */ SDL_SCANCODE_INTERNATIONAL3, // Yen + /* 125, 0x07d */ SDL_SCANCODE_LGUI, // Super_L + /* 126, 0x07e */ SDL_SCANCODE_RGUI, // Super_R + /* 127, 0x07f */ SDL_SCANCODE_APPLICATION, // Menu + /* 128, 0x080 */ SDL_SCANCODE_CANCEL, // Cancel + /* 129, 0x081 */ SDL_SCANCODE_AGAIN, // Redo + /* 130, 0x082 */ SDL_SCANCODE_UNKNOWN, // SunProps + /* 131, 0x083 */ SDL_SCANCODE_UNDO, // Undo + /* 132, 0x084 */ SDL_SCANCODE_UNKNOWN, // SunFront + /* 133, 0x085 */ SDL_SCANCODE_COPY, // XF86Copy + /* 134, 0x086 */ SDL_SCANCODE_UNKNOWN, // SunOpen, XF86Open + /* 135, 0x087 */ SDL_SCANCODE_PASTE, // XF86Paste + /* 136, 0x088 */ SDL_SCANCODE_FIND, // Find + /* 137, 0x089 */ SDL_SCANCODE_CUT, // XF86Cut + /* 138, 0x08a */ SDL_SCANCODE_HELP, // Help + /* 139, 0x08b */ SDL_SCANCODE_MENU, // XF86MenuKB + /* 140, 0x08c */ SDL_SCANCODE_UNKNOWN, // XF86Calculator + /* 141, 0x08d */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 142, 0x08e */ SDL_SCANCODE_SLEEP, // XF86Sleep + /* 143, 0x08f */ SDL_SCANCODE_UNKNOWN, // XF86WakeUp + /* 144, 0x090 */ SDL_SCANCODE_UNKNOWN, // XF86Explorer + /* 145, 0x091 */ SDL_SCANCODE_UNKNOWN, // XF86Send + /* 146, 0x092 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 147, 0x093 */ SDL_SCANCODE_UNKNOWN, // XF86Xfer + /* 148, 0x094 */ SDL_SCANCODE_UNKNOWN, // XF86Launch1 + /* 149, 0x095 */ SDL_SCANCODE_UNKNOWN, // XF86Launch2 + /* 150, 0x096 */ SDL_SCANCODE_UNKNOWN, // XF86WWW + /* 151, 0x097 */ SDL_SCANCODE_UNKNOWN, // XF86DOS + /* 152, 0x098 */ SDL_SCANCODE_UNKNOWN, // XF86ScreenSaver + /* 153, 0x099 */ SDL_SCANCODE_UNKNOWN, // XF86RotateWindows + /* 154, 0x09a */ SDL_SCANCODE_UNKNOWN, // XF86TaskPane + /* 155, 0x09b */ SDL_SCANCODE_UNKNOWN, // XF86Mail + /* 156, 0x09c */ SDL_SCANCODE_AC_BOOKMARKS, // XF86Favorites + /* 157, 0x09d */ SDL_SCANCODE_UNKNOWN, // XF86MyComputer + /* 158, 0x09e */ SDL_SCANCODE_AC_BACK, // XF86Back + /* 159, 0x09f */ SDL_SCANCODE_AC_FORWARD, // XF86Forward + /* 160, 0x0a0 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 161, 0x0a1 */ SDL_SCANCODE_MEDIA_EJECT, // XF86Eject + /* 162, 0x0a2 */ SDL_SCANCODE_MEDIA_EJECT, // XF86Eject + /* 163, 0x0a3 */ SDL_SCANCODE_MEDIA_NEXT_TRACK, // XF86AudioNext + /* 164, 0x0a4 */ SDL_SCANCODE_MEDIA_PLAY_PAUSE, // XF86AudioPlay + /* 165, 0x0a5 */ SDL_SCANCODE_MEDIA_PREVIOUS_TRACK, // XF86AudioPrev + /* 166, 0x0a6 */ SDL_SCANCODE_MEDIA_STOP, // XF86AudioStop + /* 167, 0x0a7 */ SDL_SCANCODE_MEDIA_RECORD, // XF86AudioRecord + /* 168, 0x0a8 */ SDL_SCANCODE_MEDIA_REWIND, // XF86AudioRewind + /* 169, 0x0a9 */ SDL_SCANCODE_UNKNOWN, // XF86Phone + /* 170, 0x0aa */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 171, 0x0ab */ SDL_SCANCODE_F13, // XF86Tools + /* 172, 0x0ac */ SDL_SCANCODE_AC_HOME, // XF86HomePage + /* 173, 0x0ad */ SDL_SCANCODE_AC_REFRESH, // XF86Reload + /* 174, 0x0ae */ SDL_SCANCODE_UNKNOWN, // XF86Close + /* 175, 0x0af */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 176, 0x0b0 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 177, 0x0b1 */ SDL_SCANCODE_UNKNOWN, // XF86ScrollUp + /* 178, 0x0b2 */ SDL_SCANCODE_UNKNOWN, // XF86ScrollDown + /* 179, 0x0b3 */ SDL_SCANCODE_KP_LEFTPAREN, // parenleft + /* 180, 0x0b4 */ SDL_SCANCODE_KP_RIGHTPAREN, // parenright + /* 181, 0x0b5 */ SDL_SCANCODE_AC_NEW, // XF86New + /* 182, 0x0b6 */ SDL_SCANCODE_AGAIN, // Redo + /* 183, 0x0b7 */ SDL_SCANCODE_F13, // XF86Tools + /* 184, 0x0b8 */ SDL_SCANCODE_F14, // XF86Launch5 + /* 185, 0x0b9 */ SDL_SCANCODE_F15, // XF86Launch6 + /* 186, 0x0ba */ SDL_SCANCODE_F16, // XF86Launch7 + /* 187, 0x0bb */ SDL_SCANCODE_F17, // XF86Launch8 + /* 188, 0x0bc */ SDL_SCANCODE_F18, // XF86Launch9 + /* 189, 0x0bd */ SDL_SCANCODE_F19, // NoSymbol + /* 190, 0x0be */ SDL_SCANCODE_F20, // XF86AudioMicMute + /* 191, 0x0bf */ SDL_SCANCODE_UNKNOWN, // XF86TouchpadToggle + /* 192, 0x0c0 */ SDL_SCANCODE_UNKNOWN, // XF86TouchpadOn + /* 193, 0x0c1 */ SDL_SCANCODE_UNKNOWN, // XF86TouchpadOff + /* 194, 0x0c2 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 195, 0x0c3 */ SDL_SCANCODE_MODE, // Mode_switch + /* 196, 0x0c4 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 197, 0x0c5 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 198, 0x0c6 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 199, 0x0c7 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 200, 0x0c8 */ SDL_SCANCODE_MEDIA_PLAY, // XF86AudioPlay + /* 201, 0x0c9 */ SDL_SCANCODE_MEDIA_PAUSE, // XF86AudioPause + /* 202, 0x0ca */ SDL_SCANCODE_UNKNOWN, // XF86Launch3 + /* 203, 0x0cb */ SDL_SCANCODE_UNKNOWN, // XF86Launch4 + /* 204, 0x0cc */ SDL_SCANCODE_UNKNOWN, // XF86LaunchB + /* 205, 0x0cd */ SDL_SCANCODE_UNKNOWN, // XF86Suspend + /* 206, 0x0ce */ SDL_SCANCODE_AC_CLOSE, // XF86Close + /* 207, 0x0cf */ SDL_SCANCODE_MEDIA_PLAY, // XF86AudioPlay + /* 208, 0x0d0 */ SDL_SCANCODE_MEDIA_FAST_FORWARD, // XF86AudioForward + /* 209, 0x0d1 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 210, 0x0d2 */ SDL_SCANCODE_PRINTSCREEN, // Print + /* 211, 0x0d3 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 212, 0x0d4 */ SDL_SCANCODE_UNKNOWN, // XF86WebCam + /* 213, 0x0d5 */ SDL_SCANCODE_UNKNOWN, // XF86AudioPreset + /* 214, 0x0d6 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 215, 0x0d7 */ SDL_SCANCODE_UNKNOWN, // XF86Mail + /* 216, 0x0d8 */ SDL_SCANCODE_UNKNOWN, // XF86Messenger + /* 217, 0x0d9 */ SDL_SCANCODE_AC_SEARCH, // XF86Search + /* 218, 0x0da */ SDL_SCANCODE_UNKNOWN, // XF86Go + /* 219, 0x0db */ SDL_SCANCODE_UNKNOWN, // XF86Finance + /* 220, 0x0dc */ SDL_SCANCODE_UNKNOWN, // XF86Game + /* 221, 0x0dd */ SDL_SCANCODE_UNKNOWN, // XF86Shop + /* 222, 0x0de */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 223, 0x0df */ SDL_SCANCODE_CANCEL, // Cancel + /* 224, 0x0e0 */ SDL_SCANCODE_UNKNOWN, // XF86MonBrightnessDown + /* 225, 0x0e1 */ SDL_SCANCODE_UNKNOWN, // XF86MonBrightnessUp + /* 226, 0x0e2 */ SDL_SCANCODE_MEDIA_SELECT, // XF86AudioMedia + /* 227, 0x0e3 */ SDL_SCANCODE_UNKNOWN, // XF86Display + /* 228, 0x0e4 */ SDL_SCANCODE_UNKNOWN, // XF86KbdLightOnOff + /* 229, 0x0e5 */ SDL_SCANCODE_UNKNOWN, // XF86KbdBrightnessDown + /* 230, 0x0e6 */ SDL_SCANCODE_UNKNOWN, // XF86KbdBrightnessUp + /* 231, 0x0e7 */ SDL_SCANCODE_UNKNOWN, // XF86Send + /* 232, 0x0e8 */ SDL_SCANCODE_UNKNOWN, // XF86Reply + /* 233, 0x0e9 */ SDL_SCANCODE_UNKNOWN, // XF86MailForward + /* 234, 0x0ea */ SDL_SCANCODE_UNKNOWN, // XF86Save + /* 235, 0x0eb */ SDL_SCANCODE_UNKNOWN, // XF86Documents + /* 236, 0x0ec */ SDL_SCANCODE_UNKNOWN, // XF86Battery + /* 237, 0x0ed */ SDL_SCANCODE_UNKNOWN, // XF86Bluetooth + /* 238, 0x0ee */ SDL_SCANCODE_UNKNOWN, // XF86WLAN + /* 239, 0x0ef */ SDL_SCANCODE_UNKNOWN, // XF86UWB + /* 240, 0x0f0 */ SDL_SCANCODE_UNKNOWN, // NoSymbol + /* 241, 0x0f1 */ SDL_SCANCODE_UNKNOWN, // XF86Next_VMode + /* 242, 0x0f2 */ SDL_SCANCODE_UNKNOWN, // XF86Prev_VMode + /* 243, 0x0f3 */ SDL_SCANCODE_UNKNOWN, // XF86MonBrightnessCycle + /* 244, 0x0f4 */ SDL_SCANCODE_UNKNOWN, // XF86BrightnessAuto + /* 245, 0x0f5 */ SDL_SCANCODE_UNKNOWN, // XF86DisplayOff + /* 246, 0x0f6 */ SDL_SCANCODE_UNKNOWN, // XF86WWAN + /* 247, 0x0f7 */ SDL_SCANCODE_UNKNOWN, // XF86RFKill +}; + +// Xvnc / Xtightvnc scancodes from xmodmap -pk +static const SDL_Scancode xvnc_scancode_table[] = { + /* 0 */ SDL_SCANCODE_LCTRL, + /* 1 */ SDL_SCANCODE_RCTRL, + /* 2 */ SDL_SCANCODE_LSHIFT, + /* 3 */ SDL_SCANCODE_RSHIFT, + /* 4 */ SDL_SCANCODE_UNKNOWN, // Meta_L + /* 5 */ SDL_SCANCODE_UNKNOWN, // Meta_R + /* 6 */ SDL_SCANCODE_LALT, + /* 7 */ SDL_SCANCODE_RALT, + /* 8 */ SDL_SCANCODE_SPACE, + /* 9 */ SDL_SCANCODE_0, + /* 10 */ SDL_SCANCODE_1, + /* 11 */ SDL_SCANCODE_2, + /* 12 */ SDL_SCANCODE_3, + /* 13 */ SDL_SCANCODE_4, + /* 14 */ SDL_SCANCODE_5, + /* 15 */ SDL_SCANCODE_6, + /* 16 */ SDL_SCANCODE_7, + /* 17 */ SDL_SCANCODE_8, + /* 18 */ SDL_SCANCODE_9, + /* 19 */ SDL_SCANCODE_MINUS, + /* 20 */ SDL_SCANCODE_EQUALS, + /* 21 */ SDL_SCANCODE_LEFTBRACKET, + /* 22 */ SDL_SCANCODE_RIGHTBRACKET, + /* 23 */ SDL_SCANCODE_SEMICOLON, + /* 24 */ SDL_SCANCODE_APOSTROPHE, + /* 25 */ SDL_SCANCODE_GRAVE, + /* 26 */ SDL_SCANCODE_COMMA, + /* 27 */ SDL_SCANCODE_PERIOD, + /* 28 */ SDL_SCANCODE_SLASH, + /* 29 */ SDL_SCANCODE_BACKSLASH, + /* 30 */ SDL_SCANCODE_A, + /* 31 */ SDL_SCANCODE_B, + /* 32 */ SDL_SCANCODE_C, + /* 33 */ SDL_SCANCODE_D, + /* 34 */ SDL_SCANCODE_E, + /* 35 */ SDL_SCANCODE_F, + /* 36 */ SDL_SCANCODE_G, + /* 37 */ SDL_SCANCODE_H, + /* 38 */ SDL_SCANCODE_I, + /* 39 */ SDL_SCANCODE_J, + /* 40 */ SDL_SCANCODE_K, + /* 41 */ SDL_SCANCODE_L, + /* 42 */ SDL_SCANCODE_M, + /* 43 */ SDL_SCANCODE_N, + /* 44 */ SDL_SCANCODE_O, + /* 45 */ SDL_SCANCODE_P, + /* 46 */ SDL_SCANCODE_Q, + /* 47 */ SDL_SCANCODE_R, + /* 48 */ SDL_SCANCODE_S, + /* 49 */ SDL_SCANCODE_T, + /* 50 */ SDL_SCANCODE_U, + /* 51 */ SDL_SCANCODE_V, + /* 52 */ SDL_SCANCODE_W, + /* 53 */ SDL_SCANCODE_X, + /* 54 */ SDL_SCANCODE_Y, + /* 55 */ SDL_SCANCODE_Z, + /* 56 */ SDL_SCANCODE_BACKSPACE, + /* 57 */ SDL_SCANCODE_RETURN, + /* 58 */ SDL_SCANCODE_TAB, + /* 59 */ SDL_SCANCODE_ESCAPE, + /* 60 */ SDL_SCANCODE_DELETE, + /* 61 */ SDL_SCANCODE_HOME, + /* 62 */ SDL_SCANCODE_END, + /* 63 */ SDL_SCANCODE_PAGEUP, + /* 64 */ SDL_SCANCODE_PAGEDOWN, + /* 65 */ SDL_SCANCODE_UP, + /* 66 */ SDL_SCANCODE_DOWN, + /* 67 */ SDL_SCANCODE_LEFT, + /* 68 */ SDL_SCANCODE_RIGHT, + /* 69 */ SDL_SCANCODE_F1, + /* 70 */ SDL_SCANCODE_F2, + /* 71 */ SDL_SCANCODE_F3, + /* 72 */ SDL_SCANCODE_F4, + /* 73 */ SDL_SCANCODE_F5, + /* 74 */ SDL_SCANCODE_F6, + /* 75 */ SDL_SCANCODE_F7, + /* 76 */ SDL_SCANCODE_F8, + /* 77 */ SDL_SCANCODE_F9, + /* 78 */ SDL_SCANCODE_F10, + /* 79 */ SDL_SCANCODE_F11, + /* 80 */ SDL_SCANCODE_F12, +}; + +#endif // scancodes_xfree86_h_ + +/* *INDENT-ON* */ // clang-format on -- cgit v1.2.3