From 08ef9e2bd94d1b41ef7286660cc0e63c7974c82f Mon Sep 17 00:00:00 2001 From: Ty Lamontagne Date: Thu, 16 Oct 2025 19:01:54 -0400 Subject: [PATCH] Qt: Make mouse screen locking DPI aware Also removed some global mouse hook stuff. Don't ever want to use that anyways. --- common/Windows/WinMisc.cpp | 44 ++------------------------ pcsx2-qt/MainWindow.cpp | 63 +++++++++++++++++++------------------- 2 files changed, 35 insertions(+), 72 deletions(-) diff --git a/common/Windows/WinMisc.cpp b/common/Windows/WinMisc.cpp index b7bdb89d24..5b302cf52c 100644 --- a/common/Windows/WinMisc.cpp +++ b/common/Windows/WinMisc.cpp @@ -100,54 +100,16 @@ void Common::SetMousePosition(int x, int y) SetCursorPos(x, y); } -/* -static HHOOK mouseHook = nullptr; -static std::function fnMouseMoveCb; -LRESULT CALLBACK Mousecb(int nCode, WPARAM wParam, LPARAM lParam) -{ - if (nCode >= 0 && wParam == WM_MOUSEMOVE) - { - MSLLHOOKSTRUCT* mouse = (MSLLHOOKSTRUCT*)lParam; - fnMouseMoveCb(mouse->pt.x, mouse->pt.y); - } - return CallNextHookEx(mouseHook, nCode, wParam, lParam); -} -*/ - -// This (and the above) works, but is not recommended on Windows and is only here for consistency. -// Defer to using raw input instead. bool Common::AttachMousePositionCb(std::function cb) { - /* - if (mouseHook) - Common::DetachMousePositionCb(); - - fnMouseMoveCb = cb; - mouseHook = SetWindowsHookEx(WH_MOUSE_LL, Mousecb, GetModuleHandle(NULL), 0); - if (!mouseHook) - { - Console.Warning("Failed to set mouse hook: %d", GetLastError()); - return false; - } - - #if defined(PCSX2_DEBUG) || defined(PCSX2_DEVBUILD) - static bool warned = false; - if (!warned) - { - Console.Warning("Mouse hooks are enabled, and this isn't a release build! Using a debugger, or loading symbols, _will_ stall the hook and cause global mouse lag."); - warned = true; - } - #endif - */ + // We use raw input messages which are handled by the windows message loop. + // The alternative is to use a low-level mouse hook, but this passes Windows all mouse messages to PCSX2. + // If PCSX2 hangs, or you attach a debugger, the mouse will stop working system-wide. return true; } void Common::DetachMousePositionCb() { - /* - UnhookWindowsHookEx(mouseHook); - mouseHook = nullptr; - */ } bool Common::PlaySoundAsync(const char* path) diff --git a/pcsx2-qt/MainWindow.cpp b/pcsx2-qt/MainWindow.cpp index de4f05280a..3efdddb09e 100644 --- a/pcsx2-qt/MainWindow.cpp +++ b/pcsx2-qt/MainWindow.cpp @@ -2323,19 +2323,24 @@ bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, qintptr if (msg->message == WM_INPUT) { - UINT dwSize = 40; - static BYTE lpb[40]; - if (GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER))) + UINT dwSize = 0; + GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER)); + + if (dwSize > 0) { - const RAWINPUT* raw = (RAWINPUT*)lpb; - if (raw->header.dwType == RIM_TYPEMOUSE) + std::vector lpb(dwSize); + if (GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, lpb.data(), &dwSize, sizeof(RAWINPUTHEADER)) == dwSize) { - const RAWMOUSE& mouse = raw->data.mouse; - if (mouse.usFlags == MOUSE_MOVE_ABSOLUTE || mouse.usFlags == MOUSE_MOVE_RELATIVE) + const RAWINPUT* raw = reinterpret_cast(lpb.data()); + if (raw->header.dwType == RIM_TYPEMOUSE) { - POINT cursorPos; - GetCursorPos(&cursorPos); - checkMousePosition(cursorPos.x, cursorPos.y); + const RAWMOUSE& mouse = raw->data.mouse; + if (mouse.usFlags == MOUSE_MOVE_ABSOLUTE || mouse.usFlags == MOUSE_MOVE_RELATIVE) + { + POINT cursorPos; + if (GetCursorPos(&cursorPos)) + checkMousePosition(cursorPos.x, cursorPos.y); + } } } } @@ -2639,30 +2644,26 @@ void MainWindow::checkMousePosition(int x, int y) if (!shouldMouseLock()) return; - const QPoint globalCursorPos = {x, y}; - QRect windowBounds = isRenderingFullscreen() ? screen()->geometry() : geometry(); - if (windowBounds.contains(globalCursorPos)) + // physical mouse position + const QPoint physicalPos(x, y); + + // logical (DIP) frame rect + QRectF logicalBounds = isRenderingFullscreen() ? screen()->geometry() : geometry(); + + // physical frame rect + const qreal scale = window()->devicePixelRatioF(); + QRectF physicalBounds( + logicalBounds.x() * scale, + logicalBounds.y() * scale, + logicalBounds.width() * scale, + logicalBounds.height() * scale); + + if (physicalBounds.contains(physicalPos)) return; Common::SetMousePosition( - std::clamp(globalCursorPos.x(), windowBounds.left(), windowBounds.right()), - std::clamp(globalCursorPos.y(), windowBounds.top(), windowBounds.bottom())); - - /* - Provided below is how we would handle this if we were using low level hooks (What is used in Common::AttachMouseCb) - We currently use rawmouse on Windows, so Common::SetMousePosition called directly works fine. - */ -#if 0 - // We are currently in a low level hook. SetCursorPos here (what is in Common::SetMousePosition) will not work! - // Let's (a)buse Qt's event loop to dispatch the call at a later time, outside of the hook. - QMetaObject::invokeMethod( - this, [=]() { - Common::SetMousePosition( - std::clamp(globalCursorPos.x(), windowBounds.left(), windowBounds.right()), - std::clamp(globalCursorPos.y(), windowBounds.top(), windowBounds.bottom())); - }, - Qt::QueuedConnection); -#endif + std::clamp(physicalPos.x(), (int)physicalBounds.left(), (int)physicalBounds.right()), + std::clamp(physicalPos.y(), (int)physicalBounds.top(), (int)physicalBounds.bottom())); } void MainWindow::saveDisplayWindowGeometryToConfig()