Skip to content

Commit

Permalink
Stop setting GCLP_HCURSOR in WM_SETCURSOR unless the game itself is u…
Browse files Browse the repository at this point in the history
…sing a class cursor
  • Loading branch information
Kaldaien committed Dec 28, 2024
1 parent f7d6149 commit 28b9101
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 31 deletions.
2 changes: 1 addition & 1 deletion include/SpecialK/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ class SK_TLS;

bool
__stdcall
SK_IsGameWindowActive (bool activate_if_in_limbo = false);
SK_IsGameWindowActive (bool activate_if_in_limbo = false, HWND hWndForeground = 0);

bool
__stdcall
Expand Down
78 changes: 58 additions & 20 deletions include/imgui/imgui_user.inl
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,7 @@ ImGui_WndProcHandler ( HWND hWnd, UINT msg,
if ( LOWORD (lParam) == HTCLIENT ||
LOWORD (lParam) == HTTRANSPARENT )
{
static POINT lastMouse =
static thread_local POINT lastMouse =
{ SHORT_MAX, SHORT_MAX };

#if 0
Expand All @@ -1093,37 +1093,62 @@ ImGui_WndProcHandler ( HWND hWnd, UINT msg,
ImGui::GetIO ().WantCaptureMouse;

if ( ( hWnd == game_window.hWnd ||
hWnd == game_window.child ) && HIWORD (lParam) != WM_NULL && ( mousePos.x != lastMouse.x ||
mousePos.y != lastMouse.y ||
bRawCapture ) )
hWnd == game_window.child ) && HIWORD (lParam) != WM_NULL && (mousePos.x != lastMouse.x ||
mousePos.y != lastMouse.y ||
bRawCapture ) )
{
lastMouse = mousePos;

auto messageTime = GetMessageTime ();

static LONG lastTime = 0;
if (std::exchange (lastTime, messageTime) != messageTime || bRawCapture)
{
static HCURSOR hLastClassCursor = (HCURSOR)(-1);

if (bRawCapture || ( SK_ImGui_IsAnythingHovered () &&
SK_ImGui_WantMouseCapture () ))
{
if (hLastClassCursor == (HCURSOR)(-1))
hLastClassCursor = (HCURSOR)GetClassLongPtrW (game_window.hWnd, GCLP_HCURSOR);

if (SK_ImGui_WantHWCursor ())
{
SetClassLongPtrW (game_window.hWnd, GCLP_HCURSOR, (LONG_PTR)ImGui_DesiredCursor ());
}
auto desired_cursor = ImGui_DesiredCursor ();
bool using_class_cursor = false;

lastMouse = mousePos;
// Set the class cursor so that we do not have to repeatedly
// call SetCursor (...) every time this message is received...
// but only if the game also uses a non-zero class cursor.
if ((intptr_t)game_window.real_cursor > 0)
{
using_class_cursor =
(game_window.real_cursor == desired_cursor);

if ((! using_class_cursor) && (intptr_t)game_window.game_cursor > 0)
{
game_window.game_cursor =
(HCURSOR)SetClassLongPtrW (
game_window.hWnd, GCLP_HCURSOR,
(LONG_PTR)game_window.real_cursor );
}
}

// We have to manually call SetCursor (...), because the game
// is not using class cursors.
if (! using_class_cursor)
SetCursor (desired_cursor);
}

return TRUE;
}

else
{
if (hLastClassCursor != (HCURSOR)(-1))
SetClassLongPtrW (game_window.hWnd, GCLP_HCURSOR, (LONG_PTR)std::exchange (hLastClassCursor, (HCURSOR)(-1)));
// Reset the class cursor if necessary.
if ((intptr_t)game_window.game_cursor > 0 &&
game_window.game_cursor != game_window.real_cursor)
{
game_window.real_cursor = game_window.game_cursor;

SetClassLongPtrW ( game_window.hWnd, GCLP_HCURSOR,
(LONG_PTR)game_window.real_cursor );
}

if (config.input.cursor.manage)
{
Expand All @@ -1137,16 +1162,12 @@ ImGui_WndProcHandler ( HWND hWnd, UINT msg,

if (! SK_Window_IsCursorActive ())
{
lastMouse = mousePos;

SK_SetCursor (0);

return TRUE;
}
}
}

lastMouse = mousePos;
}
}
}
Expand Down Expand Up @@ -3203,13 +3224,30 @@ SK_ImGui_UpdateMouseButtons (bool bActive, ImGuiIO& io)

POINT SK_ImGui_LastKnownCursorPos;

void
SK_ImGui_UpdateClassCursor (void)
{
SK_RunOnce (
game_window.real_cursor =
(HCURSOR)GetClassLongPtrW (game_window.hWnd, GCLP_HCURSOR)
);

bool SK_ImGui_IsImGuiCursor (HCURSOR hCursor);
if (! SK_ImGui_IsImGuiCursor (game_window.real_cursor))
{
game_window.game_cursor = game_window.real_cursor;
}
}

