From 17442862752fb22138d81f84ffd78e88806d1608 Mon Sep 17 00:00:00 2001 From: Kaldaien Date: Sun, 29 Dec 2024 22:16:16 -0500 Subject: [PATCH] Add backup input thread for games that stop processing input on their message queue for long periods of time (i.e. during FMV playback or loading screens). --- CHANGELOG.txt | 12 ++++++- include/SpecialK/DLL_VERSION.H | 4 +-- include/imgui/imgui_user.inl | 65 ++++++++++++++++++++++++++++------ src/control_panel.cpp | 7 ++++ 4 files changed, 74 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 194d60841..488ebc174 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,4 +1,14 @@ -24.12.29.4 +24.12.29.5 +========== + + Add backup input thread for games that stop processing input on their + message queue for long periods of time (i.e. during FMV playback), + so that SK's keyboard macros and basic mouse input (no scrollwheel) + remain responsive. + + * Or, in the worst-case, this backup thread handles all Keyboard & Mouse + because it wasn't possible to hook the game's window thread. + +24.12.29.4 ========== + Removed foreground window HWND caching, the WinEventHookProc does not order the events it sends coherently. diff --git a/include/SpecialK/DLL_VERSION.H b/include/SpecialK/DLL_VERSION.H index 74ecc5fb6..2d139c522 100644 --- a/include/SpecialK/DLL_VERSION.H +++ b/include/SpecialK/DLL_VERSION.H @@ -3,8 +3,8 @@ #define SK_YEAR 24 #define SK_MONTH 12 #define SK_DATE 29 -#define SK_REV_N 4 -#define SK_REV 4 +#define SK_REV_N 5 +#define SK_REV 5 #ifndef _A2 #define _A2(a) #a diff --git a/include/imgui/imgui_user.inl b/include/imgui/imgui_user.inl index dcfcebaef..26f8889bd 100644 --- a/include/imgui/imgui_user.inl +++ b/include/imgui/imgui_user.inl @@ -3240,26 +3240,68 @@ SK_ImGui_UpdateClassCursor (void) } } +BOOL bCursorThreadIsAttached = FALSE; HANDLE hPollCursorEvent; bool SK_ImGui_IsHWCursorVisible = false; +extern DWORD SK_ImGui_LastKeyboardProcMessageTime; +extern DWORD SK_ImGui_LastMouseProcMessageTime; + DWORD WINAPI -SK_ImGui_CursorPollingThread (LPVOID) +SK_ImGui_BackupInputThread (LPVOID) { - SK_Thread_SetCurrentPriority (THREAD_PRIORITY_ABOVE_NORMAL); + SK_Thread_SetCurrentPriority (THREAD_PRIORITY_NORMAL); const HANDLE hEvents [] = { __SK_DLL_TeardownEvent, hPollCursorEvent }; - while (WaitForMultipleObjects (2, hEvents, FALSE, 1) != WAIT_OBJECT_0) + DWORD dwWaitState = WAIT_TIMEOUT; + while (dwWaitState != WAIT_OBJECT_0) { - //SK_GetCursorPos (&SK_ImGui_LastKnownCursorPos); - SK_ImGui_LastKnownCursor = - SK_GetCursor (); - SK_ImGui_IsHWCursorVisible = - SK_InputUtil_IsHWCursorVisible (); + dwWaitState = + WaitForMultipleObjects (2, hEvents, FALSE, 2); + + // Sometimes games stop processing their message loop for long periods + // of time (i.e. FMV playback or load screens), so we need to resort + // to an alternate means of getting keyboard state. + if (SK_ImGui_LastKeyboardProcMessageTime < SK::ControlPanel::current_time - 500UL && + (dwWaitState == (WAIT_OBJECT_0 + 1))) + { + auto& io = + ImGui::GetIO (); + + bool last_keys [256] = {}; + memcpy (last_keys, io.KeysDown, 256); + + for (UINT i = 7 ; i < 255 ; ++i) + { + bool last_state = + last_keys [i]; + io.KeysDown [i] = + ((SK_GetAsyncKeyState (i) & 0x8000) != 0x0); + + if (last_state != io.KeysDown [i]) + { + if (io.KeysDown [i]) SK_Console::getInstance ()->KeyDown ((BYTE)(i & 0xFF), MAXDWORD); + else SK_Console::getInstance ()->KeyUp ((BYTE)(i & 0xFF), MAXDWORD); + } + } + } + + // Sometimes games stop processing their message loop for long periods + // of time (i.e. FMV playback or load screens), so we need to resort + // to an alternate means of getting cursor position. + if (SK_ImGui_LastMouseProcMessageTime < SK::ControlPanel::current_time - 250UL) + { + SK_GetCursorPos (&SK_ImGui_LastKnownCursorPos); + } + + SK_ImGui_LastKnownCursor = + SK_GetCursor (); + SK_ImGui_IsHWCursorVisible = + SK_InputUtil_IsHWCursorVisible (); } SK_Thread_CloseSelf (); @@ -3276,12 +3318,13 @@ SK_ImGui_User_NewFrame (void) SK_ImGui_UpdateClassCursor (); - POINT cursor_pos = SK_ImGui_LastKnownCursorPos; + POINT cursor_pos = SK_ImGui_LastKnownCursorPos; + SK_RunOnce ( hPollCursorEvent = SK_CreateEvent (nullptr, FALSE, FALSE, nullptr); - SK_Thread_CreateEx (SK_ImGui_CursorPollingThread, - L"[SK] CursorPollingThread", nullptr); + SK_Thread_CreateEx (SK_ImGui_BackupInputThread, + L"[SK] Backup Input Thread", nullptr); ); SetEvent (hPollCursorEvent); diff --git a/src/control_panel.cpp b/src/control_panel.cpp index becf34f16..8e62ed3b8 100644 --- a/src/control_panel.cpp +++ b/src/control_panel.cpp @@ -7247,6 +7247,9 @@ SK_Platform_GetUserName (char* pszName, int max_len = 512) extern POINT SK_ImGui_LastKnownCursorPos; +DWORD SK_ImGui_LastMouseProcMessageTime = 0; +DWORD SK_ImGui_LastKeyboardProcMessageTime = 0; + LRESULT CALLBACK SK_ImGui_MouseProc (int code, WPARAM wParam, LPARAM lParam) @@ -7254,6 +7257,8 @@ SK_ImGui_MouseProc (int code, WPARAM wParam, LPARAM lParam) if (code < 0 || GImGui == nullptr) // We saw nothing (!!) return CallNextHookEx (0, code, wParam, lParam); + SK_ImGui_LastMouseProcMessageTime = SK::ControlPanel::current_time; + auto& io = ImGui::GetIO (); @@ -7467,6 +7472,8 @@ SK_ImGui_KeyboardProc (int code, WPARAM wParam, LPARAM lParam) if (code < 0 || GImGui == nullptr) // We saw nothing (!!) return CallNextHookEx (0, code, wParam, lParam); + SK_ImGui_LastKeyboardProcMessageTime = SK::ControlPanel::current_time; + const bool keyboard_capture = SK_ImGui_WantKeyboardCapture ();