7.8 KiB
独立光标原型可行性实测(2026-11-03)
2026-11-05更新:Linux两台主机已接入不同于本原型的认证SSH原生光标方案,见实施记录。本页保留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图像暂不可用,不能算完整通过;修正后才通过完整流程。没有把前两轮的失败隐藏成成功。
暴露的两个实际问题
- 静止画面的旧光标会留在旧视频帧里。 第一轮切换快捷键后立即截图,原位置的远程箭头仍在;之后画面更新才消失。最后一轮加入测试窗口时钟更新并等待新帧,禁用后的光标区域变为空背景,恢复后的区域重新出现Windows忙碌光标。正式实现必须用双方确认的视频帧边界切换,不能只延时几百毫秒后直接显示本地箭头。
- X11指针资源有连接所有权。 辅助程序在自己连接上复制一个隐藏指针,再关闭连接,并不足以可靠恢复SDL原先的资源。原型现在在XFixes临时隐藏保护下,使用Moonlight本地光标快捷键成对切换,让SDL重新设置它自己拥有的隐藏指针,再释放辅助资源。此清理依赖同一前台绝对鼠标会话,不能代替正式客户端内部的资源生命周期管理。代码失焦时明确报错,不声称任意退出路径都能可靠恢复。
下一阶段执行顺序
- 固定现场Sunshine版本对应提交,在独立目录准备Windows可复现构建;当前未准备好该服务端C++构建环境。先验证未经修改的构建,再备份/部署测试实例,避免直接替换正常服务。
- 在现有已认证、加密的控制通道添加能力协商、形状/热点、显隐、状态序号与显示配置代数。Moonlight将有界状态投递SDL主线程,缓存形状,本地移动直接跟随物理输入;旧服务端保持远程模式。
- Sunshine提供有明确目标状态、帧边界确认和会话租约的光标交接,代替全局toggle;未捕获到可分离光标或形状不支持时回退。锁屏/UAC、远程主动warp、动画、缩放、多会话也须覆盖。
- 验收断网/重连/失焦、文字选择、拖窗、右键/双击及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、GetIconInfo、Desktop Duplication光标元数据。正式协议及验收要求继续见 双方二次开发设计。