From d5a44eb40c05a8047dd26a2d3a10aa86f879d30b Mon Sep 17 00:00:00 2001 From: narzoul Date: Sat, 20 Apr 2024 17:00:30 +0200 Subject: [PATCH] Fixed inaccurate cursor clipping in DPI unaware mode --- DDrawCompat/DDraw/RealPrimarySurface.cpp | 18 ++---------- DDrawCompat/Gdi/Cursor.cpp | 36 ++++++++++++++++++++++-- DDrawCompat/Gdi/Cursor.h | 2 ++ DDrawCompat/Gdi/WinProc.cpp | 10 ++++++- 4 files changed, 47 insertions(+), 19 deletions(-) diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 32cfe35..386b7a5 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -340,22 +340,8 @@ namespace void setFullscreenPresentationMode(const Win32::DisplayMode::MonitorInfo& mi) { - if (IsRectEmpty(&mi.rcDpiAware)) - { - Gdi::Cursor::setEmulated(false); - Gdi::Cursor::setMonitorClipRect({}); - } - else - { - auto clipRect = mi.rcEmulated; - if (!EqualRect(&mi.rcMonitor, &mi.rcReal)) - { - InflateRect(&clipRect, -1, -1); - } - - Gdi::Cursor::setMonitorClipRect(clipRect); - Gdi::Cursor::setEmulated(!Overlay::Steam::isOverlayOpen()); - } + Gdi::Cursor::setEmulated(!IsRectEmpty(&mi.rcEmulated) && !Overlay::Steam::isOverlayOpen()); + Gdi::Cursor::setMonitorClipRect(mi.rcEmulated); } void updateNow(CompatWeakPtr src, bool isOverlayOnly) diff --git a/DDrawCompat/Gdi/Cursor.cpp b/DDrawCompat/Gdi/Cursor.cpp index 01849e5..a277f79 100644 --- a/DDrawCompat/Gdi/Cursor.cpp +++ b/DDrawCompat/Gdi/Cursor.cpp @@ -62,9 +62,13 @@ namespace LOG_FUNC("GetCursorInfo", pci); Compat::ScopedCriticalSection lock(g_cs); BOOL result = CALL_ORIG_FUNC(GetCursorInfo)(pci); - if (result && pci->hCursor == g_nullCursor) + if (result) { - pci->hCursor = g_cursor; + if (pci->hCursor == g_nullCursor) + { + pci->hCursor = g_cursor; + } + Gdi::Cursor::clip(pci->ptScreenPos); } return LOG_RESULT(result); } @@ -121,6 +125,33 @@ namespace Gdi { namespace Cursor { + void clip() + { + Compat::ScopedCriticalSection lock(g_cs); + if (!IsRectEmpty(&g_monitorClipRect)) + { + POINT cp = {}; + CALL_ORIG_FUNC(GetCursorPos)(&cp); + if (!PtInRect(&g_monitorClipRect, cp)) + { + clip(cp); + CALL_ORIG_FUNC(SetCursorPos)(cp.x, cp.y); + } + } + } + + void clip(POINT& pt) + { + Compat::ScopedCriticalSection lock(g_cs); + if (!IsRectEmpty(&g_monitorClipRect)) + { + pt.x = std::max(pt.x, g_monitorClipRect.left); + pt.x = std::min(pt.x, g_monitorClipRect.right); + pt.y = std::max(pt.y, g_monitorClipRect.top); + pt.y = std::min(pt.y, g_monitorClipRect.bottom); + } + } + CURSORINFO getEmulatedCursorInfo() { CURSORINFO ci = {}; @@ -139,6 +170,7 @@ namespace Gdi ci.hCursor = nullptr; ci.flags = 0; } + clip(ci.ptScreenPos); } return ci; diff --git a/DDrawCompat/Gdi/Cursor.h b/DDrawCompat/Gdi/Cursor.h index 620bf0a..d98a205 100644 --- a/DDrawCompat/Gdi/Cursor.h +++ b/DDrawCompat/Gdi/Cursor.h @@ -6,6 +6,8 @@ namespace Gdi { namespace Cursor { + void clip(); + void clip(POINT& pt); CURSORINFO getEmulatedCursorInfo(); void installHooks(); bool isEmulated(); diff --git a/DDrawCompat/Gdi/WinProc.cpp b/DDrawCompat/Gdi/WinProc.cpp index 3e985e1..a0820ee 100644 --- a/DDrawCompat/Gdi/WinProc.cpp +++ b/DDrawCompat/Gdi/WinProc.cpp @@ -337,13 +337,20 @@ namespace *lpPoint = *g_cursorPos; return TRUE; } - return CALL_ORIG_FUNC(GetCursorPos)(lpPoint); + + BOOL result = CALL_ORIG_FUNC(GetCursorPos)(lpPoint); + if (result) + { + Gdi::Cursor::clip(*lpPoint); + } + return result; } BOOL WINAPI getMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, decltype(&GetMessageA) origGetMessage) { DDraw::RealPrimarySurface::setUpdateReady(); + Gdi::Cursor::clip(); return origGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); } @@ -564,6 +571,7 @@ namespace decltype(&PeekMessageA) origPeekMessage) { DDraw::RealPrimarySurface::setUpdateReady(); + Gdi::Cursor::clip(); BOOL result = origPeekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); if (!g_isFrameStarted || Config::Settings::FpsLimiter::MSGLOOP != Config::fpsLimiter.get()) {