From 2fe1a6a27960126041590d7bbf8080fb5228b1fb Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 20 Mar 2024 06:58:00 -0700 Subject: [PATCH] Initial support for hotplugging mice and keyboards --- include/SDL3/SDL_events.h | 33 +++- include/SDL3/SDL_gamepad.h | 12 ++ include/SDL3/SDL_joystick.h | 12 ++ include/SDL3/SDL_keyboard.h | 27 +++ include/SDL3/SDL_mouse.h | 25 +++ src/core/haiku/SDL_BApp.h | 2 +- src/core/linux/SDL_evdev.c | 4 +- src/core/openbsd/SDL_wscons_kbd.c | 12 +- src/core/windows/SDL_hid.c | 172 ++++++++++++++++++ src/core/windows/SDL_hid.h | 17 +- src/core/winrt/SDL_winrtapp_direct3d.cpp | 4 +- src/dynapi/SDL_dynapi.sym | 6 + src/dynapi/SDL_dynapi_overrides.h | 6 + src/dynapi/SDL_dynapi_procs.h | 6 + src/events/SDL_events.c | 18 ++ src/events/SDL_keyboard.c | 146 +++++++++++++-- src/events/SDL_keyboard_c.h | 15 +- src/events/SDL_mouse.c | 145 ++++++++++++++- src/events/SDL_mouse_c.h | 11 +- src/joystick/SDL_gamepad.c | 20 +++ src/joystick/SDL_joystick.c | 19 ++ src/joystick/android/SDL_sysjoystick.c | 4 +- src/joystick/windows/SDL_windowsjoystick.c | 185 +++----------------- src/test/SDL_test_common.c | 20 ++- src/video/android/SDL_androidkeyboard.c | 4 +- src/video/cocoa/SDL_cocoakeyboard.m | 10 +- src/video/cocoa/SDL_cocoawindow.m | 4 +- src/video/emscripten/SDL_emscriptenevents.c | 2 +- src/video/haiku/SDL_BApp.h | 2 +- src/video/ngage/SDL_ngageevents.cpp | 4 +- src/video/psp/SDL_pspevents.c | 4 +- src/video/qnx/SDL_qnxkeyboard.c | 4 +- src/video/riscos/SDL_riscosevents.c | 4 +- src/video/uikit/SDL_uikitevents.h | 2 - src/video/uikit/SDL_uikitevents.m | 46 ++--- src/video/uikit/SDL_uikitview.m | 16 +- src/video/vita/SDL_vitakeyboard.c | 56 +++--- src/video/wayland/SDL_waylandevents.c | 6 +- src/video/windows/SDL_windowsevents.c | 154 ++++++++++++++-- src/video/windows/SDL_windowsevents.h | 1 + src/video/windows/SDL_windowsvideo.c | 4 + src/video/winrt/SDL_winrtkeyboard.cpp | 2 +- src/video/x11/SDL_x11events.c | 12 +- test/testhotplug.c | 24 ++- 44 files changed, 961 insertions(+), 321 deletions(-) diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h index 4a615f61b..619197361 100644 --- a/include/SDL3/SDL_events.h +++ b/include/SDL3/SDL_events.h @@ -143,12 +143,16 @@ typedef enum SDL_EVENT_TEXT_INPUT, /**< Keyboard text input */ SDL_EVENT_KEYMAP_CHANGED, /**< Keymap changed due to a system event such as an input language or keyboard layout change. */ + SDL_EVENT_KEYBOARD_ADDED, /**< A new keyboard has been inserted into the system */ + SDL_EVENT_KEYBOARD_REMOVED, /**< A keyboard has been removed */ /* Mouse events */ SDL_EVENT_MOUSE_MOTION = 0x400, /**< Mouse moved */ SDL_EVENT_MOUSE_BUTTON_DOWN, /**< Mouse button pressed */ SDL_EVENT_MOUSE_BUTTON_UP, /**< Mouse button released */ SDL_EVENT_MOUSE_WHEEL, /**< Mouse wheel motion */ + SDL_EVENT_MOUSE_ADDED, /**< A new mouse has been inserted into the system */ + SDL_EVENT_MOUSE_REMOVED, /**< A mouse has been removed */ /* Joystick events */ SDL_EVENT_JOYSTICK_AXIS_MOTION = 0x600, /**< Joystick axis motion */ @@ -270,6 +274,17 @@ typedef struct SDL_WindowEvent Sint32 data2; /**< event dependent data */ } SDL_WindowEvent; +/** + * Keyboard device event structure (event.kdevice.*) + */ +typedef struct SDL_KeyboardDeviceEvent +{ + SDL_EventType type; /**< ::SDL_EVENT_KEYBOARD_ADDED or ::SDL_EVENT_KEYBOARD_REMOVED */ + Uint32 reserved; + Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ + SDL_KeyboardID which; /**< The keyboard instance id */ +} SDL_KeyboardDeviceEvent; + /** * Keyboard button event structure (event.key.*) */ @@ -279,6 +294,7 @@ typedef struct SDL_KeyboardEvent Uint32 reserved; Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ SDL_WindowID windowID; /**< The window with keyboard focus, if any */ + SDL_KeyboardID which; /**< The keyboard instance id, or 0 if unknown or virtual */ Uint8 state; /**< ::SDL_PRESSED or ::SDL_RELEASED */ Uint8 repeat; /**< Non-zero if this is a key repeat */ Uint8 padding2; @@ -320,6 +336,17 @@ typedef struct SDL_TextInputEvent char *text; /**< The input text */ } SDL_TextInputEvent; +/** + * Mouse device event structure (event.mdevice.*) + */ +typedef struct SDL_MouseDeviceEvent +{ + SDL_EventType type; /**< ::SDL_EVENT_MOUSE_ADDED or ::SDL_EVENT_MOUSE_REMOVED */ + Uint32 reserved; + Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ + SDL_MouseID which; /**< The mouse instance id */ +} SDL_MouseDeviceEvent; + /** * Mouse motion event structure (event.motion.*) */ @@ -718,21 +745,23 @@ typedef union SDL_Event SDL_CommonEvent common; /**< Common event data */ SDL_DisplayEvent display; /**< Display event data */ SDL_WindowEvent window; /**< Window event data */ + SDL_KeyboardDeviceEvent kdevice; /**< Keyboard device change event data */ SDL_KeyboardEvent key; /**< Keyboard event data */ SDL_TextEditingEvent edit; /**< Text editing event data */ SDL_TextInputEvent text; /**< Text input event data */ + SDL_MouseDeviceEvent mdevice; /**< Mouse device change event data */ SDL_MouseMotionEvent motion; /**< Mouse motion event data */ SDL_MouseButtonEvent button; /**< Mouse button event data */ SDL_MouseWheelEvent wheel; /**< Mouse wheel event data */ + SDL_JoyDeviceEvent jdevice; /**< Joystick device change event data */ SDL_JoyAxisEvent jaxis; /**< Joystick axis event data */ SDL_JoyBallEvent jball; /**< Joystick ball event data */ SDL_JoyHatEvent jhat; /**< Joystick hat event data */ SDL_JoyButtonEvent jbutton; /**< Joystick button event data */ - SDL_JoyDeviceEvent jdevice; /**< Joystick device change event data */ SDL_JoyBatteryEvent jbattery; /**< Joystick battery event data */ + SDL_GamepadDeviceEvent gdevice; /**< Gamepad device event data */ SDL_GamepadAxisEvent gaxis; /**< Gamepad axis event data */ SDL_GamepadButtonEvent gbutton; /**< Gamepad button event data */ - SDL_GamepadDeviceEvent gdevice; /**< Gamepad device event data */ SDL_GamepadTouchpadEvent gtouchpad; /**< Gamepad touchpad event data */ SDL_GamepadSensorEvent gsensor; /**< Gamepad sensor event data */ SDL_AudioDeviceEvent adevice; /**< Audio device event data */ diff --git a/include/SDL3/SDL_gamepad.h b/include/SDL3/SDL_gamepad.h index 1b2f25f59..7a9b7e826 100644 --- a/include/SDL3/SDL_gamepad.h +++ b/include/SDL3/SDL_gamepad.h @@ -389,6 +389,17 @@ extern DECLSPEC char * SDLCALL SDL_GetGamepadMapping(SDL_Gamepad *gamepad); */ extern DECLSPEC int SDLCALL SDL_SetGamepadMapping(SDL_JoystickID instance_id, const char *mapping); +/** + * Return whether a gamepad is currently connected. + * + * \returns SDL_TRUE if a gamepad is connected, SDL_FALSE otherwise. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetGamepads + */ +extern DECLSPEC SDL_bool SDLCALL SDL_HasGamepad(void); + /** * Get a list of currently connected gamepads. * @@ -399,6 +410,7 @@ extern DECLSPEC int SDLCALL SDL_SetGamepadMapping(SDL_JoystickID instance_id, co * * \since This function is available since SDL 3.0.0. * + * \sa SDL_HasGamepad * \sa SDL_OpenGamepad */ extern DECLSPEC SDL_JoystickID *SDLCALL SDL_GetGamepads(int *count); diff --git a/include/SDL3/SDL_joystick.h b/include/SDL3/SDL_joystick.h index b0135c024..4708aa7ba 100644 --- a/include/SDL3/SDL_joystick.h +++ b/include/SDL3/SDL_joystick.h @@ -137,6 +137,17 @@ extern DECLSPEC void SDLCALL SDL_LockJoysticks(void) SDL_ACQUIRE(SDL_joystick_lo */ extern DECLSPEC void SDLCALL SDL_UnlockJoysticks(void) SDL_RELEASE(SDL_joystick_lock); +/** + * Return whether a joystick is currently connected. + * + * \returns SDL_TRUE if a joystick is connected, SDL_FALSE otherwise. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetJoysticks + */ +extern DECLSPEC SDL_bool SDLCALL SDL_HasJoystick(void); + /** * Get a list of currently connected joysticks. * @@ -147,6 +158,7 @@ extern DECLSPEC void SDLCALL SDL_UnlockJoysticks(void) SDL_RELEASE(SDL_joystick_ * * \since This function is available since SDL 3.0.0. * + * \sa SDL_HasJoystick * \sa SDL_OpenJoystick */ extern DECLSPEC SDL_JoystickID *SDLCALL SDL_GetJoysticks(int *count); diff --git a/include/SDL3/SDL_keyboard.h b/include/SDL3/SDL_keyboard.h index 08ca35c30..d2a8b1cfb 100644 --- a/include/SDL3/SDL_keyboard.h +++ b/include/SDL3/SDL_keyboard.h @@ -39,6 +39,8 @@ extern "C" { #endif +typedef Uint32 SDL_KeyboardID; + /** * The SDL keysym structure, used in key events. * @@ -54,6 +56,31 @@ typedef struct SDL_Keysym /* Function prototypes */ +/** + * Return whether a keyboard is currently connected. + * + * \returns SDL_TRUE if a keyboard is connected, SDL_FALSE otherwise. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetKeyboards + */ +extern DECLSPEC SDL_bool SDLCALL SDL_HasKeyboard(void); + +/** + * Get a list of currently connected keyboards. + * + * \param count a pointer filled in with the number of keyboards returned + * \returns a 0 terminated array of keyboards instance IDs which should be + * freed with SDL_free(), or NULL on error; call SDL_GetError() for + * more details. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_HasKeyboard + */ +extern DECLSPEC SDL_KeyboardID *SDLCALL SDL_GetKeyboards(int *count); + /** * Query the window which currently has keyboard focus. * diff --git a/include/SDL3/SDL_mouse.h b/include/SDL3/SDL_mouse.h index 92a8eab0a..da1eb3b90 100644 --- a/include/SDL3/SDL_mouse.h +++ b/include/SDL3/SDL_mouse.h @@ -81,6 +81,31 @@ typedef enum /* Function prototypes */ +/** + * Return whether a mouse is currently connected. + * + * \returns SDL_TRUE if a mouse is connected, SDL_FALSE otherwise. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetMice + */ +extern DECLSPEC SDL_bool SDLCALL SDL_HasMouse(void); + +/** + * Get a list of currently connected mice. + * + * \param count a pointer filled in with the number of mice returned + * \returns a 0 terminated array of mouse instance IDs which should be + * freed with SDL_free(), or NULL on error; call SDL_GetError() for + * more details. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_HasMouse + */ +extern DECLSPEC SDL_MouseID *SDLCALL SDL_GetMice(int *count); + /** * Get the window which currently has mouse focus. * diff --git a/src/core/haiku/SDL_BApp.h b/src/core/haiku/SDL_BApp.h index 39fec7782..2d5be1e2b 100644 --- a/src/core/haiku/SDL_BApp.h +++ b/src/core/haiku/SDL_BApp.h @@ -303,7 +303,7 @@ class SDL_BLooper : public BLooper return; } HAIKU_SetKeyState(scancode, state); - SDL_SendKeyboardKey(0, state, HAIKU_GetScancodeFromBeKey(scancode)); + SDL_SendKeyboardKey(0, 0, state, HAIKU_GetScancodeFromBeKey(scancode)); if (state == SDL_PRESSED && SDL_EventEnabled(SDL_EVENT_TEXT_INPUT)) { const int8 *keyUtf8; diff --git a/src/core/linux/SDL_evdev.c b/src/core/linux/SDL_evdev.c index 9a435db8d..5a8c6e5e5 100644 --- a/src/core/linux/SDL_evdev.c +++ b/src/core/linux/SDL_evdev.c @@ -375,9 +375,9 @@ void SDL_EVDEV_Poll(void) scan_code = SDL_EVDEV_translate_keycode(event->code); if (scan_code != SDL_SCANCODE_UNKNOWN) { if (event->value == 0) { - SDL_SendKeyboardKey(SDL_EVDEV_GetEventTimestamp(event), SDL_RELEASED, scan_code); + SDL_SendKeyboardKey(SDL_EVDEV_GetEventTimestamp(event), (SDL_KeyboardID)item->fd, SDL_RELEASED, scan_code); } else if (event->value == 1 || event->value == 2 /* key repeated */) { - SDL_SendKeyboardKey(SDL_EVDEV_GetEventTimestamp(event), SDL_PRESSED, scan_code); + SDL_SendKeyboardKey(SDL_EVDEV_GetEventTimestamp(event), (SDL_KeyboardID)item->fd, SDL_PRESSED, scan_code); } } SDL_EVDEV_kbd_keycode(_this->kbd, event->code, event->value); diff --git a/src/core/openbsd/SDL_wscons_kbd.c b/src/core/openbsd/SDL_wscons_kbd.c index 8b08f05d0..1cc361b76 100644 --- a/src/core/openbsd/SDL_wscons_kbd.c +++ b/src/core/openbsd/SDL_wscons_kbd.c @@ -553,22 +553,22 @@ static void Translate_to_keycode(SDL_WSCONS_input_data *input, int type, keysym_ switch (keyDesc.command) { case KS_Cmd_ScrollBack: { - SDL_SendKeyboardKey(0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_PAGEUP); + SDL_SendKeyboardKey(0, 0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_PAGEUP); return; } case KS_Cmd_ScrollFwd: { - SDL_SendKeyboardKey(0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_PAGEDOWN); + SDL_SendKeyboardKey(0, 0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_PAGEDOWN); return; } } for (i = 0; i < sizeof(conversion_table) / sizeof(struct wscons_keycode_to_SDL); i++) { if (conversion_table[i].sourcekey == group[0]) { - SDL_SendKeyboardKey(0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, conversion_table[i].targetKey); + SDL_SendKeyboardKey(0, 0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, conversion_table[i].targetKey); return; } } - SDL_SendKeyboardKey(0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_UNKNOWN); + SDL_SendKeyboardKey(0, 0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_UNKNOWN); } static void updateKeyboard(SDL_WSCONS_input_data *input) @@ -802,13 +802,13 @@ static void updateKeyboard(SDL_WSCONS_input_data *input) } break; case WSCONS_EVENT_ALL_KEYS_UP: for (i = 0; i < SDL_NUM_SCANCODES; i++) { - SDL_SendKeyboardKey(0, SDL_RELEASED, i); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, i); } break; } if (input->type == WSKBD_TYPE_USB && events[i].value <= 0xE7) - SDL_SendKeyboardKey(0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, (SDL_Scancode)events[i].value); + SDL_SendKeyboardKey(0, 0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, (SDL_Scancode)events[i].value); else Translate_to_keycode(input, type, events[i].value); diff --git a/src/core/windows/SDL_hid.c b/src/core/windows/SDL_hid.c index 9c86b69d5..0e42bb667 100644 --- a/src/core/windows/SDL_hid.c +++ b/src/core/windows/SDL_hid.c @@ -35,6 +35,7 @@ HidP_GetData_t SDL_HidP_GetData; static HMODULE s_pHIDDLL = 0; static int s_HIDDLLRefCount = 0; + int WIN_LoadHIDDLL(void) { if (s_pHIDDLL) { @@ -82,3 +83,174 @@ void WIN_UnloadHIDDLL(void) } #endif /* !SDL_PLATFORM_WINRT */ + +#if !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) + +/* CM_Register_Notification definitions */ + +#define CR_SUCCESS 0 + +DECLARE_HANDLE(HCMNOTIFICATION); +typedef HCMNOTIFICATION *PHCMNOTIFICATION; + +typedef enum _CM_NOTIFY_FILTER_TYPE +{ + CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE = 0, + CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE, + CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE, + CM_NOTIFY_FILTER_TYPE_MAX +} CM_NOTIFY_FILTER_TYPE, *PCM_NOTIFY_FILTER_TYPE; + +typedef struct _CM_NOTIFY_FILTER +{ + DWORD cbSize; + DWORD Flags; + CM_NOTIFY_FILTER_TYPE FilterType; + DWORD Reserved; + union + { + struct + { + GUID ClassGuid; + } DeviceInterface; + struct + { + HANDLE hTarget; + } DeviceHandle; + struct + { + WCHAR InstanceId[200]; + } DeviceInstance; + } u; +} CM_NOTIFY_FILTER, *PCM_NOTIFY_FILTER; + +typedef enum _CM_NOTIFY_ACTION +{ + CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL = 0, + CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL, + CM_NOTIFY_ACTION_DEVICEQUERYREMOVE, + CM_NOTIFY_ACTION_DEVICEQUERYREMOVEFAILED, + CM_NOTIFY_ACTION_DEVICEREMOVEPENDING, + CM_NOTIFY_ACTION_DEVICEREMOVECOMPLETE, + CM_NOTIFY_ACTION_DEVICECUSTOMEVENT, + CM_NOTIFY_ACTION_DEVICEINSTANCEENUMERATED, + CM_NOTIFY_ACTION_DEVICEINSTANCESTARTED, + CM_NOTIFY_ACTION_DEVICEINSTANCEREMOVED, + CM_NOTIFY_ACTION_MAX +} CM_NOTIFY_ACTION, *PCM_NOTIFY_ACTION; + +typedef struct _CM_NOTIFY_EVENT_DATA +{ + CM_NOTIFY_FILTER_TYPE FilterType; + DWORD Reserved; + union + { + struct + { + GUID ClassGuid; + WCHAR SymbolicLink[ANYSIZE_ARRAY]; + } DeviceInterface; + struct + { + GUID EventGuid; + LONG NameOffset; + DWORD DataSize; + BYTE Data[ANYSIZE_ARRAY]; + } DeviceHandle; + struct + { + WCHAR InstanceId[ANYSIZE_ARRAY]; + } DeviceInstance; + } u; +} CM_NOTIFY_EVENT_DATA, *PCM_NOTIFY_EVENT_DATA; + +typedef DWORD (CALLBACK *PCM_NOTIFY_CALLBACK)(HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize); + +typedef DWORD (WINAPI *CM_Register_NotificationFunc)(PCM_NOTIFY_FILTER pFilter, PVOID pContext, PCM_NOTIFY_CALLBACK pCallback, PHCMNOTIFICATION pNotifyContext); +typedef DWORD (WINAPI *CM_Unregister_NotificationFunc)(HCMNOTIFICATION NotifyContext); + +static GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } }; + +static int s_DeviceNotificationsRequested; +static HMODULE cfgmgr32_lib_handle; +static CM_Register_NotificationFunc CM_Register_Notification; +static CM_Unregister_NotificationFunc CM_Unregister_Notification; +static HCMNOTIFICATION s_DeviceNotificationFuncHandle; +static Uint64 s_LastDeviceNotification = 1; + +static DWORD CALLBACK SDL_DeviceNotificationFunc(HCMNOTIFICATION hNotify, PVOID context, CM_NOTIFY_ACTION action, PCM_NOTIFY_EVENT_DATA eventData, DWORD event_data_size) +{ + if (action == CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL || + action == CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL) { + s_LastDeviceNotification = SDL_GetTicksNS(); + } + return ERROR_SUCCESS; +} + +void WIN_InitDeviceNotification(void) +{ + ++s_DeviceNotificationsRequested; + if (s_DeviceNotificationsRequested > 1) { + return; + } + + cfgmgr32_lib_handle = LoadLibraryA("cfgmgr32.dll"); + if (cfgmgr32_lib_handle) { + CM_Register_Notification = (CM_Register_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Register_Notification"); + CM_Unregister_Notification = (CM_Unregister_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Unregister_Notification"); + if (CM_Register_Notification && CM_Unregister_Notification) { + CM_NOTIFY_FILTER notify_filter; + + SDL_zero(notify_filter); + notify_filter.cbSize = sizeof(notify_filter); + notify_filter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE; + notify_filter.u.DeviceInterface.ClassGuid = GUID_DEVINTERFACE_HID; + if (CM_Register_Notification(¬ify_filter, NULL, SDL_DeviceNotificationFunc, &s_DeviceNotificationFuncHandle) == CR_SUCCESS) { + return; + } + } + } + + // FIXME: Should we log errors? +} + +Uint64 WIN_GetLastDeviceNotification(void) +{ + return s_LastDeviceNotification; +} + +void WIN_QuitDeviceNotification(void) +{ + if (--s_DeviceNotificationsRequested > 0) { + return; + } + /* Make sure we have balanced calls to init/quit */ + SDL_assert(s_DeviceNotificationsRequested == 0); + + if (cfgmgr32_lib_handle) { + if (s_DeviceNotificationFuncHandle && CM_Unregister_Notification) { + CM_Unregister_Notification(s_DeviceNotificationFuncHandle); + s_DeviceNotificationFuncHandle = NULL; + } + + FreeLibrary(cfgmgr32_lib_handle); + cfgmgr32_lib_handle = NULL; + } +} + +#else + +void WIN_InitDeviceNotification(void) +{ +} + +Uint64 WIN_GetLastDeviceNotification( void ) +{ + return 0; +} + +void WIN_QuitDeviceNotification(void) +{ +} + +#endif // !SDL_PLATFORM_WINRT && !SDL_PLATFORM_XBOXONE && !SDL_PLATFORM_XBOXSERIES diff --git a/src/core/windows/SDL_hid.h b/src/core/windows/SDL_hid.h index e747e46ea..3d7821126 100644 --- a/src/core/windows/SDL_hid.h +++ b/src/core/windows/SDL_hid.h @@ -193,12 +193,12 @@ typedef struct extern int WIN_LoadHIDDLL(void); extern void WIN_UnloadHIDDLL(void); -typedef BOOLEAN(WINAPI *HidD_GetString_t)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength); -typedef NTSTATUS(WINAPI *HidP_GetCaps_t)(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities); -typedef NTSTATUS(WINAPI *HidP_GetButtonCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData); -typedef NTSTATUS(WINAPI *HidP_GetValueCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData); -typedef ULONG(WINAPI *HidP_MaxDataListLength_t)(HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData); -typedef NTSTATUS(WINAPI *HidP_GetData_t)(HIDP_REPORT_TYPE ReportType, PHIDP_DATA DataList, PULONG DataLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength); +typedef BOOLEAN (WINAPI *HidD_GetString_t)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength); +typedef NTSTATUS (WINAPI *HidP_GetCaps_t)(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities); +typedef NTSTATUS (WINAPI *HidP_GetButtonCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData); +typedef NTSTATUS (WINAPI *HidP_GetValueCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData); +typedef ULONG (WINAPI *HidP_MaxDataListLength_t)(HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData); +typedef NTSTATUS (WINAPI *HidP_GetData_t)(HIDP_REPORT_TYPE ReportType, PHIDP_DATA DataList, PULONG DataLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength); extern HidD_GetString_t SDL_HidD_GetManufacturerString; extern HidD_GetString_t SDL_HidD_GetProductString; @@ -210,4 +210,9 @@ extern HidP_GetData_t SDL_HidP_GetData; #endif /* !SDL_PLATFORM_WINRT */ + +void WIN_InitDeviceNotification(void); +Uint64 WIN_GetLastDeviceNotification(void); +void WIN_QuitDeviceNotification(void); + #endif /* SDL_hid_h_ */ diff --git a/src/core/winrt/SDL_winrtapp_direct3d.cpp b/src/core/winrt/SDL_winrtapp_direct3d.cpp index 0459ab107..9fddd3d10 100644 --- a/src/core/winrt/SDL_winrtapp_direct3d.cpp +++ b/src/core/winrt/SDL_winrtapp_direct3d.cpp @@ -724,8 +724,8 @@ void SDL_WinRTApp::OnCharacterReceived(Windows::UI::Core::CoreWindow ^ sender, W template static void WINRT_OnBackButtonPressed(BackButtonEventArgs ^ args) { - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_AC_BACK); - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_AC_BACK); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_AC_BACK); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_AC_BACK); if (SDL_GetHintBoolean(SDL_HINT_WINRT_HANDLE_BACK_BUTTON, SDL_FALSE)) { args->Handled = true; diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index e651008fc..be498a820 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -320,11 +320,13 @@ SDL3_0.0.0 { SDL_GetKeyName; SDL_GetKeyboardFocus; SDL_GetKeyboardState; + SDL_GetKeyboards; SDL_GetLogOutputFunction; SDL_GetMasksForPixelFormatEnum; SDL_GetMaxHapticEffects; SDL_GetMaxHapticEffectsPlaying; SDL_GetMemoryFunctions; + SDL_GetMice; SDL_GetModState; SDL_GetMouseFocus; SDL_GetMouseState; @@ -487,9 +489,13 @@ SDL3_0.0.0 { SDL_HasClipboardText; SDL_HasEvent; SDL_HasEvents; + SDL_HasGamepad; + SDL_HasJoystick; + SDL_HasKeyboard; SDL_HasLASX; SDL_HasLSX; SDL_HasMMX; + SDL_HasMouse; SDL_HasNEON; SDL_HasPrimarySelectionText; SDL_HasProperty; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index ac9310c48..8f140360d 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -345,11 +345,13 @@ #define SDL_GetKeyName SDL_GetKeyName_REAL #define SDL_GetKeyboardFocus SDL_GetKeyboardFocus_REAL #define SDL_GetKeyboardState SDL_GetKeyboardState_REAL +#define SDL_GetKeyboards SDL_GetKeyboards_REAL #define SDL_GetLogOutputFunction SDL_GetLogOutputFunction_REAL #define SDL_GetMasksForPixelFormatEnum SDL_GetMasksForPixelFormatEnum_REAL #define SDL_GetMaxHapticEffects SDL_GetMaxHapticEffects_REAL #define SDL_GetMaxHapticEffectsPlaying SDL_GetMaxHapticEffectsPlaying_REAL #define SDL_GetMemoryFunctions SDL_GetMemoryFunctions_REAL +#define SDL_GetMice SDL_GetMice_REAL #define SDL_GetModState SDL_GetModState_REAL #define SDL_GetMouseFocus SDL_GetMouseFocus_REAL #define SDL_GetMouseState SDL_GetMouseState_REAL @@ -512,9 +514,13 @@ #define SDL_HasClipboardText SDL_HasClipboardText_REAL #define SDL_HasEvent SDL_HasEvent_REAL #define SDL_HasEvents SDL_HasEvents_REAL +#define SDL_HasGamepad SDL_HasGamepad_REAL +#define SDL_HasJoystick SDL_HasJoystick_REAL +#define SDL_HasKeyboard SDL_HasKeyboard_REAL #define SDL_HasLASX SDL_HasLASX_REAL #define SDL_HasLSX SDL_HasLSX_REAL #define SDL_HasMMX SDL_HasMMX_REAL +#define SDL_HasMouse SDL_HasMouse_REAL #define SDL_HasNEON SDL_HasNEON_REAL #define SDL_HasPrimarySelectionText SDL_HasPrimarySelectionText_REAL #define SDL_HasProperty SDL_HasProperty_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index f1ff330c6..8a2804a24 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -383,11 +383,13 @@ SDL_DYNAPI_PROC(SDL_Keycode,SDL_GetKeyFromScancode,(SDL_Scancode a),(a),return) SDL_DYNAPI_PROC(const char*,SDL_GetKeyName,(SDL_Keycode a),(a),return) SDL_DYNAPI_PROC(SDL_Window*,SDL_GetKeyboardFocus,(void),(),return) SDL_DYNAPI_PROC(const Uint8*,SDL_GetKeyboardState,(int *a),(a),return) +SDL_DYNAPI_PROC(SDL_MouseID*,SDL_GetKeyboards,(int *a),(a),return) SDL_DYNAPI_PROC(void,SDL_GetLogOutputFunction,(SDL_LogOutputFunction *a, void **b),(a,b),) SDL_DYNAPI_PROC(SDL_bool,SDL_GetMasksForPixelFormatEnum,(SDL_PixelFormatEnum a, int *b, Uint32 *c, Uint32 *d, Uint32 *e, Uint32 *f),(a,b,c,d,e,f),return) SDL_DYNAPI_PROC(int,SDL_GetMaxHapticEffects,(SDL_Haptic *a),(a),return) SDL_DYNAPI_PROC(int,SDL_GetMaxHapticEffectsPlaying,(SDL_Haptic *a),(a),return) SDL_DYNAPI_PROC(void,SDL_GetMemoryFunctions,(SDL_malloc_func *a, SDL_calloc_func *b, SDL_realloc_func *c, SDL_free_func *d),(a,b,c,d),) +SDL_DYNAPI_PROC(SDL_MouseID*,SDL_GetMice,(int *a),(a),return) SDL_DYNAPI_PROC(SDL_Keymod,SDL_GetModState,(void),(),return) SDL_DYNAPI_PROC(SDL_Window*,SDL_GetMouseFocus,(void),(),return) SDL_DYNAPI_PROC(Uint32,SDL_GetMouseState,(float *a, float *b),(a,b),return) @@ -543,9 +545,13 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_HasClipboardData,(const char *a),(a),return) SDL_DYNAPI_PROC(SDL_bool,SDL_HasClipboardText,(void),(),return) SDL_DYNAPI_PROC(SDL_bool,SDL_HasEvent,(Uint32 a),(a),return) SDL_DYNAPI_PROC(SDL_bool,SDL_HasEvents,(Uint32 a, Uint32 b),(a,b),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_HasGamepad,(void),(),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_HasJoystick,(void),(),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_HasKeyboard,(void),(),return) SDL_DYNAPI_PROC(SDL_bool,SDL_HasLASX,(void),(),return) SDL_DYNAPI_PROC(SDL_bool,SDL_HasLSX,(void),(),return) SDL_DYNAPI_PROC(SDL_bool,SDL_HasMMX,(void),(),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_HasMouse,(void),(),return) SDL_DYNAPI_PROC(SDL_bool,SDL_HasNEON,(void),(),return) SDL_DYNAPI_PROC(SDL_bool,SDL_HasPrimarySelectionText,(void),(),return) SDL_DYNAPI_PROC(SDL_bool,SDL_HasProperty,(SDL_PropertiesID a, const char *b),(a,b),return) diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c index 305a4744c..d1b277641 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -325,6 +325,15 @@ static void SDL_LogEvent(const SDL_Event *event) SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_DESTROYED); #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 state=%s repeat=%s scancode=%u keycode=%u mod=%u)", \ (uint)event->key.timestamp, (uint)event->key.windowID, \ @@ -351,6 +360,15 @@ static void SDL_LogEvent(const SDL_Event *event) (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, diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c index 555fc2280..63bd9842e 100644 --- a/src/events/SDL_keyboard.c +++ b/src/events/SDL_keyboard.c @@ -55,6 +55,8 @@ struct SDL_Keyboard }; static SDL_Keyboard SDL_keyboard; +static int SDL_keyboard_count; +static SDL_KeyboardID *SDL_keyboards; static const SDL_Keycode SDL_default_keymap[SDL_NUM_SCANCODES] = { /* 0 */ SDLK_UNKNOWN, @@ -678,6 +680,109 @@ int SDL_InitKeyboard(void) return 0; } +SDL_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 SDL_FALSE; + } + + /* Eventually we'll have a blacklist of devices that enumerate as keyboards but aren't really */ + return SDL_TRUE; +} + +void SDL_PrivateKeyboardAdded(SDL_KeyboardID keyboardID) +{ + int keyboard_index = -1; + + SDL_assert(keyboardID != 0); + + for (int i = 0; i < SDL_keyboard_count; ++i) { + if (keyboardID == SDL_keyboards[i]) { + keyboard_index = i; + break; + } + } + + if (keyboard_index >= 0) { + /* We already know about this keyboard */ + return; + } + + SDL_KeyboardID *keyboards = (SDL_KeyboardID *)SDL_realloc(SDL_keyboards, (SDL_keyboard_count + 1) * sizeof(*keyboards)); + if (!keyboards) { + return; + } + keyboards[SDL_keyboard_count] = keyboardID; + SDL_keyboards = keyboards; + ++SDL_keyboard_count; + + SDL_Event event; + SDL_zero(event); + event.type = SDL_EVENT_KEYBOARD_ADDED; + event.kdevice.which = keyboardID; + SDL_PushEvent(&event); +} + +void SDL_PrivateKeyboardRemoved(SDL_KeyboardID keyboardID) +{ + int keyboard_index = -1; + + SDL_assert(keyboardID != 0); + + for (int i = 0; i < SDL_keyboard_count; ++i) { + if (keyboardID == SDL_keyboards[i]) { + keyboard_index = i; + break; + } + } + + if (keyboard_index < 0) { + /* We don't know about this keyboard */ + return; + } + + if (keyboard_index != SDL_keyboard_count - 1) { + SDL_memcpy(&SDL_keyboards[keyboard_index], &SDL_keyboards[keyboard_index + 1], (SDL_keyboard_count - keyboard_index - 1) * sizeof(SDL_keyboards[keyboard_index])); + } + --SDL_keyboard_count; + + SDL_Event event; + SDL_zero(event); + event.type = SDL_EVENT_KEYBOARD_REMOVED; + event.kdevice.which = keyboardID; + SDL_PushEvent(&event); +} + +SDL_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]; + } + keyboards[i] = 0; + } else { + if (count) { + *count = 0; + } + } + + return keyboards; +} + void SDL_ResetKeyboard(void) { SDL_Keyboard *keyboard = &SDL_keyboard; @@ -688,7 +793,7 @@ void SDL_ResetKeyboard(void) #endif for (scancode = (SDL_Scancode)0; scancode < SDL_NUM_SCANCODES; ++scancode) { if (keyboard->keystate[scancode] == SDL_PRESSED) { - SDL_SendKeyboardKey(0, SDL_RELEASED, scancode); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, scancode); } } } @@ -822,7 +927,7 @@ int SDL_SetKeyboardFocus(SDL_Window *window) return 0; } -static int SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode) +static int SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, SDL_KeyboardID keyboardID, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode) { SDL_Keyboard *keyboard = &SDL_keyboard; int posted; @@ -831,6 +936,13 @@ static int SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, Uint8 sta Uint8 repeat = SDL_FALSE; const Uint8 source = flags & KEYBOARD_SOURCE_MASK; + if (keyboardID == 0) { + if (source == KEYBOARD_HARDWARE && SDL_keyboard_count > 0) { + /* Assume it's from the first keyboard */ + keyboardID = SDL_keyboards[0]; + } + } + if (scancode == SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) { return 0; } @@ -949,6 +1061,7 @@ static int SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, Uint8 sta event.key.keysym.sym = keycode; event.key.keysym.mod = keyboard->modstate; event.key.windowID = keyboard->focus ? keyboard->focus->id : 0; + event.key.which = keyboardID; posted = (SDL_PushEvent(&event) > 0); } @@ -982,43 +1095,43 @@ int SDL_SendKeyboardUnicodeKey(Uint64 timestamp, Uint32 ch) if (mod & SDL_KMOD_SHIFT) { /* If the character uses shift, press shift down */ - SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_PRESSED, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN); + SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, 0, SDL_PRESSED, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN); } /* Send a keydown and keyup for the character */ - SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_PRESSED, code, SDLK_UNKNOWN); - SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_RELEASED, code, SDLK_UNKNOWN); + SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, 0, SDL_PRESSED, code, SDLK_UNKNOWN); + SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, 0, SDL_RELEASED, code, SDLK_UNKNOWN); if (mod & SDL_KMOD_SHIFT) { /* If the character uses shift, release shift */ - SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_RELEASED, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN); + SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, 0, SDL_RELEASED, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN); } return 0; } int SDL_SendVirtualKeyboardKey(Uint64 timestamp, Uint8 state, SDL_Scancode scancode) { - return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, state, scancode, SDLK_UNKNOWN); + return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, 0, state, scancode, SDLK_UNKNOWN); } -int SDL_SendKeyboardKey(Uint64 timestamp, Uint8 state, SDL_Scancode scancode) +int SDL_SendKeyboardKey(Uint64 timestamp, SDL_KeyboardID keyboardID, Uint8 state, SDL_Scancode scancode) { - return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, state, scancode, SDLK_UNKNOWN); + return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, keyboardID, state, scancode, SDLK_UNKNOWN); } -int SDL_SendKeyboardKeyAndKeycode(Uint64 timestamp, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode) +int SDL_SendKeyboardKeyAndKeycode(Uint64 timestamp, SDL_KeyboardID keyboardID, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode) { - return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, state, scancode, keycode); + return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, keyboardID, state, scancode, keycode); } int SDL_SendKeyboardKeyAutoRelease(Uint64 timestamp, SDL_Scancode scancode) { - return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_AUTORELEASE, SDL_PRESSED, scancode, SDLK_UNKNOWN); + return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_AUTORELEASE, 0, SDL_PRESSED, scancode, SDLK_UNKNOWN); } -int SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, Uint8 state, SDL_Scancode scancode) +int SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, SDL_KeyboardID keyboardID, Uint8 state, SDL_Scancode scancode) { - return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE | KEYBOARD_IGNOREMODIFIERS, state, scancode, SDLK_UNKNOWN); + return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE | KEYBOARD_IGNOREMODIFIERS, keyboardID, state, scancode, SDLK_UNKNOWN); } void SDL_ReleaseAutoReleaseKeys(void) @@ -1029,7 +1142,7 @@ void SDL_ReleaseAutoReleaseKeys(void) if (keyboard->autorelease_pending) { for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES; ++scancode) { if (keyboard->keysource[scancode] == KEYBOARD_AUTORELEASE) { - SDL_SendKeyboardKeyInternal(0, KEYBOARD_AUTORELEASE, SDL_RELEASED, scancode, SDLK_UNKNOWN); + SDL_SendKeyboardKeyInternal(0, KEYBOARD_AUTORELEASE, 0, SDL_RELEASED, scancode, SDLK_UNKNOWN); } } keyboard->autorelease_pending = SDL_FALSE; @@ -1117,6 +1230,9 @@ int SDL_SendEditingText(const char *text, int start, int length) void SDL_QuitKeyboard(void) { + SDL_keyboard_count = 0; + SDL_free(SDL_keyboards); + SDL_keyboards = NULL; } const Uint8 *SDL_GetKeyboardState(int *numkeys) diff --git a/src/events/SDL_keyboard_c.h b/src/events/SDL_keyboard_c.h index 98459b1dd..f32566df7 100644 --- a/src/events/SDL_keyboard_c.h +++ b/src/events/SDL_keyboard_c.h @@ -26,6 +26,15 @@ /* Initialize the keyboard subsystem */ extern int SDL_InitKeyboard(void); +/* Return whether a device is actually a keyboard */ +extern SDL_bool SDL_IsKeyboard(Uint16 vendor, Uint16 product, int num_keys); + +/* A keyboard has been added to the system */ +extern void SDL_PrivateKeyboardAdded(SDL_KeyboardID keyboardID); + +/* A keyboard has been removed from the system */ +extern void SDL_PrivateKeyboardRemoved(SDL_KeyboardID keyboardID); + /* Get the default keymap */ extern void SDL_GetDefaultKeymap(SDL_Keycode *keymap); @@ -53,13 +62,13 @@ extern int SDL_SendKeyboardUnicodeKey(Uint64 timestamp, Uint32 ch); extern int SDL_SendVirtualKeyboardKey(Uint64 timestamp, Uint8 state, SDL_Scancode scancode); /* Send a keyboard key event */ -extern int SDL_SendKeyboardKey(Uint64 timestamp, Uint8 state, SDL_Scancode scancode); +extern int SDL_SendKeyboardKey(Uint64 timestamp, SDL_KeyboardID keyboardID, Uint8 state, SDL_Scancode scancode); extern int SDL_SendKeyboardKeyAutoRelease(Uint64 timestamp, SDL_Scancode scancode); -extern int SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, Uint8 state, SDL_Scancode scancode); +extern int SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, SDL_KeyboardID keyboardID, Uint8 state, 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 int SDL_SendKeyboardKeyAndKeycode(Uint64 timestamp, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode); +extern int SDL_SendKeyboardKeyAndKeycode(Uint64 timestamp, SDL_KeyboardID keyboardID, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode); /* Release all the autorelease keys */ extern void SDL_ReleaseAutoReleaseKeys(void); diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index f9aa6d31e..347227020 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -35,6 +35,8 @@ /* The mouse state */ static SDL_Mouse SDL_mouse; +static int SDL_mouse_count; +static SDL_MouseID *SDL_mice; /* for mapping mouse events to touch */ static SDL_bool track_mouse_down = SDL_FALSE; @@ -227,6 +229,118 @@ void SDL_PostInitMouse(void) SDL_PenInit(); } +SDL_bool SDL_IsMouse(Uint16 vendor, Uint16 product) +{ + /* Eventually we'll have a blacklist of devices that enumerate as mice but aren't really */ + return SDL_TRUE; +} + +void SDL_PrivateMouseAdded(SDL_MouseID mouseID) +{ + int mouse_index = -1; + + SDL_assert(mouseID != 0); + + for (int i = 0; i < SDL_mouse_count; ++i) { + if (mouseID == SDL_mice[i]) { + mouse_index = i; + break; + } + } + + if (mouse_index >= 0) { + /* We already know about this mouse */ + return; + } + + SDL_MouseID *mice = (SDL_MouseID *)SDL_realloc(SDL_mice, (SDL_mouse_count + 1) * sizeof(*mice)); + if (!mice) { + return; + } + mice[SDL_mouse_count] = mouseID; + SDL_mice = mice; + ++SDL_mouse_count; + + SDL_Event event; + SDL_zero(event); + event.type = SDL_EVENT_MOUSE_ADDED; + event.mdevice.which = mouseID; + SDL_PushEvent(&event); +} + +void SDL_PrivateMouseRemoved(SDL_MouseID mouseID) +{ + int mouse_index = -1; + + SDL_assert(mouseID != 0); + + for (int i = 0; i < SDL_mouse_count; ++i) { + if (mouseID == SDL_mice[i]) { + mouse_index = i; + break; + } + } + + if (mouse_index < 0) { + /* We don't know about this mouse */ + return; + } + + if (mouse_index != SDL_mouse_count - 1) { + SDL_memcpy(&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) { + if (i != mouse->num_sources - 1) { + SDL_memcpy(&mouse->sources[i], &mouse->sources[i + 1], (mouse->num_sources - i - 1) * sizeof(mouse->sources[i])); + } + --mouse->num_sources; + break; + } + } + + SDL_Event event; + SDL_zero(event); + event.type = SDL_EVENT_MOUSE_REMOVED; + event.mdevice.which = mouseID; + SDL_PushEvent(&event); +} + +SDL_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]; + } + mice[i] = 0; + } else { + if (count) { + *count = 0; + } + } + + return mice; +} + + void SDL_SetDefaultCursor(SDL_Cursor *cursor) { SDL_Mouse *mouse = SDL_GetMouse(); @@ -687,18 +801,35 @@ static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_ return posted; } -static SDL_MouseInputSource *GetMouseInputSource(SDL_Mouse *mouse, SDL_MouseID mouseID) +static SDL_MouseInputSource *GetMouseInputSource(SDL_Mouse *mouse, SDL_MouseID mouseID, Uint8 state, Uint8 button) { - SDL_MouseInputSource *source, *sources; + SDL_MouseInputSource *source, *match = NULL, *sources; int i; for (i = 0; i < mouse->num_sources; ++i) { source = &mouse->sources[i]; if (source->mouseID == mouseID) { - return source; + match = source; + break; } } + if (!state && (!match || !(match->buttonstate & SDL_BUTTON(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(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; @@ -737,7 +868,7 @@ static int SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_ Uint32 buttonstate; SDL_MouseInputSource *source; - source = GetMouseInputSource(mouse, mouseID); + source = GetMouseInputSource(mouse, mouseID, state, button); if (!source) { return 0; } @@ -823,7 +954,7 @@ static int SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_ event.type = type; event.common.timestamp = timestamp; event.button.windowID = mouse->focus ? mouse->focus->id : 0; - event.button.which = mouseID; + event.button.which = source->mouseID; event.button.state = state; event.button.button = button; event.button.clicks = (Uint8)SDL_min(clicks, 255); @@ -957,6 +1088,10 @@ void SDL_QuitMouse(void) SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION, SDL_MouseRelativeWarpMotionChanged, mouse); + + SDL_mouse_count = 0; + SDL_free(SDL_mice); + SDL_mice = NULL; } Uint32 SDL_GetMouseState(float *x, float *y) diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index ac3334e03..1b2ccbeac 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -128,8 +128,17 @@ extern int 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 SDL_bool SDL_IsMouse(Uint16 vendor, Uint16 product); + +/* A mouse has been added to the system */ +extern void SDL_PrivateMouseAdded(SDL_MouseID mouseID); + +/* A mouse has been removed from the system */ +extern void SDL_PrivateMouseRemoved(SDL_MouseID mouseID); + /* Get the mouse state structure */ -SDL_Mouse *SDL_GetMouse(void); +extern SDL_Mouse *SDL_GetMouse(void); /* Set the default mouse cursor */ extern void SDL_SetDefaultCursor(SDL_Cursor *cursor); diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c index 13d2a4d22..c5f56828a 100644 --- a/src/joystick/SDL_gamepad.c +++ b/src/joystick/SDL_gamepad.c @@ -2369,6 +2369,26 @@ int SDL_InitGamepads(void) return 0; } +SDL_bool SDL_HasGamepad(void) +{ + int num_joysticks = 0; + int num_gamepads = 0; + SDL_JoystickID *joysticks = SDL_GetJoysticks(&num_joysticks); + if (joysticks) { + int i; + for (i = num_joysticks - 1; i >= 0 && num_gamepads == 0; --i) { + if (SDL_IsGamepad(joysticks[i])) { + ++num_gamepads; + } + } + SDL_free(joysticks); + } + if (num_gamepads > 0) { + return SDL_TRUE; + } + return SDL_FALSE; +} + SDL_JoystickID *SDL_GetGamepads(int *count) { int num_joysticks = 0; diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 82fb8a799..5b4b1e777 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -682,6 +682,25 @@ SDL_bool SDL_JoystickHandledByAnotherDriver(struct SDL_JoystickDriver *driver, U return result; } +SDL_bool SDL_HasJoystick(void) +{ + int i; + int total_joysticks = 0; + + SDL_LockJoysticks(); + { + for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { + total_joysticks += SDL_joystick_drivers[i]->GetCount(); + } + } + SDL_UnlockJoysticks(); + + if (total_joysticks > 0) { + return SDL_TRUE; + } + return SDL_FALSE; +} + SDL_JoystickID *SDL_GetJoysticks(int *count) { int i, num_joysticks, device_index; diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c index fe085a749..c6408c067 100644 --- a/src/joystick/android/SDL_sysjoystick.c +++ b/src/joystick/android/SDL_sysjoystick.c @@ -205,7 +205,7 @@ int Android_OnPadDown(int device_id, int keycode) if (item && item->joystick) { SDL_SendJoystickButton(timestamp, item->joystick, button, SDL_PRESSED); } else { - SDL_SendKeyboardKey(timestamp, SDL_PRESSED, button_to_scancode(button)); + SDL_SendKeyboardKey(timestamp, 0, SDL_PRESSED, button_to_scancode(button)); } SDL_UnlockJoysticks(); return 0; @@ -225,7 +225,7 @@ int Android_OnPadUp(int device_id, int keycode) if (item && item->joystick) { SDL_SendJoystickButton(timestamp, item->joystick, button, SDL_RELEASED); } else { - SDL_SendKeyboardKey(timestamp, SDL_RELEASED, button_to_scancode(button)); + SDL_SendKeyboardKey(timestamp, 0, SDL_RELEASED, button_to_scancode(button)); } SDL_UnlockJoysticks(); return 0; diff --git a/src/joystick/windows/SDL_windowsjoystick.c b/src/joystick/windows/SDL_windowsjoystick.c index 415f1d99b..6bd204ae4 100644 --- a/src/joystick/windows/SDL_windowsjoystick.c +++ b/src/joystick/windows/SDL_windowsjoystick.c @@ -35,6 +35,7 @@ #include "../SDL_sysjoystick.h" #include "../../thread/SDL_systhread.h" #include "../../core/windows/SDL_windows.h" +#include "../../core/windows/SDL_hid.h" #if !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) #include #endif @@ -51,162 +52,34 @@ #define DEVICE_NOTIFY_WINDOW_HANDLE 0x00000000 #endif -/* CM_Register_Notification definitions */ - -#define CR_SUCCESS (0x00000000) - -/* Set up for C function definitions, even when using C++ */ -#ifdef __cplusplus -extern "C" { -#endif - -DECLARE_HANDLE(HCMNOTIFICATION); -typedef HCMNOTIFICATION *PHCMNOTIFICATION; - -typedef enum _CM_NOTIFY_FILTER_TYPE -{ - CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE = 0, - CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE, - CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE, - CM_NOTIFY_FILTER_TYPE_MAX -} CM_NOTIFY_FILTER_TYPE, - *PCM_NOTIFY_FILTER_TYPE; - -typedef struct _CM_NOTIFY_FILTER -{ - DWORD cbSize; - DWORD Flags; - CM_NOTIFY_FILTER_TYPE FilterType; - DWORD Reserved; - union - { - struct - { - GUID ClassGuid; - } DeviceInterface; - struct - { - HANDLE hTarget; - } DeviceHandle; - struct - { - WCHAR InstanceId[200]; - } DeviceInstance; - } u; -} CM_NOTIFY_FILTER, *PCM_NOTIFY_FILTER; - -typedef enum _CM_NOTIFY_ACTION -{ - CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL = 0, - CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL, - CM_NOTIFY_ACTION_DEVICEQUERYREMOVE, - CM_NOTIFY_ACTION_DEVICEQUERYREMOVEFAILED, - CM_NOTIFY_ACTION_DEVICEREMOVEPENDING, - CM_NOTIFY_ACTION_DEVICEREMOVECOMPLETE, - CM_NOTIFY_ACTION_DEVICECUSTOMEVENT, - CM_NOTIFY_ACTION_DEVICEINSTANCEENUMERATED, - CM_NOTIFY_ACTION_DEVICEINSTANCESTARTED, - CM_NOTIFY_ACTION_DEVICEINSTANCEREMOVED, - CM_NOTIFY_ACTION_MAX -} CM_NOTIFY_ACTION, - *PCM_NOTIFY_ACTION; - -typedef struct _CM_NOTIFY_EVENT_DATA -{ - CM_NOTIFY_FILTER_TYPE FilterType; - DWORD Reserved; - union - { - struct - { - GUID ClassGuid; - WCHAR SymbolicLink[ANYSIZE_ARRAY]; - } DeviceInterface; - struct - { - GUID EventGuid; - LONG NameOffset; - DWORD DataSize; - BYTE Data[ANYSIZE_ARRAY]; - } DeviceHandle; - struct - { - WCHAR InstanceId[ANYSIZE_ARRAY]; - } DeviceInstance; - } u; -} CM_NOTIFY_EVENT_DATA, *PCM_NOTIFY_EVENT_DATA; - -typedef DWORD(CALLBACK *PCM_NOTIFY_CALLBACK)(HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize); - -typedef DWORD(WINAPI *CM_Register_NotificationFunc)(PCM_NOTIFY_FILTER pFilter, PVOID pContext, PCM_NOTIFY_CALLBACK pCallback, PHCMNOTIFICATION pNotifyContext); -typedef DWORD(WINAPI *CM_Unregister_NotificationFunc)(HCMNOTIFICATION NotifyContext); - /* local variables */ static SDL_bool s_bJoystickThread = SDL_FALSE; -static SDL_bool s_bWindowsDeviceChanged = SDL_FALSE; static SDL_Condition *s_condJoystickThread = NULL; static SDL_Mutex *s_mutexJoyStickEnum = NULL; static SDL_Thread *s_joystickThread = NULL; static SDL_bool s_bJoystickThreadQuit = SDL_FALSE; +static Uint64 s_lastDeviceChange = 0; static GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } }; JoyStick_DeviceData *SYS_Joystick; /* array to hold joystick ID values */ -#if !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) -static HMODULE cfgmgr32_lib_handle; -static CM_Register_NotificationFunc CM_Register_Notification; -static CM_Unregister_NotificationFunc CM_Unregister_Notification; -static HCMNOTIFICATION s_DeviceNotificationFuncHandle; + +static SDL_bool WindowsDeviceChanged(void) +{ + return (s_lastDeviceChange != WIN_GetLastDeviceNotification()); +} + +static void SetWindowsDeviceChanged(void) +{ + s_lastDeviceChange = 0; +} void WINDOWS_RAWINPUTEnabledChanged(void) { - s_bWindowsDeviceChanged = SDL_TRUE; + SetWindowsDeviceChanged(); } -static DWORD CALLBACK SDL_DeviceNotificationFunc(HCMNOTIFICATION hNotify, PVOID context, CM_NOTIFY_ACTION action, PCM_NOTIFY_EVENT_DATA eventData, DWORD event_data_size) -{ - if (action == CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL || - action == CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL) { - s_bWindowsDeviceChanged = SDL_TRUE; - } - return ERROR_SUCCESS; -} - -static void SDL_CleanupDeviceNotificationFunc(void) -{ - if (cfgmgr32_lib_handle) { - if (s_DeviceNotificationFuncHandle != NULL && CM_Unregister_Notification) { - CM_Unregister_Notification(s_DeviceNotificationFuncHandle); - s_DeviceNotificationFuncHandle = NULL; - } - - FreeLibrary(cfgmgr32_lib_handle); - cfgmgr32_lib_handle = NULL; - } -} - -static SDL_bool SDL_CreateDeviceNotificationFunc(void) -{ - cfgmgr32_lib_handle = LoadLibraryA("cfgmgr32.dll"); - if (cfgmgr32_lib_handle) { - CM_Register_Notification = (CM_Register_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Register_Notification"); - CM_Unregister_Notification = (CM_Unregister_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Unregister_Notification"); - if (CM_Register_Notification && CM_Unregister_Notification) { - CM_NOTIFY_FILTER notify_filter; - - SDL_zero(notify_filter); - notify_filter.cbSize = sizeof(notify_filter); - notify_filter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE; - notify_filter.u.DeviceInterface.ClassGuid = GUID_DEVINTERFACE_HID; - if (CM_Register_Notification(¬ify_filter, NULL, SDL_DeviceNotificationFunc, &s_DeviceNotificationFuncHandle) == CR_SUCCESS) { - return SDL_TRUE; - } - } - } - - SDL_CleanupDeviceNotificationFunc(); - return SDL_FALSE; -} +#if !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) typedef struct { @@ -239,7 +112,7 @@ static LRESULT CALLBACK SDL_PrivateJoystickDetectProc(HWND hwnd, UINT msg, WPARA if (wParam == IDT_SDL_DEVICE_CHANGE_TIMER_1 || wParam == IDT_SDL_DEVICE_CHANGE_TIMER_2) { KillTimer(hwnd, wParam); - s_bWindowsDeviceChanged = SDL_TRUE; + SetWindowsDeviceChanged(); return 0; } break; @@ -327,7 +200,7 @@ static SDL_bool SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, } SDL_UnlockMutex(mutex); - while (lastret > 0 && s_bWindowsDeviceChanged == SDL_FALSE) { + while (lastret > 0 && !WindowsDeviceChanged()) { lastret = GetMessage(&msg, NULL, 0, 0); /* WM_QUIT causes return value of 0 */ if (lastret > 0) { TranslateMessage(&msg); @@ -378,7 +251,7 @@ static int SDLCALL SDL_JoystickThread(void *_data) const DWORD result = XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities); const SDL_bool available = (result == ERROR_SUCCESS); if (bOpenedXInputDevices[userId] != available) { - s_bWindowsDeviceChanged = SDL_TRUE; + SetWindowsDeviceChanged(); bOpenedXInputDevices[userId] = available; } } @@ -476,13 +349,9 @@ static int WINDOWS_JoystickInit(void) return -1; } - s_bWindowsDeviceChanged = SDL_TRUE; /* force a scan of the system for joysticks this first time */ - - WINDOWS_JoystickDetect(); + WIN_InitDeviceNotification(); #if !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) - SDL_CreateDeviceNotificationFunc(); - s_bJoystickThread = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_THREAD, SDL_FALSE); if (s_bJoystickThread) { if (SDL_StartJoystickThread() < 0) { @@ -502,6 +371,11 @@ static int WINDOWS_JoystickInit(void) return -1; } #endif + + SetWindowsDeviceChanged(); /* force a scan of the system for joysticks this first time */ + + WINDOWS_JoystickDetect(); + return 0; } @@ -524,7 +398,7 @@ void WINDOWS_JoystickDetect(void) JoyStick_DeviceData *pCurList = NULL; /* only enum the devices if the joystick thread told us something changed */ - if (!s_bWindowsDeviceChanged) { + if (!WindowsDeviceChanged()) { return; /* thread hasn't signaled, nothing to do right now. */ } @@ -532,7 +406,7 @@ void WINDOWS_JoystickDetect(void) SDL_LockMutex(s_mutexJoyStickEnum); } - s_bWindowsDeviceChanged = SDL_FALSE; + s_lastDeviceChange = WIN_GetLastDeviceNotification(); pCurList = SYS_Joystick; SYS_Joystick = NULL; @@ -774,8 +648,6 @@ void WINDOWS_JoystickQuit(void) } else { SDL_CleanupDeviceNotification(&s_notification_data); } - - SDL_CleanupDeviceNotificationFunc(); #endif #if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) @@ -787,7 +659,7 @@ void WINDOWS_JoystickQuit(void) SDL_DINPUT_JoystickQuit(); SDL_XINPUT_JoystickQuit(); - s_bWindowsDeviceChanged = SDL_FALSE; + WIN_QuitDeviceNotification(); } static SDL_bool WINDOWS_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) @@ -819,11 +691,6 @@ SDL_JoystickDriver SDL_WINDOWS_JoystickDriver = { WINDOWS_JoystickGetGamepadMapping }; -/* Ends C function definitions when using C++ */ -#ifdef __cplusplus -} -#endif - #else #ifdef SDL_JOYSTICK_RAWINPUT diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index e8f33211e..0bbf54e44 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -1661,6 +1661,14 @@ static void SDLTest_PrintEvent(const SDL_Event *event) case SDL_EVENT_WINDOW_DESTROYED: SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " destroyed", event->window.windowID); break; + case SDL_EVENT_KEYBOARD_ADDED: + SDL_Log("SDL EVENT: Keyboard %" SDL_PRIu32 " attached", + event->kdevice.which); + break; + case SDL_EVENT_KEYBOARD_REMOVED: + SDL_Log("SDL EVENT: Keyboard %" SDL_PRIu32 " removed", + event->kdevice.which); + break; case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: { char modstr[64]; @@ -1691,6 +1699,14 @@ static void SDLTest_PrintEvent(const SDL_Event *event) case SDL_EVENT_KEYMAP_CHANGED: SDL_Log("SDL EVENT: Keymap changed"); break; + case SDL_EVENT_MOUSE_ADDED: + SDL_Log("SDL EVENT: Mouse %" SDL_PRIu32 " attached", + event->mdevice.which); + break; + case SDL_EVENT_MOUSE_REMOVED: + SDL_Log("SDL EVENT: Mouse %" SDL_PRIu32 " removed", + event->mdevice.which); + break; case SDL_EVENT_MOUSE_MOTION: SDL_Log("SDL EVENT: Mouse: moved to %g,%g (%g,%g) in window %" SDL_PRIu32, event->motion.x, event->motion.y, @@ -1712,7 +1728,7 @@ static void SDLTest_PrintEvent(const SDL_Event *event) event->wheel.x, event->wheel.y, event->wheel.direction, event->wheel.windowID); break; case SDL_EVENT_JOYSTICK_ADDED: - SDL_Log("SDL EVENT: Joystick index %" SDL_PRIu32 " attached", + SDL_Log("SDL EVENT: Joystick %" SDL_PRIu32 " attached", event->jdevice.which); break; case SDL_EVENT_JOYSTICK_REMOVED: @@ -1768,7 +1784,7 @@ static void SDLTest_PrintEvent(const SDL_Event *event) event->jbutton.which, event->jbutton.button); break; case SDL_EVENT_GAMEPAD_ADDED: - SDL_Log("SDL EVENT: Gamepad index %" SDL_PRIu32 " attached", + SDL_Log("SDL EVENT: Gamepad %" SDL_PRIu32 " attached", event->gdevice.which); break; case SDL_EVENT_GAMEPAD_REMOVED: diff --git a/src/video/android/SDL_androidkeyboard.c b/src/video/android/SDL_androidkeyboard.c index a63d0b68a..3c5063bd3 100644 --- a/src/video/android/SDL_androidkeyboard.c +++ b/src/video/android/SDL_androidkeyboard.c @@ -330,12 +330,12 @@ static SDL_Scancode TranslateKeycode(int keycode) int Android_OnKeyDown(int keycode) { - return SDL_SendKeyboardKey(0, SDL_PRESSED, TranslateKeycode(keycode)); + return SDL_SendKeyboardKey(0, 0, SDL_PRESSED, TranslateKeycode(keycode)); } int Android_OnKeyUp(int keycode) { - return SDL_SendKeyboardKey(0, SDL_RELEASED, TranslateKeycode(keycode)); + return SDL_SendKeyboardKey(0, 0, SDL_RELEASED, TranslateKeycode(keycode)); } SDL_bool Android_HasScreenKeyboardSupport(SDL_VideoDevice *_this) diff --git a/src/video/cocoa/SDL_cocoakeyboard.m b/src/video/cocoa/SDL_cocoakeyboard.m index 1a7296b82..5c419cda3 100644 --- a/src/video/cocoa/SDL_cocoakeyboard.m +++ b/src/video/cocoa/SDL_cocoakeyboard.m @@ -231,9 +231,9 @@ static void HandleModifiers(SDL_VideoDevice *_this, SDL_Scancode code, unsigned } if (pressed) { - SDL_SendKeyboardKey(0, SDL_PRESSED, code); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, code); } else { - SDL_SendKeyboardKey(0, SDL_RELEASED, code); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, code); } } @@ -279,7 +279,7 @@ static void UpdateKeymap(SDL_CocoaVideoData *data, SDL_bool send_event) continue; } - /* + /* * Swap the scancode for these two wrongly translated keys * UCKeyTranslate() function does not do its job properly for ISO layout keyboards, where the key '@', * which is located in the top left corner of the keyboard right under the Escape key, and the additional @@ -414,7 +414,7 @@ void Cocoa_HandleKeyEvent(SDL_VideoDevice *_this, NSEvent *event) UpdateKeymap(data, SDL_TRUE); } - SDL_SendKeyboardKey(Cocoa_GetEventTimestamp([event timestamp]), SDL_PRESSED, code); + SDL_SendKeyboardKey(Cocoa_GetEventTimestamp([event timestamp]), 0, SDL_PRESSED, code); #ifdef DEBUG_SCANCODES if (code == SDL_SCANCODE_UNKNOWN) { SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, report this to the SDL forums/mailing list or to Christian Walther . Mac virtual key code is %d.\n", scancode); @@ -433,7 +433,7 @@ void Cocoa_HandleKeyEvent(SDL_VideoDevice *_this, NSEvent *event) } break; case NSEventTypeKeyUp: - SDL_SendKeyboardKey(Cocoa_GetEventTimestamp([event timestamp]), SDL_RELEASED, code); + SDL_SendKeyboardKey(Cocoa_GetEventTimestamp([event timestamp]), 0, SDL_RELEASED, code); break; case NSEventTypeFlagsChanged: { // see if the new modifierFlags mean any existing keys should be pressed/released... diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 585216b17..5b7c5aca6 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -1381,8 +1381,8 @@ static SDL_bool Cocoa_IsZoomed(SDL_Window *window) const SDL_bool osenabled = ([theEvent modifierFlags] & NSEventModifierFlagCapsLock) ? SDL_TRUE : SDL_FALSE; const SDL_bool sdlenabled = (SDL_GetModState() & SDL_KMOD_CAPS) ? SDL_TRUE : SDL_FALSE; if (osenabled ^ sdlenabled) { - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_CAPSLOCK); - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_CAPSLOCK); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_CAPSLOCK); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_CAPSLOCK); } } - (void)keyDown:(NSEvent *)theEvent diff --git a/src/video/emscripten/SDL_emscriptenevents.c b/src/video/emscripten/SDL_emscriptenevents.c index 8a30544f7..d1e768dfd 100644 --- a/src/video/emscripten/SDL_emscriptenevents.c +++ b/src/video/emscripten/SDL_emscriptenevents.c @@ -811,7 +811,7 @@ static EM_BOOL Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent } if (scancode != SDL_SCANCODE_UNKNOWN) { - SDL_SendKeyboardKeyAndKeycode(0, eventType == EMSCRIPTEN_EVENT_KEYDOWN ? SDL_PRESSED : SDL_RELEASED, scancode, keycode); + SDL_SendKeyboardKeyAndKeycode(0, 0, eventType == EMSCRIPTEN_EVENT_KEYDOWN ? SDL_PRESSED : SDL_RELEASED, scancode, keycode); } /* if TEXTINPUT events are enabled we can't prevent keydown or we won't get keypress diff --git a/src/video/haiku/SDL_BApp.h b/src/video/haiku/SDL_BApp.h index 39fec7782..2d5be1e2b 100644 --- a/src/video/haiku/SDL_BApp.h +++ b/src/video/haiku/SDL_BApp.h @@ -303,7 +303,7 @@ class SDL_BLooper : public BLooper return; } HAIKU_SetKeyState(scancode, state); - SDL_SendKeyboardKey(0, state, HAIKU_GetScancodeFromBeKey(scancode)); + SDL_SendKeyboardKey(0, 0, state, HAIKU_GetScancodeFromBeKey(scancode)); if (state == SDL_PRESSED && SDL_EventEnabled(SDL_EVENT_TEXT_INPUT)) { const int8 *keyUtf8; diff --git a/src/video/ngage/SDL_ngageevents.cpp b/src/video/ngage/SDL_ngageevents.cpp index fecfaff9e..091d6e968 100644 --- a/src/video/ngage/SDL_ngageevents.cpp +++ b/src/video/ngage/SDL_ngageevents.cpp @@ -154,10 +154,10 @@ int HandleWsEvent(SDL_VideoDevice *_this, const TWsEvent &aWsEvent) switch (aWsEvent.Type()) { case EEventKeyDown: /* Key events */ - SDL_SendKeyboardKey(0, SDL_PRESSED, ConvertScancode(_this, aWsEvent.Key()->iScanCode)); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, ConvertScancode(_this, aWsEvent.Key()->iScanCode)); break; case EEventKeyUp: /* Key events */ - SDL_SendKeyboardKey(0, SDL_RELEASED, ConvertScancode(_this, aWsEvent.Key()->iScanCode)); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, ConvertScancode(_this, aWsEvent.Key()->iScanCode)); break; case EEventFocusGained: /* SDL window got focus */ phdata->NGAGE_IsWindowFocused = ETrue; diff --git a/src/video/psp/SDL_pspevents.c b/src/video/psp/SDL_pspevents.c index 8cec093fe..5cf7e66f2 100644 --- a/src/video/psp/SDL_pspevents.c +++ b/src/video/psp/SDL_pspevents.c @@ -90,7 +90,7 @@ void PSP_PumpEvents(SDL_VideoDevice *_this) if (changed) { for (i = 0; i < sizeof(keymap_psp) / sizeof(keymap_psp[0]); i++) { if (changed & keymap_psp[i].id) { - SDL_SendKeyboardKey(0, (keys & keymap_psp[i].id) ? SDL_PRESSED : SDL_RELEASED, SDL_GetScancodeFromKey(keymap_psp[i].sym)); + SDL_SendKeyboardKey(0, 0, (keys & keymap_psp[i].id) ? SDL_PRESSED : SDL_RELEASED, SDL_GetScancodeFromKey(keymap_psp[i].sym)); } } } @@ -113,7 +113,7 @@ void PSP_PumpEvents(SDL_VideoDevice *_this) sym.sym = keymap[raw]; /* not tested */ /* SDL_PrivateKeyboard(pressed?SDL_PRESSED:SDL_RELEASED, &sym); */ - SDL_SendKeyboardKey(0, (keys & keymap_psp[i].id) ? SDL_PRESSED : SDL_RELEASED, SDL_GetScancodeFromKey(keymap[raw])); + SDL_SendKeyboardKey(0, 0, (keys & keymap_psp[i].id) ? SDL_PRESSED : SDL_RELEASED, SDL_GetScancodeFromKey(keymap[raw])); } } } diff --git a/src/video/qnx/SDL_qnxkeyboard.c b/src/video/qnx/SDL_qnxkeyboard.c index 4b091dc5d..bb9546887 100644 --- a/src/video/qnx/SDL_qnxkeyboard.c +++ b/src/video/qnx/SDL_qnxkeyboard.c @@ -125,8 +125,8 @@ void handleKeyboardEvent(screen_event_t event) // FIXME: // Need to handle more key states (such as key combinations). if (val & KEY_DOWN) { - SDL_SendKeyboardKey(0, SDL_PRESSED, scancode); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, scancode); } else { - SDL_SendKeyboardKey(0, SDL_RELEASED, scancode); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, scancode); } } diff --git a/src/video/riscos/SDL_riscosevents.c b/src/video/riscos/SDL_riscosevents.c index ab530115d..ad4a72c9d 100644 --- a/src/video/riscos/SDL_riscosevents.c +++ b/src/video/riscos/SDL_riscosevents.c @@ -58,7 +58,7 @@ void RISCOS_PollKeyboard(SDL_VideoDevice *_this) for (i = 0; i < RISCOS_MAX_KEYS_PRESSED; i++) { if (driverdata->key_pressed[i] != 255) { if ((_kernel_osbyte(129, driverdata->key_pressed[i] ^ 0xff, 0xff) & 0xff) != 255) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_RISCOS_translate_keycode(driverdata->key_pressed[i])); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_RISCOS_translate_keycode(driverdata->key_pressed[i])); driverdata->key_pressed[i] = 255; } } @@ -81,7 +81,7 @@ void RISCOS_PollKeyboard(SDL_VideoDevice *_this) break; default: - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_RISCOS_translate_keycode(key)); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_RISCOS_translate_keycode(key)); /* Record the press so we can detect release later. */ for (i = 0; i < RISCOS_MAX_KEYS_PRESSED; i++) { diff --git a/src/video/uikit/SDL_uikitevents.h b/src/video/uikit/SDL_uikitevents.h index 08c6cbcc6..4754110e5 100644 --- a/src/video/uikit/SDL_uikitevents.h +++ b/src/video/uikit/SDL_uikitevents.h @@ -29,11 +29,9 @@ extern Uint64 UIKit_GetEventTimestamp(NSTimeInterval nsTimestamp); extern void UIKit_PumpEvents(SDL_VideoDevice *_this); extern void SDL_InitGCKeyboard(void); -extern SDL_bool SDL_HasGCKeyboard(void); extern void SDL_QuitGCKeyboard(void); extern void SDL_InitGCMouse(void); -extern SDL_bool SDL_HasGCMouse(void); extern SDL_bool SDL_GCMouseRelativeMode(void); extern void SDL_QuitGCMouse(void); diff --git a/src/video/uikit/SDL_uikitevents.m b/src/video/uikit/SDL_uikitevents.m index 223f5565e..7f640cf02 100644 --- a/src/video/uikit/SDL_uikitevents.m +++ b/src/video/uikit/SDL_uikitevents.m @@ -171,15 +171,17 @@ void UIKit_PumpEvents(SDL_VideoDevice *_this) #ifdef ENABLE_GCKEYBOARD -static SDL_bool keyboard_connected = SDL_FALSE; static id keyboard_connect_observer = nil; static id keyboard_disconnect_observer = nil; static void OnGCKeyboardConnected(GCKeyboard *keyboard) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) { - keyboard_connected = SDL_TRUE; + SDL_KeyboardID keyboardID = (SDL_KeyboardID)(uintptr_t)keyboard; + + SDL_PrivateKeyboardAdded(keyboardID); + keyboard.keyboardInput.keyChangedHandler = ^(GCKeyboardInput *kbrd, GCControllerButtonInput *key, GCKeyCode keyCode, BOOL pressed) { - SDL_SendKeyboardKey(0, pressed ? SDL_PRESSED : SDL_RELEASED, (SDL_Scancode)keyCode); + SDL_SendKeyboardKey(0, keyboardID, pressed ? SDL_PRESSED : SDL_RELEASED, (SDL_Scancode)keyCode); }; dispatch_queue_t queue = dispatch_queue_create("org.libsdl.input.keyboard", DISPATCH_QUEUE_SERIAL); @@ -189,8 +191,11 @@ static void OnGCKeyboardConnected(GCKeyboard *keyboard) API_AVAILABLE(macos(11.0 static void OnGCKeyboardDisconnected(GCKeyboard *keyboard) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) { + SDL_KeyboardID keyboardID = (SDL_KeyboardID)(uintptr_t)keyboard; + + SDL_PrivateKeyboardRemoved(keyboardID); + keyboard.keyboardInput.keyChangedHandler = nil; - keyboard_connected = SDL_FALSE; } void SDL_InitGCKeyboard(void) @@ -222,11 +227,6 @@ void SDL_InitGCKeyboard(void) } } -SDL_bool SDL_HasGCKeyboard(void) -{ - return keyboard_connected; -} - void SDL_QuitGCKeyboard(void) { @autoreleasepool { @@ -256,11 +256,6 @@ void SDL_InitGCKeyboard(void) { } -SDL_bool SDL_HasGCKeyboard(void) -{ - return SDL_FALSE; -} - void SDL_QuitGCKeyboard(void) { } @@ -269,7 +264,6 @@ void SDL_QuitGCKeyboard(void) #ifdef ENABLE_GCMOUSE -static int mice_connected = 0; static id mouse_connect_observer = nil; static id mouse_disconnect_observer = nil; static bool mouse_relative_mode = SDL_FALSE; @@ -291,7 +285,7 @@ static void UpdateScrollDirection(void) /* Couldn't read the preference, assume natural scrolling direction */ naturalScrollDirection = YES; } - if (naturalScrollDirection) { + if (naturalScrollDirection) { mouse_scroll_direction = SDL_MOUSEWHEEL_FLIPPED; } else { mouse_scroll_direction = SDL_MOUSEWHEEL_NORMAL; @@ -323,7 +317,9 @@ static void OnGCMouseButtonChanged(SDL_MouseID mouseID, Uint8 button, BOOL press static void OnGCMouseConnected(GCMouse *mouse) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) { - SDL_MouseID mouseID = mice_connected; + SDL_MouseID mouseID = (SDL_MouseID)(uintptr_t)mouse; + + SDL_PrivateMouseAdded(mouseID); mouse.mouseInput.leftButton.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { OnGCMouseButtonChanged(mouseID, SDL_BUTTON_LEFT, pressed); @@ -370,14 +366,12 @@ static void OnGCMouseConnected(GCMouse *mouse) API_AVAILABLE(macos(11.0), ios(14 dispatch_set_target_queue(queue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)); mouse.handlerQueue = queue; - ++mice_connected; - UpdatePointerLock(); } static void OnGCMouseDisconnected(GCMouse *mouse) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) { - --mice_connected; + SDL_MouseID mouseID = (SDL_MouseID)(uintptr_t)mouse; mouse.mouseInput.mouseMovedHandler = nil; @@ -390,6 +384,8 @@ static void OnGCMouseDisconnected(GCMouse *mouse) API_AVAILABLE(macos(11.0), ios } UpdatePointerLock(); + + SDL_PrivateMouseRemoved(mouseID); } void SDL_InitGCMouse(void) @@ -432,11 +428,6 @@ void SDL_InitGCMouse(void) } } -SDL_bool SDL_HasGCMouse(void) -{ - return (mice_connected > 0); -} - SDL_bool SDL_GCMouseRelativeMode(void) { return mouse_relative_mode; @@ -473,11 +464,6 @@ void SDL_InitGCMouse(void) { } -SDL_bool SDL_HasGCMouse(void) -{ - return SDL_FALSE; -} - SDL_bool SDL_GCMouseRelativeMode(void) { return SDL_FALSE; diff --git a/src/video/uikit/SDL_uikitview.m b/src/video/uikit/SDL_uikitview.m index 232be71b9..3bd4d4694 100644 --- a/src/video/uikit/SDL_uikitview.m +++ b/src/video/uikit/SDL_uikitview.m @@ -229,7 +229,7 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick; #if !defined(SDL_PLATFORM_TVOS) && defined(__IPHONE_13_4) if (@available(iOS 13.4, *)) { if (touch.type == UITouchTypeIndirectPointer) { - if (!SDL_HasGCMouse()) { + if (!SDL_HasMouse()) { int i; for (i = 1; i <= MAX_MOUSE_BUTTONS; ++i) { @@ -285,7 +285,7 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick; #if !defined(SDL_PLATFORM_TVOS) && defined(__IPHONE_13_4) if (@available(iOS 13.4, *)) { if (touch.type == UITouchTypeIndirectPointer) { - if (!SDL_HasGCMouse()) { + if (!SDL_HasMouse()) { int i; for (i = 1; i <= MAX_MOUSE_BUTTONS; ++i) { @@ -411,10 +411,10 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick; - (void)pressesBegan:(NSSet *)presses withEvent:(UIPressesEvent *)event { - if (!SDL_HasGCKeyboard()) { + if (!SDL_HasKeyboard()) { for (UIPress *press in presses) { SDL_Scancode scancode = [self scancodeFromPress:press]; - SDL_SendKeyboardKey(UIKit_GetEventTimestamp([event timestamp]), SDL_PRESSED, scancode); + SDL_SendKeyboardKey(UIKit_GetEventTimestamp([event timestamp]), 0, SDL_PRESSED, scancode); } } if (SDL_TextInputActive()) { @@ -424,10 +424,10 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick; - (void)pressesEnded:(NSSet *)presses withEvent:(UIPressesEvent *)event { - if (!SDL_HasGCKeyboard()) { + if (!SDL_HasKeyboard()) { for (UIPress *press in presses) { SDL_Scancode scancode = [self scancodeFromPress:press]; - SDL_SendKeyboardKey(UIKit_GetEventTimestamp([event timestamp]), SDL_RELEASED, scancode); + SDL_SendKeyboardKey(UIKit_GetEventTimestamp([event timestamp]), 0, SDL_RELEASED, scancode); } } if (SDL_TextInputActive()) { @@ -437,10 +437,10 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick; - (void)pressesCancelled:(NSSet *)presses withEvent:(UIPressesEvent *)event { - if (!SDL_HasGCKeyboard()) { + if (!SDL_HasKeyboard()) { for (UIPress *press in presses) { SDL_Scancode scancode = [self scancodeFromPress:press]; - SDL_SendKeyboardKey(UIKit_GetEventTimestamp([event timestamp]), SDL_RELEASED, scancode); + SDL_SendKeyboardKey(UIKit_GetEventTimestamp([event timestamp]), 0, SDL_RELEASED, scancode); } } if (SDL_TextInputActive()) { diff --git a/src/video/vita/SDL_vitakeyboard.c b/src/video/vita/SDL_vitakeyboard.c index 255c916c8..64108b1e7 100644 --- a/src/video/vita/SDL_vitakeyboard.c +++ b/src/video/vita/SDL_vitakeyboard.c @@ -62,40 +62,40 @@ void VITA_PollKeyboard(void) // The k_report only reports the state of the LED if (k_reports[numReports - 1].modifiers[1] & 0x1) { if (!(locks & 0x1)) { - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_NUMLOCKCLEAR); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_NUMLOCKCLEAR); locks |= 0x1; } } else { if (locks & 0x1) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_NUMLOCKCLEAR); - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_NUMLOCKCLEAR); - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_NUMLOCKCLEAR); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_NUMLOCKCLEAR); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_NUMLOCKCLEAR); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_NUMLOCKCLEAR); locks &= ~0x1; } } if (k_reports[numReports - 1].modifiers[1] & 0x2) { if (!(locks & 0x2)) { - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_CAPSLOCK); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_CAPSLOCK); locks |= 0x2; } } else { if (locks & 0x2) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_CAPSLOCK); - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_CAPSLOCK); - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_CAPSLOCK); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_CAPSLOCK); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_CAPSLOCK); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_CAPSLOCK); locks &= ~0x2; } } if (k_reports[numReports - 1].modifiers[1] & 0x4) { if (!(locks & 0x4)) { - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_SCROLLLOCK); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_SCROLLLOCK); locks |= 0x4; } } else { if (locks & 0x4) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_SCROLLLOCK); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_SCROLLLOCK); locks &= ~0x4; } } @@ -105,58 +105,58 @@ void VITA_PollKeyboard(void) if (changed_modifiers & 0x01) { if (prev_modifiers & 0x01) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_LCTRL); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_LCTRL); } else { - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_LCTRL); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_LCTRL); } } if (changed_modifiers & 0x02) { if (prev_modifiers & 0x02) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_LSHIFT); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_LSHIFT); } else { - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_LSHIFT); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_LSHIFT); } } if (changed_modifiers & 0x04) { if (prev_modifiers & 0x04) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_LALT); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_LALT); } else { - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_LALT); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_LALT); } } if (changed_modifiers & 0x08) { if (prev_modifiers & 0x08) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_LGUI); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_LGUI); } else { - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_LGUI); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_LGUI); } } if (changed_modifiers & 0x10) { if (prev_modifiers & 0x10) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_RCTRL); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_RCTRL); } else { - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_RCTRL); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_RCTRL); } } if (changed_modifiers & 0x20) { if (prev_modifiers & 0x20) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_RSHIFT); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_RSHIFT); } else { - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_RSHIFT); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_RSHIFT); } } if (changed_modifiers & 0x40) { if (prev_modifiers & 0x40) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_RALT); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_RALT); } else { - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_RALT); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_RALT); } } if (changed_modifiers & 0x80) { if (prev_modifiers & 0x80) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_RGUI); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_RGUI); } else { - SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_RGUI); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, SDL_SCANCODE_RGUI); } } } @@ -170,10 +170,10 @@ void VITA_PollKeyboard(void) if (keyCode != prev_keys[i]) { if (prev_keys[i]) { - SDL_SendKeyboardKey(0, SDL_RELEASED, prev_keys[i]); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, prev_keys[i]); } if (keyCode) { - SDL_SendKeyboardKey(0, SDL_PRESSED, keyCode); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, keyCode); } prev_keys[i] = keyCode; } diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 00f10a756..a1f2140f5 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -264,7 +264,7 @@ static SDL_bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, U while (elapsed >= repeat_info->next_repeat_ns) { if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) { const Uint64 timestamp = repeat_info->wl_press_time_ns + repeat_info->next_repeat_ns; - SDL_SendKeyboardKeyIgnoreModifiers(Wayland_GetEventTimestamp(timestamp), SDL_PRESSED, repeat_info->scancode); + SDL_SendKeyboardKeyIgnoreModifiers(Wayland_GetEventTimestamp(timestamp), 0, SDL_PRESSED, repeat_info->scancode); } if (repeat_info->text[0]) { SDL_SendKeyboardText(repeat_info->text); @@ -1483,7 +1483,7 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, case SDLK_RGUI: case SDLK_MODE: Wayland_HandleModifierKeys(input, scancode, SDL_TRUE); - SDL_SendKeyboardKeyIgnoreModifiers(0, SDL_PRESSED, scancode); + SDL_SendKeyboardKeyIgnoreModifiers(0, 0, SDL_PRESSED, scancode); break; default: break; @@ -1618,7 +1618,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, if (!handled_by_ime) { scancode = Wayland_get_scancode_from_key(input, key + 8); Wayland_HandleModifierKeys(input, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED); - SDL_SendKeyboardKeyIgnoreModifiers(Wayland_GetKeyboardTimestamp(input, time), state == WL_KEYBOARD_KEY_STATE_PRESSED ? SDL_PRESSED : SDL_RELEASED, scancode); + SDL_SendKeyboardKeyIgnoreModifiers(Wayland_GetKeyboardTimestamp(input, time), 0, state == WL_KEYBOARD_KEY_STATE_PRESSED ? SDL_PRESSED : SDL_RELEASED, scancode); } if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 14a35cabe..efb63b922 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -27,6 +27,7 @@ #include "../../events/SDL_touch_c.h" #include "../../events/scancodes_windows.h" #include "../../main/SDL_main_callbacks.h" +#include "../../core/windows/SDL_hid.h" /* Dropfile support */ #include @@ -503,9 +504,9 @@ WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) } if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) { - SDL_SendKeyboardKey(0, SDL_PRESSED, scanCode); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, scanCode); } else { - SDL_SendKeyboardKey(0, SDL_RELEASED, scanCode); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, scanCode); /* If the key was down prior to our hook being installed, allow the key up message to pass normally the first time. This ensures other @@ -529,11 +530,7 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_WindowData *data, HAND return; } - /* We do all of our mouse state checking against mouse ID 0 - * We would only use the actual hDevice if we were tracking - * all mouse motion independently, and never using mouse ID 0. - */ - mouseID = 0; /* (SDL_MouseID)(uintptr_t)inp.header.hDevice; */ + mouseID = (SDL_MouseID)(uintptr_t)hDevice; if ((rawmouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) { if (rawmouse->lLastX || rawmouse->lLastY) { @@ -698,8 +695,130 @@ void WIN_PollRawMouseInput(void) #endif /*!defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)*/ -LRESULT CALLBACK -WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +static void AddDeviceID(Uint32 deviceID, Uint32 **list, int *count) +{ + int new_count = (*count + 1); + Uint32 *new_list = (Uint32 *)SDL_realloc(*list, new_count * sizeof(*new_list)); + if (!new_list) { + /* Oh well, we'll drop this one */ + return; + } + new_list[new_count - 1] = deviceID; + + *count = new_count; + *list = new_list; +} + +static SDL_bool HasDeviceID(Uint32 deviceID, Uint32 *list, int count) +{ + for (int i = 0; i < count; ++i) { + if (deviceID == list[i]) { + return SDL_TRUE; + } + } + return SDL_FALSE; +} + +void WIN_CheckKeyboardAndMouseHotplug(SDL_bool initial_check) +{ + PRAWINPUTDEVICELIST raw_devices = NULL; + UINT raw_device_count = 0; + int old_keyboard_count = 0; + SDL_KeyboardID *old_keyboards = NULL; + int new_keyboard_count = 0; + SDL_KeyboardID *new_keyboards = NULL; + int old_mouse_count = 0; + SDL_MouseID *old_mice = NULL; + int new_mouse_count = 0; + SDL_MouseID *new_mice = NULL; + + /* Check to see if anything has changed */ + static Uint64 s_last_device_change; + Uint64 last_device_change = WIN_GetLastDeviceNotification(); + if (!initial_check && last_device_change == s_last_device_change) { + return; + } + s_last_device_change = last_device_change; + + if ((GetRawInputDeviceList(NULL, &raw_device_count, sizeof(RAWINPUTDEVICELIST)) == -1) || (!raw_device_count)) { + return; /* oh well. */ + } + + raw_devices = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * raw_device_count); + if (!raw_devices) { + return; /* oh well. */ + } + + raw_device_count = GetRawInputDeviceList(raw_devices, &raw_device_count, sizeof(RAWINPUTDEVICELIST)); + if (raw_device_count == (UINT)-1) { + SDL_free(raw_devices); + raw_devices = NULL; + return; /* oh well. */ + } + + for (UINT i = 0; i < raw_device_count; i++) { + RID_DEVICE_INFO rdi; + char devName[MAX_PATH] = { 0 }; + UINT rdiSize = sizeof(rdi); + UINT nameSize = SDL_arraysize(devName); + int vendor = 0, product = 0; + + rdi.cbSize = sizeof(rdi); + + if (GetRawInputDeviceInfoA(raw_devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) == ((UINT)-1) || + GetRawInputDeviceInfoA(raw_devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) == ((UINT)-1)) { + continue; + } + + SDL_sscanf(devName, "\\\\?\\HID#VID_%X&PID_%X&", &vendor, &product); + + switch (raw_devices[i].dwType) { + case RIM_TYPEKEYBOARD: + if (SDL_IsKeyboard((Uint16)vendor, (Uint16)product, rdi.keyboard.dwNumberOfKeysTotal)) { + AddDeviceID((Uint32)(uintptr_t)raw_devices[i].hDevice, &new_keyboards, &new_keyboard_count); + } + break; + case RIM_TYPEMOUSE: + if (SDL_IsMouse((Uint16)vendor, (Uint16)product)) { + AddDeviceID((Uint32)(uintptr_t)raw_devices[i].hDevice, &new_mice, &new_mouse_count); + } + break; + default: + break; + } + } + SDL_free(raw_devices); + + old_keyboards = SDL_GetKeyboards(&old_keyboard_count); + for (int i = old_keyboard_count; i--;) { + if (!HasDeviceID(old_keyboards[i], new_keyboards, new_keyboard_count)) { + SDL_PrivateKeyboardRemoved(old_keyboards[i]); + } + } + for (int i = 0; i < new_keyboard_count; ++i) { + if (!HasDeviceID(new_keyboards[i], old_keyboards, old_keyboard_count)) { + SDL_PrivateKeyboardAdded(new_keyboards[i]); + } + } + SDL_free(new_keyboards); + SDL_free(old_keyboards); + + old_mice = SDL_GetMice(&old_mouse_count); + for (int i = old_mouse_count; i--;) { + if (!HasDeviceID(old_mice[i], new_mice, new_mouse_count)) { + SDL_PrivateMouseRemoved(old_mice[i]); + } + } + for (int i = 0; i < new_mouse_count; ++i) { + if (!HasDeviceID(new_mice[i], old_mice, old_mouse_count)) { + SDL_PrivateMouseAdded(new_mice[i]); + } + } + SDL_free(new_mice); + SDL_free(old_mice); +} + +LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { SDL_WindowData *data; LRESULT returnCode = -1; @@ -923,7 +1042,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } if (code != SDL_SCANCODE_UNKNOWN) { - SDL_SendKeyboardKey(WIN_GetEventTimestamp(), SDL_PRESSED, code); + SDL_SendKeyboardKey(WIN_GetEventTimestamp(), 0, SDL_PRESSED, code); } } @@ -939,9 +1058,9 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (code != SDL_SCANCODE_UNKNOWN) { if (code == SDL_SCANCODE_PRINTSCREEN && keyboardState[code] == SDL_RELEASED) { - SDL_SendKeyboardKey(WIN_GetEventTimestamp(), SDL_PRESSED, code); + SDL_SendKeyboardKey(WIN_GetEventTimestamp(), 0, SDL_PRESSED, code); } - SDL_SendKeyboardKey(WIN_GetEventTimestamp(), SDL_RELEASED, code); + SDL_SendKeyboardKey(WIN_GetEventTimestamp(), 0, SDL_RELEASED, code); } } returnCode = 0; @@ -1808,10 +1927,10 @@ void WIN_PumpEvents(SDL_VideoDevice *_this) and if we think a key is pressed when Windows doesn't, unstick it in SDL's state. */ keystate = SDL_GetKeyboardState(NULL); if ((keystate[SDL_SCANCODE_LSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_LSHIFT) & 0x8000)) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_LSHIFT); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_LSHIFT); } if ((keystate[SDL_SCANCODE_RSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_RSHIFT) & 0x8000)) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_RSHIFT); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_RSHIFT); } /* The Windows key state gets lost when using Windows+Space or Windows+G shortcuts and @@ -1820,10 +1939,10 @@ void WIN_PumpEvents(SDL_VideoDevice *_this) focusWindow = SDL_GetKeyboardFocus(); if (!focusWindow || !(focusWindow->flags & SDL_WINDOW_KEYBOARD_GRABBED)) { if ((keystate[SDL_SCANCODE_LGUI] == SDL_PRESSED) && !(GetKeyState(VK_LWIN) & 0x8000)) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_LGUI); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_LGUI); } if ((keystate[SDL_SCANCODE_RGUI] == SDL_PRESSED) && !(GetKeyState(VK_RWIN) & 0x8000)) { - SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_RGUI); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, SDL_SCANCODE_RGUI); } } @@ -1832,6 +1951,9 @@ void WIN_PumpEvents(SDL_VideoDevice *_this) /* Update mouse capture */ WIN_UpdateMouseCapture(); + + WIN_CheckKeyboardAndMouseHotplug(SDL_FALSE); + #endif /*!defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)*/ #ifdef SDL_PLATFORM_GDK diff --git a/src/video/windows/SDL_windowsevents.h b/src/video/windows/SDL_windowsevents.h index 77f1dd464..30ab7c2ab 100644 --- a/src/video/windows/SDL_windowsevents.h +++ b/src/video/windows/SDL_windowsevents.h @@ -31,6 +31,7 @@ extern LRESULT CALLBACK WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lP extern LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); extern void WIN_PollRawMouseInput(void); +extern void WIN_CheckKeyboardAndMouseHotplug(SDL_bool initial_check); extern void WIN_PumpEvents(SDL_VideoDevice *_this); extern void WIN_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window); extern int WIN_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS); diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index cb5f0e035..5b5af7572 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -28,6 +28,7 @@ #include "../SDL_sysvideo.h" #include "../SDL_pixels_c.h" #include "../../SDL_hints_c.h" +#include "../../core/windows/SDL_hid.h" #include "SDL_windowsvideo.h" #include "SDL_windowsframebuffer.h" @@ -455,6 +456,8 @@ int WIN_VideoInit(SDL_VideoDevice *_this) WIN_InitKeyboard(_this); WIN_InitMouse(_this); + WIN_InitDeviceNotification(); + WIN_CheckKeyboardAndMouseHotplug(SDL_TRUE); #endif SDL_AddHintCallback(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, UpdateWindowsEnableMessageLoop, NULL); @@ -472,6 +475,7 @@ void WIN_VideoQuit(SDL_VideoDevice *_this) { #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) WIN_QuitModes(_this); + WIN_QuitDeviceNotification(); WIN_QuitKeyboard(_this); WIN_QuitMouse(_this); #endif diff --git a/src/video/winrt/SDL_winrtkeyboard.cpp b/src/video/winrt/SDL_winrtkeyboard.cpp index f210fab4f..e6e4c3f98 100644 --- a/src/video/winrt/SDL_winrtkeyboard.cpp +++ b/src/video/winrt/SDL_winrtkeyboard.cpp @@ -77,7 +77,7 @@ void WINRT_ProcessAcceleratorKeyActivated(Windows::UI::Core::AcceleratorKeyEvent } code = WINRT_TranslateKeycode(args->VirtualKey, args->KeyStatus); - SDL_SendKeyboardKey(0, state, code); + SDL_SendKeyboardKey(0, 0, state, code); } void WINRT_ProcessCharacterReceivedEvent(SDL_Window *window, Windows::UI::Core::CharacterReceivedEventArgs ^ args) diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index e995cc323..30f520a3a 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -437,13 +437,13 @@ void X11_ReconcileKeyboardState(SDL_VideoDevice *_this) case SDLK_LGUI: case SDLK_RGUI: case SDLK_MODE: - SDL_SendKeyboardKey(0, SDL_PRESSED, scancode); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, scancode); break; default: break; } } else if (!x11KeyPressed && sdlKeyPressed) { - SDL_SendKeyboardKey(0, SDL_RELEASED, scancode); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, scancode); } } } @@ -957,9 +957,9 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) videodata->filter_time = xevent->xkey.time; if (orig_event_type == KeyPress) { - SDL_SendKeyboardKey(0, SDL_PRESSED, scancode); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, scancode); } else { - SDL_SendKeyboardKey(0, SDL_RELEASED, scancode); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, scancode); } #endif } @@ -1262,7 +1262,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) if (xevent->type == KeyPress) { /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */ if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) { - SDL_SendKeyboardKey(0, SDL_PRESSED, videodata->key_layout[keycode]); + SDL_SendKeyboardKey(0, 0, SDL_PRESSED, videodata->key_layout[keycode]); } if (*text) { SDL_SendKeyboardText(text); @@ -1272,7 +1272,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) /* We're about to get a repeated key down, ignore the key up */ break; } - SDL_SendKeyboardKey(0, SDL_RELEASED, videodata->key_layout[keycode]); + SDL_SendKeyboardKey(0, 0, SDL_RELEASED, videodata->key_layout[keycode]); } } diff --git a/test/testhotplug.c b/test/testhotplug.c index 076177446..8f09d7dbf 100644 --- a/test/testhotplug.c +++ b/test/testhotplug.c @@ -20,6 +20,8 @@ int main(int argc, char *argv[]) { + int num_keyboards = 0; + int num_mice = 0; int num_joysticks = 0; SDL_Joystick *joystick = NULL; SDL_Haptic *haptic = NULL; @@ -78,12 +80,18 @@ int main(int argc, char *argv[]) //SDL_CreateWindow("Dummy", 128, 128, 0); */ + SDL_free(SDL_GetKeyboards(&num_keyboards)); + SDL_Log("There are %d keyboards at startup\n", num_keyboards); + + SDL_free(SDL_GetMice(&num_mice)); + SDL_Log("There are %d mice at startup\n", num_mice); + SDL_free(SDL_GetJoysticks(&num_joysticks)); SDL_Log("There are %d joysticks at startup\n", num_joysticks); + if (enable_haptic) { int num_haptics; - SDL_HapticID *haptics = SDL_GetHaptics(&num_haptics); - SDL_free(haptics); + SDL_free(SDL_GetHaptics(&num_haptics)); SDL_Log("There are %d haptic devices at startup\n", num_haptics); } @@ -94,6 +102,18 @@ int main(int argc, char *argv[]) case SDL_EVENT_QUIT: keepGoing = SDL_FALSE; break; + case SDL_EVENT_KEYBOARD_ADDED: + SDL_Log("Keyboard added : %" SDL_PRIu32 "\n", event.kdevice.which); + break; + case SDL_EVENT_KEYBOARD_REMOVED: + SDL_Log("Keyboard removed: %" SDL_PRIu32 "\n", event.kdevice.which); + break; + case SDL_EVENT_MOUSE_ADDED: + SDL_Log("Mouse added : %" SDL_PRIu32 "\n", event.mdevice.which); + break; + case SDL_EVENT_MOUSE_REMOVED: + SDL_Log("Mouse removed: %" SDL_PRIu32 "\n", event.mdevice.which); + break; case SDL_EVENT_JOYSTICK_ADDED: if (joystick) { SDL_Log("Only one joystick supported by this test\n");