From 744ebfba0d5050bffcec10b59c11fc848b20b6ba Mon Sep 17 00:00:00 2001 From: yuanyuanxiang <962914132@qq.com> Date: Fri, 15 May 2026 01:42:31 +0200 Subject: [PATCH] Improve(Web): Headless host opens terminal fix two-finger scroll speed and zoom misdetect --- server/2015Remote/WebPage.h | 64 +++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/server/2015Remote/WebPage.h b/server/2015Remote/WebPage.h index 44e151a..dcc41b9 100644 --- a/server/2015Remote/WebPage.h +++ b/server/2015Remote/WebPage.h @@ -2059,13 +2059,22 @@ inline std::string GetWebPageHTML() { // Part 8b1: Device connect / terminal session (split to avoid MSVC string literal length limit) html += R"HTML( function connectDevice(id) { - const compat = checkWebCodecs(); - if (!compat.supported) { alert('Browser does not support H264: ' + compat.reason); return; } - currentDevice = devices.find(d => d.id === id || d.id === String(id)); - if (!currentDevice || !currentDevice.online) { + const dev = devices.find(d => d.id === id || d.id === String(id)); + if (!dev || !dev.online) { alert('Device is offline'); return; } + // 无显示器(screen 字段格式 "n:WxH",n=0 表示无显示器)→ 远程桌面没有意义, + // 直接走终端。 + const screenStr = String(dev.screen || ''); + const screenCount = parseInt(screenStr.split(':')[0], 10); + if (!isNaN(screenCount) && screenCount === 0) { + openTerminal(id); + return; + } + const compat = checkWebCodecs(); + if (!compat.supported) { alert('Browser does not support H264: ' + compat.reason); return; } + currentDevice = dev; document.getElementById('device-name').textContent = currentDevice.name; document.getElementById('frame-info').textContent = ''; updateScreenStatus('connecting'); @@ -2574,9 +2583,20 @@ inline std::string GetWebPageHTML() { // Part 14b: JavaScript - Zoom state and touch helpers html += R"HTML( // Two-finger gesture constants - const ZOOM_THRESHOLD = 0.05; // 5% distance change to trigger zoom - const SCROLL_SENSITIVITY = 3; // Scroll speed multiplier - const SCROLL_DEADZONE = 2; // Minimum scroll delta to send + // 缩放 vs 滚动判定(仅在双指 + 触摸场景): + // 1) 间距比例变化 > ZOOM_THRESHOLD 且 + // 2) 间距绝对变化 > ZOOM_MIN_PX 且 + // 3) 间距变化 > 中心垂直位移 → 判为缩放 + // 三个条件同时满足才触发缩放,避免双指上下滚动时手指自然张合的 ~5% 抖动被误判。 + // 真实缩放:双指主动张合,间距变化幅度本身就远大于这些阈值。 + const ZOOM_THRESHOLD = 0.15; // 间距比例变化阈值(15%) + const ZOOM_MIN_PX = 30; // 间距绝对变化阈值(px) + // 注:服务端 (WebService.cpp HandleMouse) 把 wheelDelta 钳成 ±120 一格 notch, + // SCROLL_SENSITIVITY 实际不起作用;真正决定滚动速度的是 SCROLL_DEADZONE。 + // 触摸 touchmove 在 60fps 下高频触发,旧值 2px 等于手指动一下就连发一堆 notch,体感非常飘。 + // 现在 28px ≈ 让手指移动 ~1 个文本行距离才发一格,接近 iOS 原生触摸滚动节奏。 + const SCROLL_SENSITIVITY = 1; // (server clamps to ±120, kept for clarity only) + const SCROLL_DEADZONE = 28; // Minimum finger-Y delta (px) to send one wheel notch // Pinch-to-zoom state let zoomState = { @@ -2595,7 +2615,9 @@ inline std::string GetWebPageHTML() { // Two-finger gesture detection hasZoomed: false, // Whether zoom occurred in current gesture lastScrollY: 0, // For scroll delta calculation - initialPinchDist: 0 // Distance at gesture start (for cumulative detection) + initialPinchDist: 0, // Distance at gesture start (for cumulative detection) + initialCenterX: 0, // Pinch center at gesture start (for scroll-vs-zoom intent) + initialCenterY: 0 }; const zoomIndicator = document.getElementById('zoom-indicator'); let zoomIndicatorTimer = null; @@ -2801,6 +2823,8 @@ inline std::string GetWebPageHTML() { const center = getPinchCenter(e.touches); zoomState.pinchCenterX = center.x; zoomState.pinchCenterY = center.y; + zoomState.initialCenterX = center.x; + zoomState.initialCenterY = center.y; zoomState.lastScrollY = center.y; if (zoomState.scale === 1) { @@ -2904,16 +2928,28 @@ inline std::string GetWebPageHTML() { const totalDelta = newDist / zoomState.initialPinchDist; // Cumulative change from gesture start // Detect gesture type: zoom vs scroll - // Use CUMULATIVE change to detect zoom intent (catches slow pinch gestures) - // Also treat as zoom if already at scale boundary and trying to zoom further + // 缩放意图 = 间距比例显著变 + 间距绝对显著变 + 间距变化 > 中心垂直位移 + // 单纯比例阈值 5% 太敏感:双指上下滚动时手指自然张合 ~5% 就被误判为缩放。 + // 结合绝对像素阈值 + "间距变化 vs 中心位移" 的方向性,能稳定区分两种意图。 + const distAbsChange = Math.abs(newDist - zoomState.initialPinchDist); + const distRatioChange = Math.abs(totalDelta - 1); + const centerMoveY = Math.abs(newCenter.y - zoomState.initialCenterY); + + const isClearZoom = distRatioChange > ZOOM_THRESHOLD && + distAbsChange > ZOOM_MIN_PX && + distAbsChange > centerMoveY; + + // 已到缩放边界仍朝同方向尝试 → 给视觉反馈,但要求绝对像素变化 > 半阈值, + // 避免静止时手指轻微抖动也被认为"想缩放"。 const atMinScale = zoomState.scale <= zoomState.minScale; const atMaxScale = zoomState.scale >= zoomState.maxScale; - const tryingToShrink = totalDelta < 1; // Use cumulative for direction + const tryingToShrink = totalDelta < 1; const tryingToEnlarge = totalDelta > 1; + const boundaryFeedback = distAbsChange > ZOOM_MIN_PX / 2 && ( + (atMinScale && tryingToShrink) || (atMaxScale && tryingToEnlarge) + ); - if (Math.abs(totalDelta - 1) > ZOOM_THRESHOLD || - (atMinScale && tryingToShrink) || - (atMaxScale && tryingToEnlarge)) { + if (isClearZoom || boundaryFeedback) { zoomState.hasZoomed = true; }