vdi-cloud/docs/independent-cursor-feasibility-20261103.md

56 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 独立光标原型可行性实测(2026-11-03)
> 2026-11-05更新:Linux两台主机已接入不同于本原型的认证SSH原生光标方案,见[实施记录](linux-native-cursor-20261105.md)。本页保留11月3日Windows受控实验;Windows仍走原视频光标,正式双方控制协议尚未实现。
## 结论和当前现场
本地独立移动和 Windows 光标静态形状显示可行,值得继续开发 Sunshine + Moonlight 的正式同步协议。本轮完成了真实盒子和 VM100 的受控原型,不是仅做源码调研。但是自动形状同步、视频帧交接、断线回退尚未成为产品功能,不能默认启用,也不能称鼠标或窗口零延迟。
测试已结束,Windows 临时任务 VDICursorPOC 已停止并删除。正常 Moonlight PID31694、2560×1440/45FPS、RKMPP/EGL 和原二进制 SHA256 `35de7b1a4ade583823b23b5f2e012307f6d0a3848c8eb97bd6d4de9660afa00f` 保留。VDD读回 DISPLAY3、2560×1440@60。最后确认本地指针为全透明1×1,屏幕里只有正常Windows远程白色光标;没有遗留测试辅助进程。GTX965M错误码0,编码占用11%,Sunshine该正常会话创建了h264_nvenc。没有重启机器、修改GPU固件/直通、Windows鼠标主题或正式客户端配置。
## 原型做了什么
Windows已登录用户会话运行临时测试窗口,用 GetCursorInfo 读取实际光标状态;GetIconInfo/DrawIconEx 导出默认箭头、文字、左右缩放、忙碌四种真实Windows形状,均为32×32,热点分别为(0,0)、(8,9)、(11,4)、(16,16)。导出仅复制资源并释放 GetIconInfo 返回的位图,没有替换系统主题。通过黑白背景双次绘制重建alpha,检测到依赖背景反色的像素就拒绝;这四个样本未检测到此类像素,不代表全部自定义光标都支持。
管理工作站通过已有的认证PVE guest-agent通道读取导出文件,再经SSH传给盒子。没有新增网络监听端口,盒子没有直接使用PVE凭据。盒子辅助程序在现有Moonlight的X11窗口上创建本地指针,形状由测试脚本按已知测试区域顺序切换。**这是脚本控制的形状回放;没有将GetCursorInfo状态自动、实时同步到客户端。** Windows另存状态变化记录,供交叉核对。
测试临时使用Sunshine的Ctrl+Alt+Shift+N隐藏视频光标,最后成对恢复。它只是原型手段,没有会话确认/租约,不能作为正式交接协议。正常Moonlight二进制未重编或替换;本轮验证的是底层X11本地指针可用性。正式功能应进入Moonlight的SDL主线程,并适配后续Weston/Wayland,不能把这份X11辅助程序当最终架构。
## 实测结果
| 验证项 | 结果与边界 |
| --- | --- |
| 四种形状及热点 | XFixes读取本地指针,尺寸/热点均与Windows导出一致;忙碌只验证一帧,未实现动画 |
| 光标显隐 | 本地隐藏状态为全透明1×1;Windows记录也捕获到隐藏flags=0 |
| 移动独立于视频 | 仅将当前Moonlight进程短暂停住,小于0.5秒,并保证SIGCONT恢复;本地指针仍从(320,500)移动到(500,650),图像保持一致。这证明依赖关系解除,没有测得物理输入到屏幕毫秒数 |
| 单光标受控稳态 | 原始XWD截图在禁用后不再包含远程指针,XFixes另行确认本地指针存在。XWD不包含本地硬件指针,不能将原始截图无指针误报为本地显示失败;未用合成图冒充屏幕截图 |
| 点击正确性 | 最后完整一轮32次跨四区点击,Windows记录32/32区域及形状正确;绝对坐标归一化差值最大1像素,不宣称零偏差 |
| 辅助状态超时 | 0.8秒测试租约过期,辅助程序退出并通过SDL恢复其拥有的隐藏指针;测试控制器随后恢复远程视频光标。没有证明真实控制断网时服务器能自动回退 |
| 输入数据边界 | 10项测试通过,覆盖尺寸、热点、像素长度/范围、重复形状、XOR拒绝、格式、未知形状、过期/异常租约及文件大小 |
最后完整轮次为 `cursor-poc-evidence-v3`。最初两轮已验证形状、移动和点击,但辅助程序退出后当前XFixes图像暂不可用,不能算完整通过;修正后才通过完整流程。没有把前两轮的失败隐藏成成功。
## 暴露的两个实际问题
1. **静止画面的旧光标会留在旧视频帧里。** 第一轮切换快捷键后立即截图,原位置的远程箭头仍在;之后画面更新才消失。最后一轮加入测试窗口时钟更新并等待新帧,禁用后的光标区域变为空背景,恢复后的区域重新出现Windows忙碌光标。正式实现必须用双方确认的视频帧边界切换,不能只延时几百毫秒后直接显示本地箭头。
2. **X11指针资源有连接所有权。** 辅助程序在自己连接上复制一个隐藏指针,再关闭连接,并不足以可靠恢复SDL原先的资源。原型现在在XFixes临时隐藏保护下,使用Moonlight本地光标快捷键成对切换,让SDL重新设置它自己拥有的隐藏指针,再释放辅助资源。此清理依赖同一前台绝对鼠标会话,不能代替正式客户端内部的资源生命周期管理。代码失焦时明确报错,不声称任意退出路径都能可靠恢复。
## 下一阶段执行顺序
1. 固定现场Sunshine版本对应提交,在独立目录准备Windows可复现构建;当前未准备好该服务端C++构建环境。先验证未经修改的构建,再备份/部署测试实例,避免直接替换正常服务。
2. 在现有已认证、加密的控制通道添加能力协商、形状/热点、显隐、状态序号与显示配置代数。Moonlight将有界状态投递SDL主线程,缓存形状,本地移动直接跟随物理输入;旧服务端保持远程模式。
3. Sunshine提供有明确目标状态、帧边界确认和会话租约的光标交接,代替全局toggle;未捕获到可分离光标或形状不支持时回退。锁屏/UAC、远程主动warp、动画、缩放、多会话也须覆盖。
4. 验收断网/重连/失焦、文字选择、拖窗、右键/双击及100%/125%/150%缩放,再用高速摄像分别测指针移动、点击反馈、窗口内容的P50/P95。通过后再开放可关闭的试用开关。
独立光标可以绕开捕获、编码、网络、解码对“指针位置显示”的等待;窗口本身和点击后的页面仍需视频返回。它不会直接解决当前盒子2K60只实渲染约46FPS的问题,视频呈现优化仍按此前对照结论推进。
## 文件与复核
- `tools/cursor-poc-host.ps1`、`tools/run-cursor-poc-host.py`:临时Windows交互任务的start/status/export/stop。不自动触发、不修改Sunshine。
- `tools/cursor-poc-x11.py`:有界资产/状态解析、静态alpha形状、本地租约、SDL所有权归还;必须显式选择同一个前台Moonlight绝对鼠标窗口。仅用于受控实验。
- `tools/verify-cursor-poc-box.py`:受控演示、32点击、短暂停客户端及恢复;**仅可在上述Windows测试窗口位于前台时运行,不能向用户普通桌面盲目注入点击。** 输出目录拒绝覆盖,复跑须使用新目录名。
- `tools/test-cursor-poc.py`:Linux边界测试,不更改指针。
- `docs/evidence/cursor-poc-20261103/`:Windows资产和状态/点击记录、XFixes形状、原始截图转换、首轮失败证据、最终成功结果、超时日志、GPU/显示/本地指针收尾查询。压缩包保留原始XWD。
实现依据:[Microsoft GetCursorInfo](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcursorinfo)、[GetIconInfo](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-geticoninfo)、[Desktop Duplication光标元数据](https://learn.microsoft.com/en-us/windows/win32/direct3ddxgi/desktop-dup-api)。正式协议及验收要求继续见 [双方二次开发设计](independent-cursor-design-20261103.md)。