From 7053f0835b55ee5590d9c566378e447b6b569ff8 Mon Sep 17 00:00:00 2001 From: Kaldaien Date: Wed, 30 Oct 2024 16:07:56 -0400 Subject: [PATCH] Optimize gamepad polling and add various protections against sending messages to external applications if SKIF has an invalid HWND --- src/SKIF.cpp | 27 +++++++++------ src/utility/gamepad.cpp | 75 ++++++++++++++++++++++++++++++++++++----- version.h | 2 +- 3 files changed, 84 insertions(+), 20 deletions(-) diff --git a/src/SKIF.cpp b/src/SKIF.cpp index c7f89ae3..d373f7a6 100644 --- a/src/SKIF.cpp +++ b/src/SKIF.cpp @@ -255,13 +255,11 @@ void SKIF_Startup_SetGameAsForeground (void) { // Exit if there is nothing to actually do - if (pidForegroundFocusOnExit == NULL && + if (pidForegroundFocusOnExit == NULL || hWndForegroundFocusOnExit == nullptr) return; - static DWORD _pid; - - _pid = 0; + DWORD _pid = 0; if (hWndForegroundFocusOnExit != nullptr && hWndForegroundFocusOnExit == GetForegroundWindow ()) @@ -294,11 +292,16 @@ SKIF_Startup_SetGameAsForeground (void) // Primary approach -- use the HWND reported by Special K if (hWndForegroundFocusOnExit != nullptr) { - if (IsWindow (hWndForegroundFocusOnExit)) + if (GetWindowThreadProcessId (hWndForegroundFocusOnExit, &_pid) && + pidForegroundFocusOnExit == _pid) { - PLOG_INFO << "Special K reported a game window, setting as foreground..."; - if (! SetForegroundWindow (hWndForegroundFocusOnExit)) - PLOG_WARNING << "SetForegroundWindow ( ) failed!"; + if (IsWindowVisible (hWndForegroundFocusOnExit)) + { + PLOG_INFO << "Special K reported a game window, setting as foreground..."; + if (! SetForegroundWindow (hWndForegroundFocusOnExit)) + PLOG_WARNING << "SetForegroundWindow ( ) failed!"; + } + return; } } @@ -307,6 +310,7 @@ SKIF_Startup_SetGameAsForeground (void) EnumWindows ( []( HWND hWnd, LPARAM lParam ) -> BOOL { + DWORD _pid = 0; if (GetWindowThreadProcessId (hWnd, &_pid)) { if (_pid != NULL && @@ -322,8 +326,11 @@ SKIF_Startup_SetGameAsForeground (void) // If it doesn't have this style, then don't set it foreground. if (dwExStyle & WS_EX_APPWINDOW) { - if (! SetForegroundWindow (hWnd)) - PLOG_WARNING << "SetForegroundWindow ( ) failed!"; + if (IsWindowVisible (hWnd)) + { + if (! SetForegroundWindow (hWnd)) + PLOG_WARNING << "SetForegroundWindow ( ) failed!"; + } return FALSE; // Stop enumeration } diff --git a/src/utility/gamepad.cpp b/src/utility/gamepad.cpp index c81322cd..368e52c8 100644 --- a/src/utility/gamepad.cpp +++ b/src/utility/gamepad.cpp @@ -151,8 +151,14 @@ SKIF_GamePadInputHelper::UpdateXInputState (void) m_bWantUpdate.store(false); - // Trigger the main thread to refresh its focus, which will also trickle down to us - PostMessage (m_hWindowHandle, WM_SKIF_REFRESHFOCUS, 0x0, 0x0); + DWORD dwProcId = 0x0; + GetWindowThreadProcessId (m_hWindowHandle, &dwProcId); + + if (dwProcId == GetProcessId (GetCurrentProcess ())) + { + // Trigger the main thread to refresh its focus, which will also trickle down to us + SendMessage (m_hWindowHandle, WM_SKIF_REFRESHFOCUS, 0x0, 0x0); + } } if (SKIF_XInputGetState == nullptr) @@ -253,7 +259,18 @@ SKIF_GamePadInputHelper::UpdateXInputState (void) } if (newest.slot == INFINITE) + newest.state = XSTATE_EMPTY; + + DWORD dwPidOfMe = GetCurrentProcessId (), + dwPidOfFG = 0x0; + + if (!(GetWindowThreadProcessId (GetForegroundWindow (), &dwPidOfFG) && + dwPidOfMe == dwPidOfFG) || + !IsWindowVisible (SKIF_ImGui_hWnd)) + { + // Neutralize input because SKIF is not in the foreground newest.state = XSTATE_EMPTY; + } m_xisGamepad.store (newest.state); @@ -263,6 +280,15 @@ SKIF_GamePadInputHelper::UpdateXInputState (void) bool SKIF_GamePadInputHelper::RegisterDevNotification (HWND hWnd) { + DWORD dwProcId = 0x0; + GetWindowThreadProcessId (hWnd, &dwProcId); + + if (dwProcId != GetProcessId (GetCurrentProcess ())) + { + m_hWindowHandle = 0; + return false; + } + GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } }; @@ -313,7 +339,9 @@ SKIF_GamePadInputHelper::SpawnChildThread (void) CRITICAL_SECTION GamepadInputPump = { }; InitializeCriticalSection (&GamepadInputPump); EnterCriticalSection (&GamepadInputPump); - + + SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL); + SKIF_Util_SetThreadDescription (GetCurrentThread (), L"SKIF_GamePadInputPump"); static SKIF_GamePadInputHelper& parent = SKIF_GamePadInputHelper::GetInstance ( ); @@ -333,20 +361,49 @@ SKIF_GamePadInputHelper::SpawnChildThread (void) ); } - packetNew = parent.UpdateXInputState ( ).dwPacketNumber; + static auto constexpr + _ThrottleIdleInputAfterMs = 3333UL; + + static DWORD dwLastInputTime = + SKIF_Util_timeGetTime (), + dwCurrentTime; + + auto _IsGamepadIdle = + [&]{ return + (dwLastInputTime < dwCurrentTime - _ThrottleIdleInputAfterMs); + }; + + dwCurrentTime = SKIF_Util_timeGetTime (); + packetNew = parent.UpdateXInputState ().dwPacketNumber; if (packetNew > 0 && packetNew != packetLast) { packetLast = packetNew; - PostMessage (parent.m_hWindowHandle, WM_SKIF_GAMEPAD, 0x0, 0x0); + + if (! _IsGamepadIdle ()) + { + SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL); + } + + dwLastInputTime = + SKIF_Util_timeGetTime (); + + SendMessage (parent.m_hWindowHandle, WM_SKIF_GAMEPAD, 0x0, 0x0); } - // XInput tends to have ~3-7 ms of latency between updates - // best-case, try to delay the next poll until there's - // new data. - Sleep (5); + static bool + s_wasGamepadIdle = + _IsGamepadIdle (); + if (_IsGamepadIdle ()) + { + if (! std::exchange (s_wasGamepadIdle, true)) + SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_IDLE); + SleepEx (15UL, TRUE); + } + else + s_wasGamepadIdle = false; } while (! SKIF_Shutdown.load()); LeaveCriticalSection (&GamepadInputPump); diff --git a/version.h b/version.h index 55830c6e..e77a47dc 100644 --- a/version.h +++ b/version.h @@ -26,7 +26,7 @@ #define SKIF_MAJOR 1 #define SKIF_MINOR 1 -#define SKIF_BUILD 8 +#define SKIF_BUILD 9 #define SKIF_REV 0