dsh-desktop-hand
IdentifiedWindows-only desktop control for DSH with six tools that list windows, capture occluded windows, focus windows, click by coordinate, inject Unicode keyboard input, and diagnose the desktop bridge.
dsh-desktop-hand
Windows desktop control for a DSH agent, as six agent-callable tools.
A plugin for DeepSeek Harness. Windows only.
特性
抓被遮挡的窗口。 这是本插件最重要的一条。desktop_capture 指定窗口时走
PrintWindow,抓到的是窗口自己的内容——即使它被别的窗口完全盖住。
抓全屏走 CopyFromScreen,只能抓到遮挡者。
同一时刻、同一个目标窗口,被一个最大化窗口完全盖住,两种抓法对比
(lib/occlusion-test.ps1 自动构造这个场景并给出客观判据):
| 抓法 | 结果 |
|---|---|
| 全屏 | 屏幕上实际可见的整屏,即只有遮挡者,目标窗口完全不可见 |
| 指定窗口 | 目标窗口自己的尺寸与内容,标题栏和正文清晰可见,与遮挡前的抓取一致 |
关键判据不是尺寸大小(窗口本来就可以比屏幕大),而是:
指定窗口抓到的图既等于目标窗口自身的 rect,又不等于全屏图——这正是
PrintWindow 与 CopyFromScreen 的分水岭。
截图直接返回给模型。 desktop_capture 的结果里带图片本体,
不需要再调一次 read_image。
输入绕过输入法。 desktop_type 走 SendInput + KEYEVENTF_UNICODE 直投字符。
中文、%.15f 这类格式符都能原样送达——用 VkKeyScan 走的键盘布局通路会被中文
输入法改写。
坐标是物理像素。 引擎每层都声明 DPI 感知,截图里的像素坐标可直接用于点击。
若截图宽与物理屏宽不一致,结果里会给出 coordScale 供换算。
点击会回报落点。 desktop_click 校验光标最终位置并与目标比对,
落点不对会明确告诉你,而不是静默失败。
六个工具:
| 工具 | 用途 |
|---|---|
desktop_diagnose | 体检:此刻合成输入可不可信(DPI / 屏幕 / 前台窗口 / 输入法 / 远程软件 / 光标落点稳定性) |
desktop_list_windows | 列窗口:句柄、PID、进程、标题、位置尺寸、是否 UWP、是否最小化 |
desktop_capture | 截屏:全屏 / 指定窗口(标题或句柄)/ 区域裁切,图片直接返回 |
desktop_focus | 把窗口拉到前台,并报告是否真的成功 |
desktop_click | 点击 / 双击 / 右键 / 拖动,带落点校验 |
desktop_type | 输入文本(Unicode 直投)或发送白名单按键 |
已知边界(不是 bug):
- UWP 应用抓不到内容(设置、计算器等)。
PrintWindow对走 DirectComposition 渲染的 UWP 是硬盲区,PowerShell 侧无法绕过。工具会返回uwpWarning—— 此时不要根据那张图判断界面状态。 - 最小化的窗口尺寸退化,抓到的内容无意义(返回
minimized: true)。 - 远程会话正在操作鼠标时,合成点击不可靠:坐标会被实时覆盖,调参无用。
用
desktop_diagnose确认,等远端空闲即可。不要杀远程控制进程,那会断连。 - 黑像素比例仅供参考,不是成功判据(实测 UWP 宿主黑像素仅 2.9%,图像却是空白框架)。
安装
dsh plugin --profile web add github:AsterionZephyr/dsh-desktop-hand
或手工安装——把仓库 clone 到任意位置,然后在 profile 的 package.json
(%APPDATA%\dsh-desktop\harness\profiles\web\package.json)里加上三处:
{
"dependencies": {
"dsh-desktop-hand": "link:/absolute/path/to/dsh-desktop-hand"
},
"dsh": {
"profile": {
"bundles": [ /* ...原有条目..., */ "dsh-desktop-hand" ]
}
},
"pnpm": {
"overrides": {
"dsh-desktop-hand": "link:/absolute/path/to/dsh-desktop-hand"
}
}
}
然后在 profile 目录里 pnpm install,重启 DSH(bundle 列表在启动时读取)。
环境要求: Windows 10/11、PowerShell 5.1(系统自带)、Node ^22.19.0 || >=24.0.0。
三处缺一不可:只有 overrides 而没有 dependencies + bundles 是无效状态,不会加载。
⚠️ bundle 通道和 profile 的
cordis.patch.yml手工挂载行,只能用一个。 两者都写会双重挂载,工具注册时报 "already registered",可能导致 DSH 起不来。
⚠️ DSH 升级会重写 profile,把本地插件条目删掉。 升级后请复查上面三处是否齐全。 细节与排查见
docs/COMPATIBILITY.md。
配置项(在 profile 里作为插件的 config 传入,一般不用改):
| 键 | 默认 | 说明 |
|---|---|---|
enginePath | 包内 lib/desktop-hand.ps1 | 引擎脚本路径 |
timeoutMs | 60000 | 单次调用超时(首次要编译 Add-Type,约 1.2 s) |
outputDir | 系统临时目录 | 截图默认落盘目录 |
使用
agent 装上后会自动获得这六个工具。典型流程:
desktop_list_windows → 找到目标,拿句柄
desktop_capture(handle=...) → 看图,量出要点哪里
desktop_focus(handle=...) → 或 desktop_click 点窗口体拿焦点
desktop_type(text="...") → 输入
desktop_capture(handle=...) → 再看图确认结果
四条使用要点
1. 要看窗口内容就用 window/handle,不要抓全屏——除非你确实要看屏幕上真实
可见的东西。指定窗口走 PrintWindow,被遮挡也能抓到目标自己的内容。
2. 看图和点图用同一张图。 desktop_capture 结果的 width 若与物理屏宽不一致,
把该 width 作为 shotWidth 传给 desktop_click。一致时图中像素坐标 1:1 可用。
3. 不要用黑像素比例判断抓取成功,必须看图。 UWP 应用是盲区,工具会给
uwpWarning。
4. 点不准或输入丢失时,先跑 desktop_diagnose,不要调坐标。 它会连采两次
光标落点:稳定=可用;持续漂移=有别的输入源在覆盖(通常是远程会话)。这是环境
问题,改代码没用。
命令行直接调引擎
引擎也可脱离 DSH 单独使用,输出单行 JSON:
$e = ".\lib\desktop-hand.ps1"
& $e -Action info # 体检:DPI/屏幕/前台/输入法/远程软件
& $e -Action list-windows # 列窗口,拿句柄
& $e -Action capture -Window "Notepad" -OutPath a.png # 后台抓窗口(被遮挡也行)
& $e -Action capture -Handle 1234567 -OutPath b.png # 按句柄抓
& $e -Action capture -FullScreen -Region "0,0,800,600" # 全屏后裁切
& $e -Action click -X 640 -Y 360 -ShotWidth 1280 # 点击(坐标取自截图)
& $e -Action click -X 100 -Y 100 -ToX 400 -ToY 400 # 拖动(给 ToX/ToY)
& $e -Action type -Text "disp(1+1)" -Enter # 输入(绕过输入法)
& $e -Action key -Key ctrl+s # 发按键
& $e -Action focus -Window "MATLAB" # 拉到前台
& $e -Action probe -X 400 -Y 400 # 检测有无输入源在覆盖光标
坐标系是截图里的像素。-ShotWidth 传你所用截图的真实宽度;截图与物理屏 1:1 时
可省略。capture 的结果里会给出 coordScale 与 originX/originY 供换算。
可用动作(9 个):info list-windows capture click move probe type key focus。
拖动是 click 的参数(同时给 -ToX/-ToY 即为拖动),不是独立动作。
自检
.\lib\link-deps.ps1 # 为脱离 DSH 的自检链接 peer 依赖
.\lib\selftest.ps1 # 37 项 — 引擎
node .\lib\selftest.mjs # 111 项 — 工具层
node .\lib\selftest-harness.mjs # 18 项 — harness 子进程契约
node .\lib\verify-serialization-contract.mjs # 25 项 — 宿主序列化契约
.\lib\occlusion-test.ps1 # 8 项 — 遮挡抓取(需肉眼看图)
.\lib\link-deps.ps1 -Clean
199 项,本地与 GitHub windows-latest 均全绿。依赖真实桌面的检查(窗口枚举、
键鼠闭环、遮挡抓取)在环境不满足时跳过而非失败——环境无法构造场景不等于代码
有缺陷。fail 是唯一代表代码坏了的信号。
verify-serialization-contract.mjs 与其它四套不同:它读的是宿主的源码,
用来钉住我们依赖的上游行为(snapshotJsonValue 接受/拒绝哪些值、
applyFinalContent 是否 await 钩子、undefined 属性在 in 与 JSON.stringify
眼里不一致)。它在找不到桌面版 DSH 时跳过,因为 npm 上的 dsh-tools
与桌面安装的版本不同;找不到时打印一行 SKIP 并 exit 0。
CI 覆盖不到"插件能否在运行中的 DSH 里加载",那需要装 DSH 并重启;
docs/COMPATIBILITY.md 第 5 节有手工检查清单。
架构
两层,中间用单行 JSON 通信。
┌─ DSH agent ────────────────────────────────────────────┐
│ desktop_diagnose / list_windows / capture / focus / │
│ click / type ← 6 个 defineTool │
└───────────────────────┬────────────────────────────────┘
│ ctx.subprocess.spawn
│ argv + JSON on stdout
┌───────────────────────▼────────────────────────────────┐
│ lib/desktop-hand.ps1 PowerShell 引擎 │
│ P/Invoke → user32 / gdi32 / shcore / dwmapi / imm32 │
└────────────────────────────────────────────────────────┘
lib/index.js — 工具层(Node, ESM)
- 用
defineTool注册 6 个工具。参数是 dsh-tools 的扁平 JSON-Schema 属性表 (不是 schemastery,后者只用于插件自己的Config)。 - 经
ctx.subprocess.spawn起引擎。不用裸node:child_process:DSH 沙箱会 拒绝 Node 以管道 stdio 起子进程(裸spawn报EPERM)。裸spawn仅作脱离 DSH 时的退路。 - 截图通过
finalizeContent钩子把 PNG 交给附件服务,追加成image内容块。 不能塞进返回值——output.schema是additionalProperties: false,多余键会校验失败。 - 引擎返回
ok:false时抛带提示的异常,让模型能自我纠正(比如"标题匹配到多个窗口, 请用 handle")。
lib/desktop-hand.ps1 — 引擎(PowerShell)
单个脚本,-Action 分发,恒向 stdout 输出单行 JSON。设计上有五条硬约束,
每条都是实测踩出来的,改动前请先读文件头的注释:
1. 抓窗口用 PrintWindow + PW_RENDERFULLCONTENT(2)。
flag 必须是 2:flag=0 对 UWP 是 100% 黑,flag=2 降到 71.7%,即 0 更糟。
2. 文本注入用 SendInput + KEYEVENTF_UNICODE。
不能用 VkKeyScan + keybd_event——那条路经过键盘布局/输入法层,会被改写
(实测想要 third batch,目标程序收到的是「第三批」)。
3. 坐标按物理像素,且 DPI 感知要显式声明。
2560×1440 + 150% 缩放时,不声明 DPI 感知会让 SetCursorPos(42,1046) 落到物理
(56,1395),而 GetCursorPos 又除回去报 (1280,720)——表现是"点的位置和说的不一样"。
4. 输出必须是显式 UTF-8。
PowerShell 5.1 在 stdout 被重定向时按控制台 ANSI 代码页(本机 GBK/936)编码,
而 Node 按 UTF-8 解码,于是所有非 ASCII 错误信息变乱码。引擎第一件事就是设
[Console]::OutputEncoding = UTF8。删掉这行不会报错,只会静默毁掉所有中文提示。
5. apply() 绝不能抛异常。
插件在 profile 里是 required: true,apply() 抛错会让整个 DSH 启动失败并进
安全模式,进而重写 profile 把插件删掉。所以系统提示段落这类锦上添花的东西整段包在
try/catch 里,失败只 warning。详见 docs/COMPATIBILITY.md。
文件
dsh-desktop-hand/
├── package.json dsh.bundle.patch 是能被加载的关键字段
├── cordis.patch.yml bundle 挂载声明
├── README.md
├── docs/
│ ├── COMPATIBILITY.md DSH 版本兼容、启动失败事故、三个序列化陷阱
│ ├── INCIDENT-2026-10-03-... 图片块序列化故障的原始排查报告(中文)
│ ├── evidence/ 故障报告引用的实拍图
│ └── ENGINEERING-NOTES.zh-CN.md 详细工程笔记(中文,含每个 bug 的定位过程)
├── skills/desktop-hand/ 给 agent 的用法 skill
└── lib/
├── index.js 6 个 defineTool + 图片返回
├── desktop-hand.ps1 PowerShell 引擎
├── selftest.ps1 引擎自检
├── selftest.mjs 工具层自检
├── selftest-harness.mjs 子进程 seam 契约自检
├── verify-serialization-contract.mjs 宿主序列化契约守卫
├── occlusion-test.ps1 遮挡抓取验证
├── hold-windows.ps1 测试台:造一对"目标 + 完全遮挡"窗口
└── link-deps.ps1 为脱离 DSH 的自检建/清依赖链接
MIT licensed — see LICENSE.
Comments
Loading…
Similar plugins
Windows desktop control with window-bound screenshots and accessibility state, text readback, DSH approvals, and activity overlays.
★ 0
dsh plugin --profile web add @very12345/dsh-computer-use-windowsby Silentforfar
DSH bundle: Windows desktop control - window screenshots, UI Automation element trees, and real input actions.
★ 0
MIT
PowerShell
Oct 21, 2026
dsh plugin --profile web add @silentforfar/dsh-computer-useby gezi-wen
Windows desktop-control tools for DeepSeek Harness (DSH): screen layout, annotated screenshots, click / type / key / scroll, window management, and UI Automation structured queries. Zero dependencies, no resident service, no API key.
★ 1
Apache-2.0
JavaScript
Oct 13, 2026
dsh plugin --profile web add dsh-guikitby MuzeWinter
Windows desktop automation for DeepSeek Harness: 14 tools for real GUI input (click, type, keys, scroll, drag), occlusion-proof window screenshots and the accessibility tree.
★ 1
NOASSERTION
JavaScript
Sep 27, 2026
dsh plugin --profile web add dscomputer-controlby momasiku
Give DeepSeek Harness hands and eyes: screen_view hands the model a real PNG of your desktop, desktop_control drives the mouse, keyboard and windows, desktop_sequence runs a whole task in one call.
★ 17
↓ 165/wk
MIT
JavaScript
Oct 22, 2026
dsh plugin --profile web add dsh-pilotby gezi-wen
Windows desktop-control tools for DeepSeek Harness (DSH): screen layout, annotated screenshots, click / type / key / scroll, window management, and UI Automation structured queries. Zero dependencies,
★ 0
MIT
JavaScript
Sep 24, 2026
dsh plugin --profile web add sage-guikit