diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 19f49e9b36..ea57c1ca42 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -786,7 +786,7 @@ static void WIN_HandleRawKeyboardInput(Uint64 timestamp, SDL_VideoData *data, HA SDL_SendKeyboardKey(timestamp, keyboardID, rawcode, code, down); } -void WIN_PollRawInput(SDL_VideoDevice *_this, Uint64 poll_start) +void WIN_PollRawInput(SDL_VideoDevice *_this, Uint64 poll_start, bool process_input) { SDL_VideoData *data = _this->internal; UINT size, i, count, total = 0; @@ -832,7 +832,7 @@ void WIN_PollRawInput(SDL_VideoDevice *_this, Uint64 poll_start) } } - if (total > 0) { + if (total > 0 && process_input) { Uint64 delta = poll_finish - poll_start; UINT mouse_total = 0; for (i = 0, input = (RAWINPUT *)data->rawinput; i < total; ++i, input = NEXTRAWINPUTBLOCK(input)) { diff --git a/src/video/windows/SDL_windowsevents.h b/src/video/windows/SDL_windowsevents.h index 45f5527dc6..21bd7a420c 100644 --- a/src/video/windows/SDL_windowsevents.h +++ b/src/video/windows/SDL_windowsevents.h @@ -29,7 +29,7 @@ extern HINSTANCE SDL_Instance; extern LRESULT CALLBACK WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam); extern LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); -extern void WIN_PollRawInput(SDL_VideoDevice *_this, Uint64 poll_start); +extern void WIN_PollRawInput(SDL_VideoDevice *_this, Uint64 poll_start, bool process_input); extern void WIN_PumpEvents(SDL_VideoDevice *_this); extern void WIN_PumpEventsForHWND(SDL_VideoDevice *_this, HWND hwnd); extern void WIN_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window); diff --git a/src/video/windows/SDL_windowsrawinput.c b/src/video/windows/SDL_windowsrawinput.c index cada2b6d63..3c5d80ab2b 100644 --- a/src/video/windows/SDL_windowsrawinput.c +++ b/src/video/windows/SDL_windowsrawinput.c @@ -40,13 +40,15 @@ typedef struct { bool done; + bool paused; Uint32 flags; HANDLE ready_event; - HANDLE done_event; + HANDLE signal_event; HANDLE thread; } RawInputThreadData; static RawInputThreadData thread_data = { + false, false, 0, INVALID_HANDLE_VALUE, @@ -104,22 +106,34 @@ static DWORD WINAPI WIN_RawInputThread(LPVOID param) // Tell the parent we're ready to go! SetEvent(data->ready_event); - Uint64 idle_begin = SDL_GetTicksNS(); - while (!data->done && - // The high-order word of GetQueueStatus() will let us know if there's currently raw input to be processed. - // If there isn't, then we'll wait for new data to arrive with MsgWaitForMultipleObjects(). - ((HIWORD(GetQueueStatus(QS_RAWINPUT)) & QS_RAWINPUT) || - (MsgWaitForMultipleObjects(1, &data->done_event, FALSE, INFINITE, QS_RAWINPUT) == WAIT_OBJECT_0 + 1))) { + while (!data->done) { + Uint64 idle_begin = SDL_GetTicksNS(); + while (!data->done && !data->paused && + // The high-order word of GetQueueStatus() will let us know if there's currently raw input to be processed. + // If there isn't, then we'll wait for new data to arrive with MsgWaitForMultipleObjects(). + ((HIWORD(GetQueueStatus(QS_RAWINPUT)) & QS_RAWINPUT) || + (MsgWaitForMultipleObjects(1, &data->signal_event, FALSE, INFINITE, QS_RAWINPUT) == WAIT_OBJECT_0 + 1))) { - Uint64 idle_end = SDL_GetTicksNS(); - Uint64 idle_time = idle_end - idle_begin; - Uint64 usb_8khz_interval = SDL_US_TO_NS(125); - Uint64 poll_start = idle_time < usb_8khz_interval ? _this->internal->last_rawinput_poll : idle_end; + Uint64 idle_end = SDL_GetTicksNS(); + Uint64 idle_time = idle_end - idle_begin; + Uint64 usb_8khz_interval = SDL_US_TO_NS(125); + Uint64 poll_start = idle_time < usb_8khz_interval ? _this->internal->last_rawinput_poll : idle_end; - WIN_PollRawInput(_this, poll_start); + WIN_PollRawInput(_this, poll_start, true); - // Reset idle_begin for the next go-around - idle_begin = SDL_GetTicksNS(); + // Reset idle_begin for the next go-around + idle_begin = SDL_GetTicksNS(); + } + + if (data->paused) { + // Wait for the resume signal + while (data->paused) { + WaitForSingleObject(data->signal_event, INFINITE); + } + + // Flush raw input queued while paused + WIN_PollRawInput(_this, SDL_GetTicksNS(), false); + } } if (_this->internal->raw_input_fake_pen_id) { @@ -141,8 +155,9 @@ static DWORD WINAPI WIN_RawInputThread(LPVOID param) static void CleanupRawInputThreadData(RawInputThreadData *data) { if (data->thread != INVALID_HANDLE_VALUE) { + data->paused = false; data->done = true; - SetEvent(data->done_event); + SetEvent(data->signal_event); WaitForSingleObject(data->thread, 3000); CloseHandle(data->thread); data->thread = INVALID_HANDLE_VALUE; @@ -153,16 +168,26 @@ static void CleanupRawInputThreadData(RawInputThreadData *data) data->ready_event = INVALID_HANDLE_VALUE; } - if (data->done_event != INVALID_HANDLE_VALUE) { - CloseHandle(data->done_event); - data->done_event = INVALID_HANDLE_VALUE; + if (data->signal_event != INVALID_HANDLE_VALUE) { + CloseHandle(data->signal_event); + data->signal_event = INVALID_HANDLE_VALUE; } } -static bool WIN_SetRawInputEnabled(SDL_VideoDevice *_this, Uint32 flags) +bool WIN_SetRawInputEnabled(SDL_VideoDevice *_this, Uint32 flags, bool force) { bool result = false; + if (thread_data.thread != INVALID_HANDLE_VALUE && !force) { + if (flags) { + thread_data.paused = false; + } else { + thread_data.paused = true; + } + SetEvent(thread_data.signal_event); + return true; + } + CleanupRawInputThreadData(&thread_data); if (flags) { @@ -176,8 +201,8 @@ static bool WIN_SetRawInputEnabled(SDL_VideoDevice *_this, Uint32 flags) } thread_data.done = false; - thread_data.done_event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (thread_data.done_event == INVALID_HANDLE_VALUE) { + thread_data.signal_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (thread_data.signal_event == INVALID_HANDLE_VALUE) { WIN_SetError("CreateEvent"); goto done; } @@ -216,15 +241,20 @@ static bool WIN_UpdateRawInputEnabled(SDL_VideoDevice *_this) } if (data->raw_keyboard_enabled) { flags |= ENABLE_RAW_KEYBOARD_INPUT; - if (data->raw_keyboard_flag_nohotkeys) { - flags |= RAW_KEYBOARD_FLAG_NOHOTKEYS; - } - if (data->raw_keyboard_flag_inputsink) { - flags |= RAW_KEYBOARD_FLAG_INPUTSINK; - } + } + 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)) { + bool force = false; + if ((flags ^ data->raw_input_enabled) & (RAW_KEYBOARD_FLAG_NOHOTKEYS | RAW_KEYBOARD_FLAG_INPUTSINK)) { + // The keyboard flags have changed + force = true; + } + if (WIN_SetRawInputEnabled(_this, flags, force)) { data->raw_input_enabled = flags; } else { return false; @@ -308,6 +338,11 @@ bool WIN_SetRawKeyboardFlag_Inputsink(SDL_VideoDevice *_this, bool enabled) #else +bool WIN_SetRawInputEnabled(SDL_VideoDevice *_this, Uint32 flags, bool force) +{ + return SDL_Unsupported(); +} + bool WIN_SetRawMouseEnabled(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 2ede2eba44..e970666a9a 100644 --- a/src/video/windows/SDL_windowsrawinput.h +++ b/src/video/windows/SDL_windowsrawinput.h @@ -23,6 +23,7 @@ #ifndef SDL_windowsrawinput_h_ #define SDL_windowsrawinput_h_ +extern bool WIN_SetRawInputEnabled(SDL_VideoDevice *_this, Uint32 flags, bool force); 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); diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index c6997dbf65..edb28e838b 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -671,8 +671,7 @@ void WIN_VideoQuit(SDL_VideoDevice *_this) SDL_RemoveHintCallback(SDL_HINT_WINDOWS_ENABLE_MENU_MNEMONICS, UpdateWindowsEnableMenuMnemonics, NULL); SDL_RemoveHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL); - WIN_SetRawMouseEnabled(_this, false); - WIN_SetRawKeyboardEnabled(_this, false); + WIN_SetRawInputEnabled(_this, 0, true); WIN_QuitGameInput(_this); #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)