From 672364d2acb01d3c288f496914f1c7e4af96bf21 Mon Sep 17 00:00:00 2001 From: KHeartz Date: Sat, 11 Jul 2026 17:00:30 -0400 Subject: [PATCH] GUI: fix wheel coords, drag state and dblclick in the CEF mouse path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three delivery bugs in View::ProcessMouseEvent, found via the F8 dev menu's teleport list: - WM_MOUSEWHEEL reports the cursor in screen coordinates (every other mouse message is client-relative) — convert with ScreenToClient before mapping into the view, so wheel events land on the element actually under the cursor when the client origin isn't at (0,0). - Events were sent with modifiers = 0; Blink sustains drags (scrollbar thumb, text selection) off the button flags carried by the move events, so every drag ended instantly. Forward the live MK_* button and Ctrl/Shift state from wParam (low word for the wheel message). - WM_LBUTTONDBLCLK was unhandled: the game window class has CS_DBLCLKS, so the second rapid click arrived as DBLCLK and was swallowed. Send it as a click_count=2 press so fast repeated clicks and page dblclick handlers work. --- code/framework/src/gui/view.cpp | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/code/framework/src/gui/view.cpp b/code/framework/src/gui/view.cpp index f97ad5eb8..7a09b382f 100644 --- a/code/framework/src/gui/view.cpp +++ b/code/framework/src/gui/view.cpp @@ -156,6 +156,19 @@ namespace Framework::GUI { } } + // MK_* button/modifier state from a mouse message's wParam, as CEF event flags. + // Blink sustains drags (scrollbar thumb, text selection) off the button flags + // carried by the move events, so these must reflect the live state. + static uint32_t CefMouseModifiers(WPARAM wParam) { + uint32_t mods = 0; + if (wParam & MK_CONTROL) mods |= EVENTFLAG_CONTROL_DOWN; + if (wParam & MK_SHIFT) mods |= EVENTFLAG_SHIFT_DOWN; + if (wParam & MK_LBUTTON) mods |= EVENTFLAG_LEFT_MOUSE_BUTTON; + if (wParam & MK_MBUTTON) mods |= EVENTFLAG_MIDDLE_MOUSE_BUTTON; + if (wParam & MK_RBUTTON) mods |= EVENTFLAG_RIGHT_MOUSE_BUTTON; + return mods; + } + void View::ProcessMouseEvent(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (!_browser || !_shouldDisplay || !_hasFocus) { return; @@ -163,12 +176,16 @@ namespace Framework::GUI { auto host = _browser->GetHost(); - // Handle mouse wheel separately + // Handle mouse wheel separately. Unlike the client-relative messages below, + // WM_MOUSEWHEEL reports the cursor in screen coordinates, and packs the + // button/modifier state into the low word of wParam. if (msg == WM_MOUSEWHEEL) { + POINT pt {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; + ::ScreenToClient(hWnd, &pt); CefMouseEvent cefEvent; - cefEvent.x = GET_X_LPARAM(lParam) - _x; - cefEvent.y = GET_Y_LPARAM(lParam) - _y; - cefEvent.modifiers = 0; + cefEvent.x = pt.x - _x; + cefEvent.y = pt.y - _y; + cefEvent.modifiers = CefMouseModifiers(GET_KEYSTATE_WPARAM(wParam)); int delta = GET_WHEEL_DELTA_WPARAM(wParam); host->SendMouseWheelEvent(cefEvent, 0, delta); return; @@ -177,7 +194,7 @@ namespace Framework::GUI { CefMouseEvent cefEvent; cefEvent.x = GET_X_LPARAM(lParam) - _x; cefEvent.y = GET_Y_LPARAM(lParam) - _y; - cefEvent.modifiers = 0; + cefEvent.modifiers = CefMouseModifiers(wParam); switch (msg) { case WM_MOUSEMOVE: { @@ -188,6 +205,10 @@ namespace Framework::GUI { _isMouseDown = true; host->SendMouseClickEvent(cefEvent, MBT_LEFT, false, 1); } break; + case WM_LBUTTONDBLCLK: { + _isMouseDown = true; + host->SendMouseClickEvent(cefEvent, MBT_LEFT, false, 2); + } break; case WM_LBUTTONUP: { _isMouseDown = false; host->SendMouseClickEvent(cefEvent, MBT_LEFT, true, 1);