void
SK_ImGui_User_NewFrame (void)
{
SK_Window_HandleOutOfBandMovement ();

SK_HID_ProcessGamepadButtonBindings ();

SK_ImGui_UpdateClassCursor ();

POINT cursor_pos = {};
SK_GetCursorPos (&cursor_pos);

Expand Down Expand Up @@ -3496,7 +3534,7 @@ SK_ImGui_User_NewFrame (void)
}

const bool bActive =
SK_IsGameWindowActive ();
SK_IsGameWindowActive (false, hWndForeground);

// Avoid overhead from calling SK_GetAsyncKeyState (...)
// repeatedly; we already have a low-level keyboard hook!
Expand Down Expand Up @@ -3786,7 +3824,7 @@ SK_ImGui_User_NewFrame (void)
SK_ImGui_WantKeyboardCapture (true);
SK_ImGui_WantMouseCapture (true, &cursor_pos);
SK_ImGui_WantGamepadCapture (true);
SK_IsGameWindowActive (true);
SK_IsGameWindowActive (true, hWndForeground);

SK_ImGui_Cursor.last_screen_pos = cursor_pos;
}
Expand Down
2 changes: 1 addition & 1 deletion src/control_panel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8768,7 +8768,7 @@ SK_ImGui_Toggle (void)
if (SK::SteamAPI::AppID () != 0 && SK_ImGui_Visible)
SK::SteamAPI::UpdateNumPlayers ();

if (config.input.ui.center_cursor)
//if (config.input.ui.center_cursor)
{
static SK_AutoHandle hMoveCursor (
SK_CreateEvent (nullptr, FALSE, FALSE, nullptr)
Expand Down
27 changes: 22 additions & 5 deletions src/input/cursor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,22 @@ sk_imgui_cursor_s::ScreenToLocal (LPPOINT lpPoint)
ClientToLocal (lpPoint);
}

bool
SK_ImGui_IsImGuiCursor (HCURSOR hCursor)
{
static const std::set <HCURSOR>
__cursors =
{
{ LoadCursor (SK_GetDLL (), (LPCWSTR)IDC_CURSOR_POINTER) },
{ LoadCursor (nullptr, IDC_IBEAM) },
{ LoadCursor (SK_GetDLL (), (LPCWSTR)IDC_CURSOR_HORZ) },
{ LoadCursor (nullptr, IDC_SIZENWSE) }
};

return
__cursors.contains (hCursor);
}

HCURSOR
ImGui_DesiredCursor (void)
{
Expand Down Expand Up @@ -706,14 +722,15 @@ HCURSOR GetGameCursor (void)

bool
__stdcall
SK_IsGameWindowActive (bool activate_if_in_limbo)
SK_IsGameWindowActive (bool activate_if_in_limbo, HWND hWndForeground)
{
bool bActive =
game_window.active;

if ((! bActive) && activate_if_in_limbo)
{
HWND hWndForeground = SK_GetForegroundWindow ();
if (hWndForeground == 0)
hWndForeground = SK_GetForegroundWindow ();

bActive =
( game_window.hWnd == hWndForeground ||
Expand Down Expand Up @@ -762,9 +779,9 @@ SK_IsGameWindowActive (bool activate_if_in_limbo)
{
// This only activates the window if performed on the same thread as the
// game's window, so don't do this if called from a different thread.
if ( 0 != SK_Win32_BackgroundHWND &&
SK_GetForegroundWindow () == SK_Win32_BackgroundHWND &&
GetCurrentThreadId () == GetWindowThreadProcessId (game_window.hWnd, nullptr) )
if ( 0 != SK_Win32_BackgroundHWND &&
hWndForeground == SK_Win32_BackgroundHWND &&
GetCurrentThreadId () == GetWindowThreadProcessId (game_window.hWnd, nullptr) )
{
game_window.active = true;

Expand Down
5 changes: 1 addition & 4 deletions src/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1759,7 +1759,7 @@ ClipCursor_Detour (const RECT *lpRect)

// Ensure the window really IS active, set active=false otherwise so that this
// clip rect is not repeatedly applied.
if (SK_IsGameWindowActive ())
if (SK_IsGameWindowActive (false, hWndForeground))
{
bool active =
( game_window.hWnd==hWndForeground ||
Expand Down Expand Up @@ -6674,9 +6674,6 @@ SK_InitWindow (HWND hWnd, bool fullscreen_exclusive)

SK_GetCursorPos ( &game_window.cursor_pos);

game_window.real_cursor =
(HCURSOR)GetClassLongPtrW (game_window.hWnd, GCLP_HCURSOR);


// Make sure any pending changes are finished before querying the
// actual value
Expand Down

0 comments on commit 28b9101

Please sign in to comment.