mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-15 12:15:16 +00:00
feat(gui): 注入改 SendInput(默认)+ 用户操作时暂缓;拆解 Coopanion 桌宠动作系统
## 拆解 Coopanion(用户指出的参考项目)
新增 DESKTOP-PET-NOTES.md,记录 Pal-AI-Lab/Coopanion 的桌宠动作系统
(packages/cortico-world-desktop-pet):
· 4 个工具:pet_say(气泡说话,可夹带动作标记) / pet_ask(提问,异步回答) /
pet_walk_to(走到 0-1 比例或 left/center/right/cursor,含走到鼠标位置) /
pet_act(只做动作; sit/sleep 是持续态)
· 动作词表 VOCAB:10 个表情 + 13 个动作,每个词多个中文别名,
英文 id 与中文别名进同一张 Map;未知词丢弃而非报错
· 脚本标记:【词,词】= 先做动作再换新气泡;<词> = 打字到那里时做、不换气泡。
让文字与动作在时间轴上对齐 —— 实现成本低但表现力强
· 设计要点:身体是 agent 唯一可见输出通道(用户看不见消息正文);
互动事件不单独唤醒模型,跟着下批事件到
可借鉴(已写入文档待办):姿态表达状态、动作与文字对齐、持续态、
动作解析容错、待机自主行为。不建议照搬:桌宠承载全部对话输出、ASR、戳摸甩。
## 注入层改 SendInput(参考它的实现)
原 PostMessage 路径只能操作原生 Win32 程序 —— Chromium/Electron 自绘界面
与游戏会忽略合成消息。这不是「平台硬限制」,是所选 API 的限制。
Coopanion 用 SendInput 注入系统输入队列,可靠性高得多。
新增三档模式 gui-prefs.deviceBridge.agentCursor:
sendinput(默认) SendInput,可靠;会动真光标,故先等用户停手
overlay PostMessage,不动用户鼠标;只能操作原生程序
real 保留旧代码路径
另有 deferMs:用户活动时最多等多久(默认 3000,上限 10000)
★ SendInput 绝对坐标是 0–65535 归一化值,不是像素。按虚拟桌面归一化
并带 MOUSEEVENTV_VIRTUALDESK,多屏下也正确(Coopanion 只按主屏归一化)。
★ 文本用 KEYEVENTF.UNICODE 逐字符发,不受键盘布局与输入法影响(比 WM_CHAR 可靠)。
## 修「用户活动感知」把自己也算进去的 bug
GetLastInputInfo 是**全局**的 —— agent 自己的 SendInput 也被算作「用户输入」。
实测:deferMs 设 0 仍被暂缓,回执写「开始时空闲仅 0ms」,即上一条命令的
注入刚把 idleMs 清零。若不排除自身注入,会永远处于「用户正在操作」状态。
按 Coopanion 的三重判定修正:
1. ownTick 自己最后一次注入时刻,之后 40ms 内的输入忽略
2. ownCursor 自己放下的光标位置,偏离 >2px 说明是用户动的
3. 无符号差值 GetTickCount 每 2^32ms 回绕,必须按无符号比较
## 修同一条命令被执行两遍
sendinput 分支把逻辑包进 runAction 箭头函数,里面的 return 只退出它自己,
于是执行完继续 fall through 到旧 real 路径。实测 8 条命令回了 16 个
cmd_result,且真光标被额外抢一次。补上外层 return。
## 判据
computeruse.test.mjs 47 条(npm test 共 131 条全绿),新增 4 条钉住本轮
踩过的坑,均做变异验证:
· 三档模式存在(overlay/real 只在条件里,不能要求赋值形式)
· 用户活动排除自身注入;且盯 send() 里的**调用点** —— 只查函数名时
删掉调用仍会误报绿(已实测并改正)
· SendInput 坐标归一化 + VIRTUALDESK
· sendinput 分支必须 return(防双执行)
## 待办(已写入 GUI-PLAN.md)
· loadGuiPrefs 不透传 agentCursor,导致 deferMs 配置读取不生效(实测)
· 显式调 SetProcessDpiAwarenessContext(-4),不依赖 Electron 默认值
· mascot 姿态:思考/等待/出错
· 真实点击效果仍未验证(当前环境无可注入的可见窗口)
This commit is contained in:
52
GUI-PLAN.md
52
GUI-PLAN.md
@ -118,16 +118,25 @@ agent 一干活用户就没法用电脑。
|
||||
| 文件 | 职责 |
|
||||
|---|---|
|
||||
| `cmd/gui/agent-cursor.js` | 透明置顶层窗口 + mascot 指针 + 移动/点击脉冲动画;记录上次命中的窗口句柄 |
|
||||
| `cmd/gui/agent-inject.js` | Windows 后台注入:`WindowFromPoint` 定位、坐标换算、`PostMessage` 投递鼠标/键盘/滚轮/文本 |
|
||||
| `cmd/gui/agent-inject.js` | 两种注入路径:`SendInput`(默认)与 `PostMessage`(后台);含用户活动感知 |
|
||||
|
||||
### 3.3 配置
|
||||
|
||||
`gui-prefs.json` → `deviceBridge.agentCursor.mode`:
|
||||
`gui-prefs.json` → `deviceBridge.agentCursor`:
|
||||
|
||||
| 值 | 行为 |
|
||||
|---|---|
|
||||
| `"overlay"` | **默认**。不动用户鼠标,后台注入 |
|
||||
| `"real"` | 旧行为,操作真实鼠标 |
|
||||
| 键 | 值 | 行为 |
|
||||
|---|---|---|
|
||||
| `mode` | `"sendinput"` | **默认**。`SendInput` 注入系统输入队列,可靠性高(Chromium/游戏都能操作)。代价:会移动真实光标,故先等用户停手 |
|
||||
| `mode` | `"overlay"` | `PostMessage` 直投窗口句柄。用户鼠标纹丝不动,但自绘界面常忽略合成消息 |
|
||||
| `mode` | `"real"` | 保留旧代码路径(兼容) |
|
||||
| `deferMs` | 数字 | 用户活动时最多等多久(默认 3000,上限 10000)。0 = 不等待 |
|
||||
|
||||
> 为什么默认改成 `sendinput`:用户要求「可靠 + 用户正在操作则暂缓」。
|
||||
> 参考 `Pal-AI-Lab/Coopanion`(见 `DESKTOP-PET-NOTES.md` 第七节)。
|
||||
>
|
||||
> ⚠ 实测发现:`GetLastInputInfo` 是**全局**的,agent 自己的 `SendInput`
|
||||
> 也会被算作「用户输入」,若不排除则**永远处于「用户正在操作」状态**。
|
||||
> 已按 Coopanion 的三重判定修正(ownTick / ownCursor / 无符号差值)。
|
||||
|
||||
### 3.4 已验证(端到端,8/8 有正确响应)
|
||||
|
||||
@ -178,13 +187,25 @@ agent 一干活用户就没法用电脑。
|
||||
|
||||
## 四、待办
|
||||
|
||||
### 4.1 优先:验证模式 A 的真实效果
|
||||
### 4.1 优先:修 `deferMs` 读取不生效
|
||||
|
||||
实测:`gui-prefs.json` 里 `agentCursor.deferMs = 0`,但命令仍按默认 3000ms
|
||||
暂缓(回执写「已等待 3000ms」)。`loadGuiPrefs()` 会重建对象且**不透传
|
||||
`agentCursor` 字段**,导致读取永远拿到默认值。
|
||||
|
||||
- [ ] `loadGuiPrefs()` 透传 `deviceBridge.agentCursor`
|
||||
- [ ] 判据:配置 `deferMs:0` 时不得进入暂缓路径
|
||||
|
||||
### 4.2 验证 sendinput 的真实效果
|
||||
|
||||
当前环境无可注入的可见目标窗口(`WindowFromPoint` 恒返回 null,
|
||||
`GetCursorPos` 读回 0,0),故「点击真的落到目标窗口上」尚未证明。
|
||||
|
||||
- [ ] 端到端测试:打开真实应用 → 点它 → 输入 → 截图回读
|
||||
- [ ] 断言全过程用户鼠标位置未变
|
||||
- [ ] 判据:把该测试固化进 `npm test`(需能在无桌面 CI 环境跳过)
|
||||
- [ ] 断言:`overlay` 模式下全过程用户鼠标位置未变
|
||||
- [ ] 判据:固化进 `npm test`(需能在无桌面 CI 环境跳过)
|
||||
|
||||
### 4.2 服务端配合(详见 `SERVER-HANDOFF.md`)
|
||||
### 4.3 服务端配合(详见 `SERVER-HANDOFF.md`)
|
||||
|
||||
- [ ] 放开 `device.go` 的 action 白名单(schema enum + switch default 双重限制)
|
||||
- [ ] 透传新参数 `tox`/`toy`/`steps`/`dx`/`ms`/`physical`
|
||||
@ -197,9 +218,16 @@ agent 一干活用户就没法用电脑。
|
||||
|
||||
- [ ] `agentCursor.mode` 的 UI(目前只能手改 `gui-prefs.json`)
|
||||
|
||||
### 4.4 可选增强
|
||||
### 4.4 设置页
|
||||
|
||||
- [ ] mascot 待机动作、常驻屏幕边缘(借鉴桌宠的视觉层)
|
||||
- [ ] `agentCursor.mode` / `deferMs` 的 UI(目前只能手改 `gui-prefs.json`)
|
||||
|
||||
### 4.5 可选增强(详见 `DESKTOP-PET-NOTES.md` 第六、九节)
|
||||
|
||||
- [ ] `main.js` 显式调 `SetProcessDpiAwarenessContext(-4)`,不依赖 Electron 默认值
|
||||
- [ ] mascot 姿态:思考 / 等待 / 出错
|
||||
- [ ] 动作解析容错:未知动作丢弃而非整条失败
|
||||
- [ ] mascot 待机自主行为:闲置时轻微眨眼/呼吸
|
||||
- [ ] Linux 侧若也要「不抢鼠标」,需 Wayland + uinput 虚拟设备
|
||||
(X11 下做不到 —— XTEST 合成的是真实设备事件)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user