Skip to content

Commit

Permalink
Optimize gamepad polling and add various protections against sending …
Browse files Browse the repository at this point in the history
…messages to external applications if SKIF has an invalid HWND
  • Loading branch information
Kaldaien committed Oct 30, 2024
1 parent 0d661e9 commit 7053f08
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 20 deletions.
27 changes: 17 additions & 10 deletions src/SKIF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ())
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -307,6 +310,7 @@ SKIF_Startup_SetGameAsForeground (void)
EnumWindows ( []( HWND hWnd,
LPARAM lParam ) -> BOOL
{
DWORD _pid = 0;
if (GetWindowThreadProcessId (hWnd, &_pid))
{
if (_pid != NULL &&
Expand All @@ -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
}
Expand Down
75 changes: 66 additions & 9 deletions src/utility/gamepad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);

Expand All @@ -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 } };
Expand Down Expand Up @@ -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 ( );
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion version.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

#define SKIF_MAJOR 1
#define SKIF_MINOR 1
#define SKIF_BUILD 8
#define SKIF_BUILD 9
#define SKIF_REV 0


Expand Down

0 comments on commit 7053f08

Please sign in to comment.