Fix: Web remote desktop double-click not working for macOS clients
This commit is contained in:
@@ -156,6 +156,8 @@ void InputHandler::handleMouseButton(CGMouseButton button, bool down, int x, int
|
|||||||
|
|
||||||
CGEventRef event = CGEventCreateMouseEvent(NULL, eventType, point, button);
|
CGEventRef event = CGEventCreateMouseEvent(NULL, eventType, point, button);
|
||||||
if (event) {
|
if (event) {
|
||||||
|
// clickState=1 for all single clicks
|
||||||
|
CGEventSetIntegerValueField(event, kCGMouseEventClickState, 1);
|
||||||
CGEventPost(kCGHIDEventTap, event);
|
CGEventPost(kCGHIDEventTap, event);
|
||||||
CFRelease(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)
|
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);
|
CGPoint point = CGPointMake(x, y);
|
||||||
m_lastMousePos = point;
|
m_lastMousePos = point;
|
||||||
|
|
||||||
@@ -184,36 +193,24 @@ void InputHandler::handleMouseDoubleClick(CGMouseButton button, int x, int y)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First click (clickState=1)
|
// Send second click: down(2) + up(2)
|
||||||
CGEventRef down1 = CGEventCreateMouseEvent(NULL, downType, point, button);
|
CGEventRef down = CGEventCreateMouseEvent(NULL, downType, point, button);
|
||||||
CGEventRef up1 = CGEventCreateMouseEvent(NULL, upType, point, button);
|
CGEventRef up = CGEventCreateMouseEvent(NULL, upType, point, button);
|
||||||
|
|
||||||
if (down1 && up1) {
|
if (down) {
|
||||||
CGEventSetIntegerValueField(down1, kCGMouseEventClickState, 1);
|
CGEventSetIntegerValueField(down, kCGMouseEventClickState, 2);
|
||||||
CGEventSetIntegerValueField(up1, kCGMouseEventClickState, 1);
|
CGEventPost(kCGHIDEventTap, down);
|
||||||
CGEventPost(kCGHIDEventTap, down1);
|
CFRelease(down);
|
||||||
CGEventPost(kCGHIDEventTap, up1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (down1) CFRelease(down1);
|
if (up) {
|
||||||
if (up1) CFRelease(up1);
|
CGEventSetIntegerValueField(up, kCGMouseEventClickState, 2);
|
||||||
|
CGEventPost(kCGHIDEventTap, up);
|
||||||
// Brief delay between clicks (50ms)
|
CFRelease(up);
|
||||||
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 (down2) CFRelease(down2);
|
// Note: For MFC client, an extra WM_LBUTTONUP will follow (sending up(1)),
|
||||||
if (up2) CFRelease(up2);
|
// but this is harmless since mouse is already up.
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputHandler::handleMouseWheel(int delta)
|
void InputHandler::handleMouseWheel(int delta)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ ScreenHandler::ScreenHandler(IOCPClient* client)
|
|||||||
, m_algorithm(ALGORITHM_H264)
|
, m_algorithm(ALGORITHM_H264)
|
||||||
, m_maxFPS(15)
|
, m_maxFPS(15)
|
||||||
, m_qualityLevel(QUALITY_GOOD) // Use fixed QUALITY_GOOD (H264) for web compatibility
|
, 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));
|
memset(&m_bmpHeader, 0, sizeof(m_bmpHeader));
|
||||||
|
|
||||||
|
|||||||
@@ -272,8 +272,8 @@ static void fillLoginInfo(LOGIN_INFOR& info)
|
|||||||
// Reserved fields (pipe-separated, must match Windows client order)
|
// 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
|
// Order: Type|Bits|Cores|Memory|Path|?|InstallTime|?|ProgBits|Auth|Location|IP|Version|User|IsAdmin|Resolution|ClientID
|
||||||
|
|
||||||
// 1. Client type
|
// 1. Client type (use GetClientType for consistency with Windows client)
|
||||||
info.AddReserved("macOS");
|
info.AddReserved(GetClientType(CLIENT_TYPE_MACOS));
|
||||||
|
|
||||||
// 2. System bits (OS bits, always 64 on modern macOS)
|
// 2. System bits (OS bits, always 64 on modern macOS)
|
||||||
info.AddReserved(64);
|
info.AddReserved(64);
|
||||||
|
|||||||
@@ -2696,7 +2696,12 @@ inline std::string GetWebPageHTML() {
|
|||||||
sendMouse('up', pos.x, pos.y, e.button);
|
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) {
|
canvas.addEventListener('mousemove', function(e) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
|||||||
@@ -770,6 +770,15 @@ void CWebService::HandleMouse(void* ws_ptr, const std::string& msg) {
|
|||||||
short wheelDelta = (short)(delta > 0 ? -120 : (delta < 0 ? 120 : 0));
|
short wheelDelta = (short)(delta > 0 ? -120 : (delta < 0 ? 120 : 0));
|
||||||
msg64.wParam = MAKEWPARAM(0, wheelDelta);
|
msg64.wParam = MAKEWPARAM(0, wheelDelta);
|
||||||
} else if (type == "dblclick") {
|
} 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) {
|
if (button == 0) {
|
||||||
msg64.message = WM_LBUTTONDBLCLK;
|
msg64.message = WM_LBUTTONDBLCLK;
|
||||||
msg64.wParam = MK_LBUTTON;
|
msg64.wParam = MK_LBUTTON;
|
||||||
|
|||||||
Reference in New Issue
Block a user