1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Improved DPI unaware cursor positioning

See issue #342.
This commit is contained in:
narzoul 2024-08-24 16:02:36 +02:00
parent 16b062d17d
commit f78a96a334
2 changed files with 53 additions and 71 deletions

View File

@ -215,7 +215,7 @@ namespace Gdi
POINT pos = {}; POINT pos = {};
CALL_ORIG_FUNC(GetCursorPos)(&pos); CALL_ORIG_FUNC(GetCursorPos)(&pos);
CALL_ORIG_FUNC(SetCursorPos)(pos.x, pos.y); SetCursorPos(pos.x, pos.y);
} }
void setMonitorClipRect(const RECT& rect) void setMonitorClipRect(const RECT& rect)

View File

@ -21,6 +21,7 @@
#include <Overlay/Steam.h> #include <Overlay/Steam.h>
#include <Overlay/Window.h> #include <Overlay/Window.h>
#include <Win32/DisplayMode.h> #include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
namespace namespace
{ {
@ -29,7 +30,6 @@ namespace
HOOKPROC origHookProc; HOOKPROC origHookProc;
LPARAM origHookStruct; LPARAM origHookStruct;
MSLLHOOKSTRUCT hookStruct; MSLLHOOKSTRUCT hookStruct;
DWORD dpiScale;
}; };
struct HotKeyData struct HotKeyData
@ -43,7 +43,6 @@ namespace
SIZE g_bmpArrowSize = {}; SIZE g_bmpArrowSize = {};
Overlay::Control* g_capture = nullptr; Overlay::Control* g_capture = nullptr;
POINT g_cursorPos = {}; POINT g_cursorPos = {};
POINT g_origCursorPos = { MAXLONG, MAXLONG };
HWND g_cursorWindow = nullptr; HWND g_cursorWindow = nullptr;
std::map<Input::HotKey, HotKeyData> g_hotKeys; std::map<Input::HotKey, HotKeyData> g_hotKeys;
RECT g_monitorRect = {}; RECT g_monitorRect = {};
@ -56,7 +55,7 @@ namespace
LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK lowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK lowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam);
POINT physicalToLogicalPoint(POINT pt, DWORD dpiScale); POINT physicalToLogicalPoint(POINT pt);
LRESULT CALLBACK cursorWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK cursorWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
@ -106,7 +105,22 @@ namespace
if (WM_MOUSEMOVE == wParam) if (WM_MOUSEMOVE == wParam)
{ {
data.hookStruct.pt = physicalToLogicalPoint(data.hookStruct.pt, data.dpiScale); if (Win32::DpiAwareness::isMixedModeSupported())
{
POINT logicalCursorPos = {};
GetCursorPos(&logicalCursorPos);
Win32::ScopedDpiAwareness dpiAwareness;
POINT physicalCursorPos = {};
GetCursorPos(&physicalCursorPos);
data.hookStruct.pt.x = logicalCursorPos.x + data.hookStruct.pt.x - physicalCursorPos.x;
data.hookStruct.pt.y = logicalCursorPos.y + data.hookStruct.pt.y - physicalCursorPos.y;
}
else
{
data.hookStruct.pt = physicalToLogicalPoint(data.hookStruct.pt);
}
} }
else else
{ {
@ -118,13 +132,6 @@ namespace
return g_dinputMouseHookData.origHookProc(nCode, wParam, lParam); return g_dinputMouseHookData.origHookProc(nCode, wParam, lParam);
} }
DWORD getDpiScaleForCursorPos()
{
POINT cp = {};
CALL_ORIG_FUNC(GetCursorPos)(&cp);
return Win32::DisplayMode::getMonitorInfo(cp).dpiScale;
}
LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{ {
if (HC_ACTION == nCode && if (HC_ACTION == nCode &&
@ -178,25 +185,23 @@ namespace
if (WM_MOUSEMOVE == wParam) if (WM_MOUSEMOVE == wParam)
{ {
if (MAXLONG == g_origCursorPos.y) POINT origCursorPos = {};
POINT newCursorPos = llHook.pt;
if (Win32::DpiAwareness::isMixedModeSupported())
{ {
if (llHook.flags & LLMHF_INJECTED) Win32::ScopedDpiAwareness dpiAwareness;
{ CALL_ORIG_FUNC(GetCursorPos)(&origCursorPos);
if (MAXLONG == g_origCursorPos.x) llHook.pt = {};
{ }
g_origCursorPos.x = llHook.pt.x; else
} {
else CALL_ORIG_FUNC(GetCursorPos)(&origCursorPos);
{ newCursorPos = physicalToLogicalPoint(llHook.pt);
g_origCursorPos.y = llHook.pt.y;
}
}
return 1;
} }
POINT cp = g_cursorPos; POINT cp = g_cursorPos;
cp.x += llHook.pt.x - g_origCursorPos.x; cp.x += newCursorPos.x - origCursorPos.x;
cp.y += llHook.pt.y - g_origCursorPos.y; cp.y += newCursorPos.y - origCursorPos.y;
cp.x = std::min(std::max(g_monitorRect.left, cp.x), g_monitorRect.right); cp.x = std::min(std::max(g_monitorRect.left, cp.x), g_monitorRect.right);
cp.y = std::min(std::max(g_monitorRect.top, cp.y), g_monitorRect.bottom); cp.y = std::min(std::max(g_monitorRect.top, cp.y), g_monitorRect.bottom);
g_cursorPos = cp; g_cursorPos = cp;
@ -240,13 +245,14 @@ namespace
TerminateProcess(GetCurrentProcess(), 0); TerminateProcess(GetCurrentProcess(), 0);
} }
POINT physicalToLogicalPoint(POINT pt, DWORD dpiScale) POINT physicalToLogicalPoint(POINT pt)
{ {
if (g_physicalToLogicalPointForPerMonitorDPI) if (g_physicalToLogicalPointForPerMonitorDPI)
{ {
g_physicalToLogicalPointForPerMonitorDPI(nullptr, &pt); g_physicalToLogicalPointForPerMonitorDPI(nullptr, &pt);
return pt; return pt;
} }
auto dpiScale = Win32::DisplayMode::getMonitorInfo(pt).dpiScale;
return { MulDiv(pt.x, 100, dpiScale), MulDiv(pt.y, 100, dpiScale) }; return { MulDiv(pt.x, 100, dpiScale), MulDiv(pt.y, 100, dpiScale) };
} }
@ -287,46 +293,28 @@ namespace
}); });
} }
void resetMouseHookFunc()
{
if (g_mouseHook)
{
UnhookWindowsHookEx(g_mouseHook);
}
g_origCursorPos = { MAXLONG, MAXLONG };
g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)(
WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_origDDrawModule, 0);
if (g_mouseHook)
{
INPUT inputs[2] = {};
inputs[0].mi.dy = 1;
inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE;
inputs[1].mi.dx = 1;
inputs[1].mi.dwFlags = MOUSEEVENTF_MOVE;
SendInput(2, inputs, sizeof(INPUT));
}
else
{
LOG_ONCE("ERROR: Failed to install low level mouse hook, error code: " << GetLastError());
}
}
void resetMouseHook() void resetMouseHook()
{ {
Gdi::GuiThread::executeAsyncFunc(resetMouseHookFunc); Gdi::GuiThread::execute([]()
} {
if (!g_capture)
{
return;
}
BOOL WINAPI setCursorPos(int X, int Y) if (g_mouseHook)
{ {
LOG_FUNC("SetCursorPos", X, Y); UnhookWindowsHookEx(g_mouseHook);
auto result = CALL_ORIG_FUNC(SetCursorPos)(X, Y); }
if (result && g_mouseHook)
{ g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)(
resetMouseHook(); WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_origDDrawModule, 0);
}
return LOG_RESULT(result); if (!g_mouseHook)
{
LOG_ONCE("ERROR: Failed to install low level mouse hook, error code: " << GetLastError());
}
});
} }
HHOOK setWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId, HHOOK setWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId,
@ -345,11 +333,6 @@ namespace
(0 == _stricmp(moduleName.c_str(), "dinput") || 0 == _stricmp(moduleName.c_str(), "dinput8"))) (0 == _stricmp(moduleName.c_str(), "dinput") || 0 == _stricmp(moduleName.c_str(), "dinput8")))
{ {
g_dinputMouseHookData.origHookProc = lpfn; g_dinputMouseHookData.origHookProc = lpfn;
if (!g_physicalToLogicalPointForPerMonitorDPI)
{
g_dinputMouseHookData.dpiScale = getDpiScaleForCursorPos();
}
lpfn = dinputLowLevelMouseProc; lpfn = dinputLowLevelMouseProc;
Compat::hookIatFunction(hmod, "CallNextHookEx", dinputCallNextHookEx); Compat::hookIatFunction(hmod, "CallNextHookEx", dinputCallNextHookEx);
} }
@ -441,7 +424,6 @@ namespace Input
GetProcAddress(GetModuleHandle("user32"), "PhysicalToLogicalPointForPerMonitorDPI")); GetProcAddress(GetModuleHandle("user32"), "PhysicalToLogicalPointForPerMonitorDPI"));
HOOK_FUNCTION(user32, RegisterRawInputDevices, registerRawInputDevices); HOOK_FUNCTION(user32, RegisterRawInputDevices, registerRawInputDevices);
HOOK_FUNCTION(user32, SetCursorPos, setCursorPos);
HOOK_FUNCTION(user32, SetWindowsHookExA, setWindowsHookExA); HOOK_FUNCTION(user32, SetWindowsHookExA, setWindowsHookExA);
HOOK_FUNCTION(user32, SetWindowsHookExW, setWindowsHookExW); HOOK_FUNCTION(user32, SetWindowsHookExW, setWindowsHookExW);