From ed4b9eeb25c3ffb62da550a7eadc257b0945e248 Mon Sep 17 00:00:00 2001 From: yuanyuanxiang <962914132@qq.com> Date: Fri, 1 May 2026 11:08:12 +0200 Subject: [PATCH] Fix: Web remote desktop double-click not working for macOS clients --- macos/InputHandler.mm | 47 +++++++++++++++----------------- macos/ScreenHandler.mm | 2 +- macos/main.mm | 4 +-- server/2015Remote/WebPage.h | 7 ++++- server/2015Remote/WebService.cpp | 9 ++++++ 5 files changed, 40 insertions(+), 29 deletions(-) diff --git a/macos/InputHandler.mm b/macos/InputHandler.mm index 6e3b6b8..e4f8901 100644 --- a/macos/InputHandler.mm +++ b/macos/InputHandler.mm @@ -156,6 +156,8 @@ void InputHandler::handleMouseButton(CGMouseButton button, bool down, int x, int CGEventRef event = CGEventCreateMouseEvent(NULL, eventType, point, button); if (event) { + // clickState=1 for all single clicks + CGEventSetIntegerValueField(event, kCGMouseEventClickState, 1); CGEventPost(kCGHIDEventTap, event); CFRelease(event); } @@ -163,6 +165,13 @@ void InputHandler::handleMouseButton(CGMouseButton button, bool down, int x, int void InputHandler::handleMouseDoubleClick(CGMouseButton button, int x, int y) { + // WM_LBUTTONDBLCLK represents the second click of a double-click. + // The first click was already sent via WM_LBUTTONDOWN/WM_LBUTTONUP. + // + // We send complete down(2) + up(2) here because: + // - Web client: dblclick fires AFTER mouseup, no subsequent WM_LBUTTONUP + // - MFC client: WM_LBUTTONUP follows, but extra up(1) is harmless + CGPoint point = CGPointMake(x, y); m_lastMousePos = point; @@ -184,36 +193,24 @@ void InputHandler::handleMouseDoubleClick(CGMouseButton button, int x, int y) break; } - // First click (clickState=1) - CGEventRef down1 = CGEventCreateMouseEvent(NULL, downType, point, button); - CGEventRef up1 = CGEventCreateMouseEvent(NULL, upType, point, button); + // Send second click: down(2) + up(2) + CGEventRef down = CGEventCreateMouseEvent(NULL, downType, point, button); + CGEventRef up = CGEventCreateMouseEvent(NULL, upType, point, button); - if (down1 && up1) { - CGEventSetIntegerValueField(down1, kCGMouseEventClickState, 1); - CGEventSetIntegerValueField(up1, kCGMouseEventClickState, 1); - CGEventPost(kCGHIDEventTap, down1); - CGEventPost(kCGHIDEventTap, up1); + if (down) { + CGEventSetIntegerValueField(down, kCGMouseEventClickState, 2); + CGEventPost(kCGHIDEventTap, down); + CFRelease(down); } - if (down1) CFRelease(down1); - if (up1) CFRelease(up1); - - // Brief delay between clicks (50ms) - usleep(50000); - - // Second click (clickState=2) - CGEventRef down2 = CGEventCreateMouseEvent(NULL, downType, point, button); - CGEventRef up2 = CGEventCreateMouseEvent(NULL, upType, point, button); - - if (down2 && up2) { - CGEventSetIntegerValueField(down2, kCGMouseEventClickState, 2); - CGEventSetIntegerValueField(up2, kCGMouseEventClickState, 2); - CGEventPost(kCGHIDEventTap, down2); - CGEventPost(kCGHIDEventTap, up2); + if (up) { + CGEventSetIntegerValueField(up, kCGMouseEventClickState, 2); + CGEventPost(kCGHIDEventTap, up); + CFRelease(up); } - if (down2) CFRelease(down2); - if (up2) CFRelease(up2); + // Note: For MFC client, an extra WM_LBUTTONUP will follow (sending up(1)), + // but this is harmless since mouse is already up. } void InputHandler::handleMouseWheel(int delta) diff --git a/macos/ScreenHandler.mm b/macos/ScreenHandler.mm index 9ada1b7..2ac622e 100644 --- a/macos/ScreenHandler.mm +++ b/macos/ScreenHandler.mm @@ -25,7 +25,7 @@ ScreenHandler::ScreenHandler(IOCPClient* client) , m_algorithm(ALGORITHM_H264) , m_maxFPS(15) , m_qualityLevel(QUALITY_GOOD) // Use fixed QUALITY_GOOD (H264) for web compatibility - , m_h264Bitrate(2000000) // 2 Mbps default + , m_h264Bitrate(3000000) // 3 Mbps (matches Windows QUALITY_GOOD) { memset(&m_bmpHeader, 0, sizeof(m_bmpHeader)); diff --git a/macos/main.mm b/macos/main.mm index e722f9e..81f673e 100644 --- a/macos/main.mm +++ b/macos/main.mm @@ -272,8 +272,8 @@ static void fillLoginInfo(LOGIN_INFOR& info) // Reserved fields (pipe-separated, must match Windows client order) // Order: Type|Bits|Cores|Memory|Path|?|InstallTime|?|ProgBits|Auth|Location|IP|Version|User|IsAdmin|Resolution|ClientID - // 1. Client type - info.AddReserved("macOS"); + // 1. Client type (use GetClientType for consistency with Windows client) + info.AddReserved(GetClientType(CLIENT_TYPE_MACOS)); // 2. System bits (OS bits, always 64 on modern macOS) info.AddReserved(64); diff --git a/server/2015Remote/WebPage.h b/server/2015Remote/WebPage.h index b230a4a..5bd7fdf 100644 --- a/server/2015Remote/WebPage.h +++ b/server/2015Remote/WebPage.h @@ -2696,7 +2696,12 @@ inline std::string GetWebPageHTML() { sendMouse('up', pos.x, pos.y, e.button); }); - // Note: dblclick is handled by mousedown-mouseup sequence, no separate handler needed + // dblclick handler - server will forward only to macOS clients + canvas.addEventListener('dblclick', function(e) { + e.preventDefault(); + const pos = getMousePos(e); + sendMouse('dblclick', pos.x, pos.y, e.button); + }); canvas.addEventListener('mousemove', function(e) { const now = Date.now(); diff --git a/server/2015Remote/WebService.cpp b/server/2015Remote/WebService.cpp index 183897c..601605d 100644 --- a/server/2015Remote/WebService.cpp +++ b/server/2015Remote/WebService.cpp @@ -770,6 +770,15 @@ void CWebService::HandleMouse(void* ws_ptr, const std::string& msg) { short wheelDelta = (short)(delta > 0 ? -120 : (delta < 0 ? 120 : 0)); msg64.wParam = MAKEWPARAM(0, wheelDelta); } else if (type == "dblclick") { + // dblclick is only needed for macOS clients + // Windows detects double-click from rapid mousedown/mouseup sequence + context* mainCtx = m_pParentDlg->FindHost(device_id); + if (!mainCtx) return; + CString clientType = mainCtx->GetAdditionalData(RES_CLIENT_TYPE); + // Check for both "MAC" (new) and "macOS" (legacy) for compatibility + if (clientType != GetClientType(CLIENT_TYPE_MACOS) && clientType != "macOS") { + return; // Skip dblclick for non-macOS clients + } if (button == 0) { msg64.message = WM_LBUTTONDBLCLK; msg64.wParam = MK_LBUTTON;