From 36f72131621115b71c35f47653c61fbd113fc513 Mon Sep 17 00:00:00 2001 From: dijunkun Date: Sun, 18 Oct 2026 22:09:35 +0800 Subject: [PATCH] [feat] allow pinch zoom outside the remote image on mobile --- apps/android/README.md | 2 +- .../src/main/java/cn/crossdesk/mobile/RemoteVideoView.java | 3 ++- apps/ios/CrossDeskMobile/Input/RemoteTouchInputView.swift | 7 ++++--- apps/ios/README.md | 5 +++++ 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/android/README.md b/apps/android/README.md index 404e3b45..8e029a26 100644 --- a/apps/android/README.md +++ b/apps/android/README.md @@ -7,7 +7,7 @@ - 官方或自托管 WSS 信令服务器;授权后进入前台即自动注册或登录本机身份,首页实时显示连接、重连及失败状态。发起桌面连接时复用该身份;切换服务器会重新登录,撤回授权会关闭连接。已有远程会话优先通过系统画中画保持连接,画中画不可用时由带连接通知的前台服务兜底;首页空闲信令在后台关闭。 - 优先使用 MediaCodec 硬件解码 H.264 / AV1,硬件缓冲区直接提交 Surface;设备无对应硬件、分辨率超限或运行失败时,按原编码格式回退到 OpenH264 / dav1d。软件输出由独立显示线程将 NV12 转 RGBA;只保留最新待显示帧。MiniRTC 原有的通用压缩帧解码队列保持不变。 - 48 kHz 单声道 PCM 播放,支持静音,音频队列有容量限制。 -- 相对鼠标(触控板)和绝对位置模式;单指点击、绝对模式按住拖动、长按右键,以及外接键盘、鼠标。画面手势与 iOS 一致:双指捏合以触点为中心缩放(1–10 倍),放大后双指拖动画面,原始比例下双指上下滑动控制滚轮。相对鼠标移到可见画面的上、下边缘后继续向外移动,会反向上下平移画面,不触发左右平移;未放大时和按住虚拟鼠标键拖动时同样生效,停止移动即停止平移,抬手保留位置。移动到极限时,画面可见部分至少占当前显示区域高度的 20%,与缩放倍数无关;整幅画面高度不足该比例时完整保留,范围计入上下黑边;缩放结束及缩回 1 倍时保留平移位置,仅在超过可见边界时限制位置;切换显示器恢复居中。 +- 相对鼠标(触控板)和绝对位置模式;单指点击、绝对模式按住拖动、长按右键,以及外接键盘、鼠标。画面手势与 iOS 一致:双指可在整个触控区域(包括画面外黑边)捏合,以触点为中心缩放(1–10 倍),放大后双指拖动画面,原始比例下双指上下滑动控制滚轮。相对鼠标移到可见画面的上、下边缘后继续向外移动,会反向上下平移画面,不触发左右平移;未放大时和按住虚拟鼠标键拖动时同样生效,停止移动即停止平移,抬手保留位置。移动到极限时,画面可见部分至少占当前显示区域高度的 20%,与缩放倍数无关;整幅画面高度不足该比例时完整保留,范围计入上下黑边;缩放结束及缩回 1 倍时保留平移位置,仅在超过可见边界时限制位置;切换显示器恢复居中。 - 横竖屏等比例显示、远端多显示器切换。与 iOS 一致的画面质量(低/中/高)、采集帧率(30/60 fps)、画面偏好;支持能力检测、电脑端确认、失败/5 秒超时回退及连续操作的应答排序。 - 根据常见移动设备解码能力和屏幕尺寸设置起始参数:显示长边不超过 1280 像素时默认低画质(最高 720p)/30 fps,其余默认中画质(最高 1080p)/30 fps。用户保存的画面偏好不变,仍可手动选择高画质或 60 fps。 - 网络状态按视频、音频、数据、合计展示收发速率和丢包率,并显示实际提交帧率、分辨率、画面延时、平滑 RTT、P2P/TURN 和实际 SRTP 状态。每秒刷新,过期或无效测量显示“—”。 diff --git a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteVideoView.java b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteVideoView.java index 5fad0b57..2e9f770a 100644 --- a/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteVideoView.java +++ b/apps/android/app/src/main/java/cn/crossdesk/mobile/RemoteVideoView.java @@ -78,7 +78,8 @@ final class RemoteVideoView extends FrameLayout implements SurfaceHolder.Callbac scales = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() { @Override public boolean onScaleBegin(ScaleGestureDetector detector) { if (mouseInput.hasVirtualButton()) return false; - if (!viewport.contains(detector.getFocusX(), detector.getFocusY())) return false; + // Pinches can start anywhere on the touch surface, including letterboxing. + if (viewport.width() <= 0 || viewport.height() <= 0) return false; viewportGesture = true; viewportPanActive = true; return true; diff --git a/apps/ios/CrossDeskMobile/Input/RemoteTouchInputView.swift b/apps/ios/CrossDeskMobile/Input/RemoteTouchInputView.swift index 54b944e7..9c865280 100644 --- a/apps/ios/CrossDeskMobile/Input/RemoteTouchInputView.swift +++ b/apps/ios/CrossDeskMobile/Input/RemoteTouchInputView.swift @@ -375,7 +375,8 @@ final class RemoteTouchSurface: UIView, UIGestureRecognizerDelegate { let focus = recognizer.location(in: self) switch recognizer.state { case .began: - pinchActive = renderRect()?.contains(focus) == true + // The full touch surface accepts pinches, including letterboxing. + pinchActive = bounds.contains(focus) && renderRect() != nil recognizer.scale = 1 case .changed: guard pinchActive else { return } @@ -414,13 +415,13 @@ final class RemoteTouchSurface: UIView, UIGestureRecognizerDelegate { if viewportScale > 1.001 || pinchActive { switch recognizer.state { case .began: - viewportPanActive = renderRect()?.contains( + viewportPanActive = pinchActive || renderRect()?.contains( recognizer.location(in: self) ) == true recognizer.setTranslation(.zero, in: self) case .changed: if !viewportPanActive { - viewportPanActive = renderRect()?.contains( + viewportPanActive = pinchActive || renderRect()?.contains( recognizer.location(in: self) ) == true } diff --git a/apps/ios/README.md b/apps/ios/README.md index b416c2eb..95504bbd 100644 --- a/apps/ios/README.md +++ b/apps/ios/README.md @@ -431,6 +431,11 @@ Old previews saved without this choice are removed on upgrade. ## Pointer edge panning +Pinch-to-zoom can start anywhere on the touch surface, including black margins +outside the image, in either pointer mode. A pinch also follows the fingers' +midpoint movement when it starts in a margin. Held virtual mouse buttons still +prevent viewport gestures. + In relative mouse mode, continuing to move outward at the top or bottom of the visible image pans the video vertically in the opposite direction. Moving down-left at the bottom edge pans upward without shifting the video horizontally;