From c2a910ab026bb685557eee3187842bc98a1c52b8 Mon Sep 17 00:00:00 2001 From: Mike Egger Date: Mon, 9 Mar 2026 00:11:33 +0100 Subject: [PATCH] windows: support flag RIDEV_INPUTSINK in raw input (#15182) (cherry picked from commit ae3ae4ba4407484f8c39b160cde95e39b55be778) --- include/SDL3/SDL_hints.h | 17 +++++++++++++++++ src/video/windows/SDL_windowsevents.c | 3 ++- src/video/windows/SDL_windowsrawinput.c | 18 +++++++++++++++++- src/video/windows/SDL_windowsrawinput.h | 1 + src/video/windows/SDL_windowsvideo.c | 9 +++++++++ src/video/windows/SDL_windowsvideo.h | 1 + 6 files changed, 47 insertions(+), 2 deletions(-) diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index 0c06266a87..76efb9164e 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -4518,6 +4518,23 @@ extern "C" { */ #define SDL_HINT_WINDOWS_RAW_KEYBOARD_EXCLUDE_HOTKEYS "SDL_WINDOWS_RAW_KEYBOARD_EXCLUDE_HOTKEYS" +/** + * A variable controlling whether the RIDEV_INPUTSINK flag is set when + * enabling Windows raw keyboard events. + * + * This enables the window to still receive input even if not in foreground. + * + * Focused windows that receive text input will still prevent input events from triggering. + * + * - "0": Input is not received when not in focus or foreground. (default) + * - "1": Input will be received even when not in focus or foreground. + * + * This hint can be set anytime. + * + * \since This hint is available since SDL 3.4.4. + */ +#define SDL_HINT_WINDOWS_RAW_KEYBOARD_INPUTSINK "SDL_WINDOWS_RAW_KEYBOARD_INPUTSINK" + /** * A variable controlling whether SDL uses Kernel Semaphores on Windows. * diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 2c5181c6e8..4c770a8630 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -774,7 +774,8 @@ static void WIN_HandleRawKeyboardInput(Uint64 timestamp, SDL_VideoData *data, HA if (down) { SDL_Window *focus = SDL_GetKeyboardFocus(); - if (!focus || focus->text_input_active) { + // With input sink flag we want to receive input even if not focused + if ((!data->raw_keyboard_flag_inputsink && !focus) || (focus && focus->text_input_active)) { return; } } diff --git a/src/video/windows/SDL_windowsrawinput.c b/src/video/windows/SDL_windowsrawinput.c index c76482ac7c..cada2b6d63 100644 --- a/src/video/windows/SDL_windowsrawinput.c +++ b/src/video/windows/SDL_windowsrawinput.c @@ -35,6 +35,7 @@ #define ENABLE_RAW_MOUSE_INPUT 0x01 #define ENABLE_RAW_KEYBOARD_INPUT 0x02 #define RAW_KEYBOARD_FLAG_NOHOTKEYS 0x04 +#define RAW_KEYBOARD_FLAG_INPUTSINK 0x08 typedef struct { @@ -85,6 +86,9 @@ static DWORD WINAPI WIN_RawInputThread(LPVOID param) if (data->flags & RAW_KEYBOARD_FLAG_NOHOTKEYS) { devices[count].dwFlags |= RIDEV_NOHOTKEYS; } + if (data->flags & RAW_KEYBOARD_FLAG_INPUTSINK) { + devices[count].dwFlags |= RIDEV_INPUTSINK; + } devices[count].hwndTarget = window; ++count; } @@ -215,6 +219,9 @@ static bool WIN_UpdateRawInputEnabled(SDL_VideoDevice *_this) if (data->raw_keyboard_flag_nohotkeys) { flags |= RAW_KEYBOARD_FLAG_NOHOTKEYS; } + if (data->raw_keyboard_flag_inputsink) { + flags |= RAW_KEYBOARD_FLAG_INPUTSINK; + } } if (flags != data->raw_input_enabled) { if (WIN_SetRawInputEnabled(_this, flags)) { @@ -263,7 +270,8 @@ bool WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, bool enabled) } typedef enum WIN_RawKeyboardFlag { - NOHOTKEYS + NOHOTKEYS, + INPUTSINK, } WIN_RawKeyboardFlag; static bool WIN_SetRawKeyboardFlag(SDL_VideoDevice *_this, WIN_RawKeyboardFlag flag, bool enabled) @@ -274,6 +282,9 @@ static bool WIN_SetRawKeyboardFlag(SDL_VideoDevice *_this, WIN_RawKeyboardFlag f case NOHOTKEYS: data->raw_keyboard_flag_nohotkeys = enabled; break; + case INPUTSINK: + data->raw_keyboard_flag_inputsink = enabled; + break; default: return false; } @@ -290,6 +301,11 @@ bool WIN_SetRawKeyboardFlag_NoHotkeys(SDL_VideoDevice *_this, bool enabled) return WIN_SetRawKeyboardFlag(_this, NOHOTKEYS, enabled); } +bool WIN_SetRawKeyboardFlag_Inputsink(SDL_VideoDevice *_this, bool enabled) +{ + return WIN_SetRawKeyboardFlag(_this, INPUTSINK, enabled); +} + #else bool WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, bool enabled) diff --git a/src/video/windows/SDL_windowsrawinput.h b/src/video/windows/SDL_windowsrawinput.h index 0523a8115b..2ede2eba44 100644 --- a/src/video/windows/SDL_windowsrawinput.h +++ b/src/video/windows/SDL_windowsrawinput.h @@ -26,5 +26,6 @@ extern bool WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, bool enabled); extern bool WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, bool enabled); extern bool WIN_SetRawKeyboardFlag_NoHotkeys(SDL_VideoDevice *_this, bool enabled); +extern bool WIN_SetRawKeyboardFlag_Inputsink(SDL_VideoDevice *_this, bool enabled); #endif // SDL_windowsrawinput_h_ diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index 056a69883a..c6997dbf65 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -156,6 +156,13 @@ static void SDLCALL UpdateWindowsRawKeyboardNoHotkeys(void *userdata, const char WIN_SetRawKeyboardFlag_NoHotkeys(_this, enabled); } +static void SDLCALL UpdateWindowsRawKeyboardInputsink(void *userdata, const char *name, const char *oldValue, const char *newValue) +{ + SDL_VideoDevice *_this = (SDL_VideoDevice *)userdata; + bool enabled = SDL_GetStringBoolean(newValue, false); + WIN_SetRawKeyboardFlag_Inputsink(_this, enabled); +} + static void SDLCALL UpdateWindowsEnableMessageLoop(void *userdata, const char *name, const char *oldValue, const char *newValue) { g_WindowsEnableMessageLoop = SDL_GetStringBoolean(newValue, true); @@ -640,6 +647,7 @@ static bool WIN_VideoInit(SDL_VideoDevice *_this) SDL_AddHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD, UpdateWindowsRawKeyboard, _this); SDL_AddHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD_EXCLUDE_HOTKEYS, UpdateWindowsRawKeyboardNoHotkeys, _this); + SDL_AddHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD_INPUTSINK, UpdateWindowsRawKeyboardInputsink, _this); SDL_AddHintCallback(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, UpdateWindowsEnableMessageLoop, NULL); SDL_AddHintCallback(SDL_HINT_WINDOWS_ENABLE_MENU_MNEMONICS, UpdateWindowsEnableMenuMnemonics, NULL); SDL_AddHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL); @@ -658,6 +666,7 @@ void WIN_VideoQuit(SDL_VideoDevice *_this) SDL_RemoveHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD, UpdateWindowsRawKeyboard, _this); SDL_RemoveHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD_EXCLUDE_HOTKEYS, UpdateWindowsRawKeyboardNoHotkeys, _this); + SDL_RemoveHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD_INPUTSINK, UpdateWindowsRawKeyboardInputsink, _this); SDL_RemoveHintCallback(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, UpdateWindowsEnableMessageLoop, NULL); SDL_RemoveHintCallback(SDL_HINT_WINDOWS_ENABLE_MENU_MNEMONICS, UpdateWindowsEnableMenuMnemonics, NULL); SDL_RemoveHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL); diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h index a09066b562..fb34acfb23 100644 --- a/src/video/windows/SDL_windowsvideo.h +++ b/src/video/windows/SDL_windowsvideo.h @@ -594,6 +594,7 @@ struct SDL_VideoData bool raw_mouse_enabled; bool raw_keyboard_enabled; bool raw_keyboard_flag_nohotkeys; + bool raw_keyboard_flag_inputsink; bool pending_E1_key_sequence; Uint32 raw_input_enabled; SDL_PenID raw_input_fake_pen_id;