平台工程

录屏假光标被打回:画出来的不算操作,与”输入送达”的四处假信号

一句话律:演示鼠标操作,观众要看的是”手怎么动”,不是”屏幕上有个圆点在动”——浏览器里画的光标无论放多大都不是系统指针;顺着这条往下,录屏自动化里每一个”看着对”的信号都要问一句”它测的是不是我以为的那件事”。

现象

教程录屏交付 11 条,被一句话打回:“这不是鼠标操作”

那批素材是 Playwright 无头浏览器录的,页面里注入一个 CSS div 当光标。收到的第一版反馈是”鼠标指针太小、看不清落点”,我据此把假光标从 18px 调到 30px、描边 2.5→3.5px、点击涟漪终点 52→88px——方向从一开始就是错的。假光标再大也只是网页里的一个圆点,真实系统指针全程没动。

根因与正解

改用 humancast 驱动真实 Windows 指针(最小急动度轨迹 + 贝塞尔弧线 + 落点前微抖 + 终点过冲回修),配成混合架构

坐标不靠推 DPI,走闭环标定:真实鼠标先走两个已知屏幕点,从页面 mousemove 读回 clientX/clientY,反解仿射变换。实测 screen = page × 1.0 + (2560, 87)。这一步绕开了混屏 DPI 的全部推理——本机主屏 2560×1440 物理 = 2048×1152 DIP(125% 缩放),Chrome 报 availLeft: 2048 而 Win32 报 2560,硬算必错。

四处”看着对”的假信号(终端录屏,同一天连废 3 条)

换到 PowerShell 终端录屏后,前三条全废。没有一条是被录软件的问题,全是判据测错了东西

  1. “有子进程”不等于”命令在跑” ⚠️首次 我用”PowerShell 有没有活着的子进程”判断命令结束,但空闲的 PowerShell 本身就挂着一个 conhost.exe 子进程,判据恒为真:git clone 一路等到 300s 超时才往下走,后面全部错位。要按 exe 名过滤。 底下还压着一层:CreateToolhelp32Snapshot 没设 restype = c_void_p,64 位句柄被 ctypes 默认按 c_int 截断。修完实测:空闲 → False,命令在跑 → ['node.exe'],跑完 → False。

  2. “开打前验过前台”不等于”全程在前台” ⚠️首次 后台进程调 SetForegroundWindow 会被 Windows 静默拒绝(不报错,就是不生效)。抽帧确认第一条废片里 pnpm run buildpnpm dsh web 根本没敲进终端——画面停在上一条命令的提示符上,而脚本以为自己敲完了。 humancast 自带保险丝 window.require_foreground(hwnd)(“不是目标窗口就一个键都不发”),但只在开打前验一次不够:一条长路径要敲三四秒,中途焦点被抢走,后半截就飞出去了。实测把后半截 {项目工作区}\lab\install-demo" 敲进了另一个窗口,终端里只剩半条 cd "E:未闭合的引号让 PowerShell 进了续行模式 >>,后续两条命令全被吞进续行,最后 pnpm install 在盘根目录跑,报 ERR_PNPM_NO_PKG_MANIFEST。 正解:AttachThreadInput 强抢前台 + 分段打字,每 6 个字符重验一次,抢不到就中止。

  3. “屏幕没变化”不等于”命令没执行” ⚠️首次 用屏幕变化确认回车生效,测出来永远是”没变化”。量了才知道:一条命令回车后整屏差异只有 0.0014,光标闪烁的本底噪声是 0.00012,而 humancast wait_change 默认 tol=0.002 正好卡在信号上方——默认值不是保守,是完全失灵。取 0.0005(噪声 4 倍、信号 1/3)才分得开。 另一半是取样时序:基线必须在按回车之前取。秒回命令(git --version)在 press 返回时输出已经画完了,回车后再取基线永远比不出差异,脚本会白敲第二次回车、多出一个空提示符。

  4. “刚拿到焦点”不等于”能开始打字” ⚠️首次 焦点切换瞬间打字会掉前几个字符,实测 git --version 变成 t --version。要是落在 git clone 上,整条素材废在第一行。 正解:命令前补两个空格当牺牲字符(PowerShell 不在乎前导空格),掉的是空格不是 gitg。 我一度改用 ESC 当”热身键”——这是个错误做法:ESC 会把”上一条没提交成功的命令”整行清掉,等于毁尸灭迹,现场连证据都不剩,反而更难查。修一个症状引入一个更坏的 bug。

附:同批次其它坑

第五处假信号:我自己的摘要 ⭐二次验证

收口写回执时,我把交接单里的「C 类 9 条」写成了「转 Mac 端另录,本机不再处理」—— 而原文写的是「Claude Code 本机处理(9 条,原误标 Mac)……本机 Windows 即可录,无需 Mac 设备」, 意思完全相反。等于我把 9 条本该我做的活,在回执里写成了别人的。

错因:写回执时我用的是自己对交接单的摘要记忆,没回去读原文那一节。而这份交接单的 C 类恰好前后改过三版(Mac 另录 → 执行人自己有 Mac → 根本不需要 Mac),我的记忆停在中间那版。

这跟协作方同日总结的「转述链衰减律」是同一条,只不过那边衰减的是人与人之间的转述, 这边衰减的是我自己对原始材料的压缩——而后者更隐蔽,因为它不经过任何人, 不会有第二个人在场提出异议。长会话被压缩、跨会话交接、隔天续做,都会制造这种”自摘要”。

判据很简单:凡是要写进交付物的”谁做什么”,落笔前回原文那一节重读一遍, 不用回忆、不用信摘要——重读一节的成本是十几秒,写反的成本是 9 条素材没人做。

教训

关联文档

类型/平台工程