From c2a910ab026bb685557eee3187842bc98a1c52b8 Mon Sep 17 00:00:00 2001
From: Mike Egger <[EMAIL REDACTED]>
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 0c06266a87ec1..76efb9164e485 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 2c5181c6e8083..4c770a8630841 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 c76482ac7cbf4..cada2b6d63a68 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 0523a8115bdad..2ede2eba445b0 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 056a69883acf9..c6997dbf658a5 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 a09066b5620f3..fb34acfb23a2a 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;