From 089b8627321d187660d61d8cb6ffb65ffb9dc376 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 24 Jun 2026 12:03:06 -0700 Subject: [PATCH] Added SDL_HINT_WINDOWS_RAW_MOUSE_NOLEGACY --- include/SDL3/SDL_hints.h | 15 ++++ src/test/SDL_test_common.c | 5 ++ src/video/windows/SDL_windowsrawinput.c | 92 +++++++++++++------------ src/video/windows/SDL_windowsrawinput.h | 1 + src/video/windows/SDL_windowsvideo.c | 8 +++ src/video/windows/SDL_windowsvideo.h | 1 + 6 files changed, 79 insertions(+), 43 deletions(-) diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index bc23b58add..b156fed663 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -4734,6 +4734,21 @@ extern "C" { */ #define SDL_HINT_WINDOWS_RAW_KEYBOARD_INPUTSINK "SDL_WINDOWS_RAW_KEYBOARD_INPUTSINK" +/** + * A variable controlling whether the RIDEV_NOLEGACY flag is set when + * enabling Windows raw mouse events. + * + * If RIDEV_NOLEGACY is set, then Windows mouse events will not be sent for mouse motion while relative mode is enabled. This improves performance when players are using high DPI mice, but should be disabled while showing custom assert dialogs in your application code. + * + * - "0": Windows mouse events will be generated while relative motion is enabled. (default) + * - "1": Windows mouse events will not be generated while relative motion is enabled. + * + * This hint can be set anytime. + * + * \since This hint is available since SDL 3.6.0. + */ +#define SDL_HINT_WINDOWS_RAW_MOUSE_NOLEGACY "SDL_WINDOWS_RAW_MOUSE_NOLEGACY" + /** * A variable controlling whether SDL uses Kernel Semaphores on Windows. * diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index 6e7b12f048..17539f2d52 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -2690,6 +2690,11 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const FullscreenTo(state, 1, event->key.windowID); } break; + case SDLK_9: + if (withControl) { + SDL_assert_always(!"Test Assertion"); + } + break; case SDLK_ESCAPE: return SDL_APP_SUCCESS; default: diff --git a/src/video/windows/SDL_windowsrawinput.c b/src/video/windows/SDL_windowsrawinput.c index c5f193c73f..1903b1ef84 100644 --- a/src/video/windows/SDL_windowsrawinput.c +++ b/src/video/windows/SDL_windowsrawinput.c @@ -33,9 +33,10 @@ #include "../../thread/SDL_systhread.h" #define ENABLE_RAW_MOUSE_INPUT 0x01 -#define ENABLE_RAW_KEYBOARD_INPUT 0x02 -#define RAW_KEYBOARD_FLAG_NOHOTKEYS 0x04 -#define RAW_KEYBOARD_FLAG_INPUTSINK 0x08 +#define RAW_MOUSE_FLAG_NOLEGACY 0x02 +#define ENABLE_RAW_KEYBOARD_INPUT 0x10 +#define RAW_KEYBOARD_FLAG_NOHOTKEYS 0x20 +#define RAW_KEYBOARD_FLAG_INPUTSINK 0x40 typedef struct { @@ -93,13 +94,19 @@ static bool UpdateRawInputDeviceFlags(HWND window, Uint32 last_flags, Uint32 new RAWINPUTDEVICE devices[2] = { 0 }; UINT count = 0; - if ((new_flags & ENABLE_RAW_MOUSE_INPUT) != (last_flags & ENABLE_RAW_MOUSE_INPUT)) { + const Uint32 old_mouse_flags = last_flags & (ENABLE_RAW_MOUSE_INPUT | RAW_MOUSE_FLAG_NOLEGACY); + const Uint32 new_mouse_flags = new_flags & (ENABLE_RAW_MOUSE_INPUT | RAW_MOUSE_FLAG_NOLEGACY); + + if (old_mouse_flags != new_mouse_flags) { devices[count].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP; devices[count].usUsage = USB_USAGE_GENERIC_MOUSE; if (new_flags & ENABLE_RAW_MOUSE_INPUT) { - devices[count].dwFlags = RIDEV_NOLEGACY; + devices[count].dwFlags = 0; devices[count].hwndTarget = window; + if (new_mouse_flags & RAW_MOUSE_FLAG_NOLEGACY) { + devices[count].dwFlags |= RIDEV_NOLEGACY; + } } else { devices[count].dwFlags = RIDEV_REMOVE; devices[count].hwndTarget = NULL; @@ -121,7 +128,6 @@ static bool UpdateRawInputDeviceFlags(HWND window, Uint32 last_flags, Uint32 new if (new_kb_flags & RAW_KEYBOARD_FLAG_NOHOTKEYS) { devices[count].dwFlags |= RIDEV_NOHOTKEYS; } - if (new_kb_flags & RAW_KEYBOARD_FLAG_INPUTSINK) { devices[count].dwFlags |= RIDEV_INPUTSINK; } @@ -241,17 +247,22 @@ static bool WIN_UpdateRawInputEnabled(SDL_VideoDevice *_this) SDL_VideoData *data = _this->internal; Uint32 desired_flags = 0; - if (data->raw_mouse_enabled) { - desired_flags |= ENABLE_RAW_MOUSE_INPUT; - } - if (data->raw_keyboard_enabled) { - desired_flags |= ENABLE_RAW_KEYBOARD_INPUT; - } - if (data->raw_keyboard_flag_nohotkeys) { - desired_flags |= RAW_KEYBOARD_FLAG_NOHOTKEYS; - } - if (data->raw_keyboard_flag_inputsink) { - desired_flags |= RAW_KEYBOARD_FLAG_INPUTSINK; + if (!data->gameinput_context) { + if (data->raw_mouse_enabled) { + desired_flags |= ENABLE_RAW_MOUSE_INPUT; + if (data->raw_mouse_flag_nolegacy) { + desired_flags |= RAW_MOUSE_FLAG_NOLEGACY; + } + } + if (data->raw_keyboard_enabled) { + desired_flags |= ENABLE_RAW_KEYBOARD_INPUT; + if (data->raw_keyboard_flag_nohotkeys) { + desired_flags |= RAW_KEYBOARD_FLAG_NOHOTKEYS; + } + if (data->raw_keyboard_flag_inputsink) { + desired_flags |= RAW_KEYBOARD_FLAG_INPUTSINK; + } + } } if (desired_flags == SDL_GetAtomicU32(&thread_data.flags)) { @@ -336,6 +347,15 @@ bool WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, bool enabled) return true; } +bool WIN_SetRawMouseFlag_NoLegacy(SDL_VideoDevice *_this, bool enabled) +{ + SDL_VideoData *data = _this->internal; + + data->raw_mouse_flag_nolegacy = enabled; + + return WIN_UpdateRawInputEnabled(_this); +} + bool WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, bool enabled) { SDL_VideoData *data = _this->internal; @@ -354,41 +374,22 @@ bool WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, bool enabled) return true; } -typedef enum WIN_RawKeyboardFlag { - NOHOTKEYS, - INPUTSINK, -} WIN_RawKeyboardFlag; - -static bool WIN_SetRawKeyboardFlag(SDL_VideoDevice *_this, WIN_RawKeyboardFlag flag, bool enabled) +bool WIN_SetRawKeyboardFlag_NoHotkeys(SDL_VideoDevice *_this, bool enabled) { SDL_VideoData *data = _this->internal; - switch(flag) { - case NOHOTKEYS: - data->raw_keyboard_flag_nohotkeys = enabled; - break; - case INPUTSINK: - data->raw_keyboard_flag_inputsink = enabled; - break; - default: - return false; - } - - if (data->gameinput_context) { - return true; - } + data->raw_keyboard_flag_nohotkeys = enabled; return WIN_UpdateRawInputEnabled(_this); } -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); + SDL_VideoData *data = _this->internal; + + data->raw_keyboard_flag_inputsink = enabled; + + return WIN_UpdateRawInputEnabled(_this); } void WIN_QuitRawInput(SDL_VideoDevice *_this) @@ -403,6 +404,11 @@ bool WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, bool enabled) return SDL_Unsupported(); } +bool WIN_SetRawMouseFlag_NoLegacy(SDL_VideoDevice *_this, bool enabled) +{ + return SDL_Unsupported(); +} + bool WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, bool enabled) { return SDL_Unsupported(); diff --git a/src/video/windows/SDL_windowsrawinput.h b/src/video/windows/SDL_windowsrawinput.h index d5e6caa05a..47f68291fa 100644 --- a/src/video/windows/SDL_windowsrawinput.h +++ b/src/video/windows/SDL_windowsrawinput.h @@ -25,6 +25,7 @@ extern void WIN_QuitRawInput(SDL_VideoDevice *_this); extern bool WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, bool enabled); +extern bool WIN_SetRawMouseFlag_NoLegacy(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); diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index 3a1527a443..3b99f179c8 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -163,6 +163,13 @@ static void SDLCALL UpdateWindowsRawKeyboardInputsink(void *userdata, const char WIN_SetRawKeyboardFlag_Inputsink(_this, enabled); } +static void SDLCALL UpdateWindowsRawMouseNoLegacy(void *userdata, const char *name, const char *oldValue, const char *newValue) +{ + SDL_VideoDevice *_this = (SDL_VideoDevice *)userdata; + bool enabled = SDL_GetStringBoolean(newValue, false); + WIN_SetRawMouseFlag_NoLegacy(_this, enabled); +} + static void SDLCALL UpdateWindowsEnableMessageLoop(void *userdata, const char *name, const char *oldValue, const char *newValue) { g_WindowsEnableMessageLoop = SDL_GetStringBoolean(newValue, true); @@ -648,6 +655,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_RAW_MOUSE_NOLEGACY, UpdateWindowsRawMouseNoLegacy, _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); diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h index b3240d3cb9..928fcd054b 100644 --- a/src/video/windows/SDL_windowsvideo.h +++ b/src/video/windows/SDL_windowsvideo.h @@ -592,6 +592,7 @@ struct SDL_VideoData Uint64 last_rawinput_poll; SDL_Point last_raw_mouse_position; bool raw_mouse_enabled; + bool raw_mouse_flag_nolegacy; bool raw_keyboard_enabled; bool raw_keyboard_flag_nohotkeys; bool raw_keyboard_flag_inputsink;