@geyj/auto-gui
v0.0.1
Published
Composable desktop automation SDK for Node.js and Electron.
Readme
@geyj/auto-gui
@geyj/auto-gui 是一个面向 Node.js / Electron 的桌面自动化 SDK,目标是用接近 Nut.js 的组合式 API 暴露窗口、鼠标、键盘、剪贴板、屏幕截图、图片查找、颜色查找、OCR 文本查找和 UI 元素查找能力。
当前包是 CommonJS 产物,TypeScript 示例默认按 module: "CommonJS" 编译运行。Node.js 版本要求为 >=22。
当前架构
flowchart TB
app["Node.js / Electron 应用"] --> pkg["@geyj/auto-gui 包入口<br/>根入口 + 子路径入口"]
pkg --> index["src/index.ts"]
subgraph ts["TypeScript API 层"]
types["types.ts<br/>Point / Size / Region / Button / Key"]
geometry["geometry.ts<br/>centerOf / straightTo / createBezierPath"]
mouse["mouse.ts"]
keyboard["keyboard.ts"]
clipboard["clipboard.ts"]
screen["screen.ts<br/>截图 / 保存 / 查找底座"]
windowApi["window.ts"]
element["element.ts + findElement.ts"]
text["text.ts + paddle-ocr.ts + findText.ts"]
image["findImage.ts"]
color["findColor.ts"]
utils["utils.ts"]
end
mouse --> native["src/native.ts<br/>加载 auto_gui_native.node"]
keyboard --> native
clipboard --> native
screen --> native
windowApi --> native
element --> windowApi
image --> screen
color --> screen
text --> screen
native --> addon["native/src/addon.cc<br/>Node-API / node-addon-api"]
addon --> platform["native/src/platform_*.cc<br/>Windows / macOS / Linux"]
text --> models["models/paddleocr<br/>PP-OCRv5 Mobile ONNX"]安装与构建
源码仓库首次初始化:
npm install
npm run prepare:ocr-models
npm run build:native
npm run build:inspector
npm run buildnpm run prepare:ocr-models 会下载 PaddleOCR PP-OCRv5 Mobile ONNX 模型。发布后的 npm 包会把 models/ 一起带上,普通使用者不需要重复执行。
发布到 npm 后,使用者走标准安装流程即可:
npm install @geyj/auto-gui当前版本还没有预编译 .node 二进制,npm 安装会依赖包内的 binding.gyp 触发本地 node-gyp rebuild。Windows 需要 Visual Studio C++ Build Tools 与 Python;macOS 需要 Xcode Command Line Tools;Linux 需要 X11/XTest 相关开发库。
导入方式
根入口导出全部公开 API:
import {
Button,
Key,
Point,
Region,
centerOf,
clipboard,
elements,
findColor,
findElement,
findImage,
findText,
getActiveWindow,
keyboard,
mouse,
screen,
sleep
} from "@geyj/auto-gui";也可以按模块导入,适合大型项目收敛依赖边界:
import { mouse } from "@geyj/auto-gui/mouse";
import { keyboard } from "@geyj/auto-gui/keyboard";
import { clipboard } from "@geyj/auto-gui/clipboard";
import { screen } from "@geyj/auto-gui/screen";
import { getActiveWindow } from "@geyj/auto-gui/window";
import { findText } from "@geyj/auto-gui/findText";
import { findImage } from "@geyj/auto-gui/findImage";
import { findColor } from "@geyj/auto-gui/findColor";
import { findElement } from "@geyj/auto-gui/findElement";
import { sleep } from "@geyj/auto-gui/utils";快速开始
import { Button, Key, Region, centerOf, findText, keyboard, mouse, screen, singleWord, windowWithTitle } from "@geyj/auto-gui";
const activeWindow = await screen.find(windowWithTitle(/记事本|Notepad/i));
console.log(activeWindow);
const saveButton = await findText(singleWord("保存"), {
searchRegion: new Region(0, 0, 1200, 800)
});
await mouse.move(centerOf(saveButton));
await mouse.click(Button.LEFT);
await keyboard.type("Hello from auto-gui");
await keyboard.press(Key.LeftControl, Key.S);当前模块与能力
| 模块 | 入口 | 主要能力 |
| --- | --- | --- |
| 基础类型 | 根入口 | Point、Size、Region、Button、Key、RGBA |
| 几何工具 | 根入口 | centerOf()、straightTo()、createBezierPath() |
| 鼠标 | @geyj/auto-gui/mouse | getPosition()、setPosition()、move()、click()、doubleClick()、rightClick()、pressButton()、releaseButton()、scrollUp()、scrollDown()、scrollLeft()、scrollRight()、drag() |
| 键盘 | @geyj/auto-gui/keyboard | type()、press()、pressKey()、releaseKey() |
| 剪贴板 | @geyj/auto-gui/clipboard | getContent()、setContent();文本跨平台,图片写入当前仅 Windows |
| 屏幕 | @geyj/auto-gui/screen | width()、height()、capture()、grab()、grabRegion()、captureRegion()、colorAt()、highlight()、find()、findAll()、waitFor()、read()、saveImage() |
| 窗口 | @geyj/auto-gui/window | getActiveWindow()、getWindows()、window.title、window.region、move()、resize()、focus()、minimize()、maximize()、restore()、getElements()、find()、findAll()、waitFor() |
| 图片查找 | @geyj/auto-gui/findImage | imageResource()、findImage()、findAllImages()、waitForImage() |
| 颜色查找 | @geyj/auto-gui/findColor | pixelWithColor()、findColor()、findAllColors()、waitForColor() |
| OCR 文本 | @geyj/auto-gui/findText | singleWord()、textLine()、findText()、findAllTexts()、waitForText()、readText()、providerRegistry、PaddleOcrTextFinder |
| UI 元素 | @geyj/auto-gui/findElement | elements.*()、windowElementDescribedBy()、findElement()、findAllElements()、waitForElement()、findMatchingWindowElements() |
| 工具函数 | @geyj/auto-gui/utils | sleep(seconds)、sleep(minSeconds, maxSeconds)、openElementInspector()、openColorPicker() |
鼠标
import { Button, mouse, straightTo } from "@geyj/auto-gui";
await mouse.move({ x: 400, y: 300 });
await mouse.move(straightTo({ x: 500, y: 320 }));
await mouse.click(Button.LEFT);
await mouse.doubleClick();
await mouse.rightClick();
await mouse.scrollDown(3);
await mouse.drag([{ x: 100, y: 100 }, { x: 300, y: 240 }]);mouse.move() 和 mouse.drag() 默认使用平滑贝塞尔轨迹。mouse.config.mouseSpeed = 0 时会直接瞬移到目标点。
键盘
import { Key, keyboard } from "@geyj/auto-gui";
await keyboard.type("第一行");
await keyboard.press(Key.Enter);
await keyboard.type("第二行");
await keyboard.press(Key.LeftControl, Key.A);
await keyboard.press(Key.LeftControl, Key.C);keyboard.type() 只负责文本输入。Windows 下单个可打印 Unicode 字符直接使用原生键盘事件,整段文本、换行和制表符临时借助剪贴板粘贴;keyboard.press() 用于单键和组合键。
剪贴板
import { clipboard, screen } from "@geyj/auto-gui";
const original = await clipboard.getContent();
await clipboard.setContent("plain text");
await clipboard.setContent({ taskId: 1001, enabled: true });
await clipboard.setContent(await screen.capture());
await clipboard.setContent(original);clipboard.setContent() 支持任意 JavaScript 值:字符串保持原样,对象和数组序列化为 JSON,其他值转成字符串。传入 Image 或兼容的 RGB/RGBA 原始像素结构时,Windows 会写入系统图片剪贴板。clipboard.getContent() 当前只读取文本。
开发辅助工具
import { openColorPicker, openElementInspector } from "@geyj/auto-gui";
const elementInspector = await openElementInspector({
delayMs: 1000,
pollIntervalMs: 120
});
// openColorPicker 当前是同一个桌面捕获器的兼容入口。
const sameInspector = await openColorPicker();
console.log(elementInspector.executablePath, elementInspector.pid, sameInspector.pid);openElementInspector():唤起合并后的 Windows 桌面捕获器auto-gui-inspector.exe。鼠标移动到目标元素后会出现蓝色选中框,悬停 1 秒后锁定元素详情。openColorPicker():兼容入口,当前同样唤起auto-gui-inspector.exe。捕获器面板会同时展示当前鼠标坐标和当前位置颜色rgba(...)。
捕获器会展示唯一标识、标题、类名、控件类型、窗口标题、鼠标坐标、颜色 RGBA/HEX、元素坐标等信息,每项都可以单独复制。鼠标移到捕获器窗口上时会暂停捕获,避免准备复制时信息被覆盖。
首次使用或源码开发时先生成 exe:
npm run build:inspector在测试项目中可以直接运行:
npm --prefix auto-gui-test run test:utils该命令会保持桌面捕获器运行。使用完关闭捕获器窗口,或在终端按 Ctrl+C 退出。需要让测试自动关闭时,可设置 $env:AUTO_GUI_TOOL_HOLD_SECONDS = "60"。
屏幕、图片和颜色
import { FileType, RGBA, Region, findColor, findImage, imageResource, pixelWithColor, saveImage, screen } from "@geyj/auto-gui";
const image = await screen.capture(new Region(0, 0, 400, 300));
await saveImage(image, "artifacts/top-left.png", FileType.PNG);
const template = await imageResource("button.png");
const buttonRegion = await findImage(template, { confidence: 0.99 });
const redPixel = await findColor(pixelWithColor(new RGBA(255, 0, 0, 255)), {
searchRegion: new Region(0, 0, 800, 600),
tolerance: 5
});
console.log(buttonRegion, redPixel);当前图片资源加载和保存只支持 PNG。模板 PNG 需要是 8 位、非交错格式。
窗口和 UI 元素
import { elements, getActiveWindow, getWindows, waitForElement } from "@geyj/auto-gui";
const activeWindow = await getActiveWindow();
console.log(await activeWindow.title, await activeWindow.region);
await activeWindow.focus();
await activeWindow.move({ x: 100, y: 100 });
await activeWindow.resize({ width: 900, height: 700 });
const windows = await getWindows();
console.log(windows.length);
const okButton = await waitForElement(elements.button({ title: "确定" }), 5000, 500, {
window: activeWindow
});
console.log(okButton);UI 元素读取当前使用 Windows UI Automation。elements 提供 button、menuItem、textField、checkBox、dialog、listItem、tab、custom 等工厂,并支持 in、descendantOf、ancestorOf、after、before、siblingOf、nthChild、notMatching 等关系查询。
OCR 文字定位
SDK 内置 PaddleOCR PP-OCRv5 Mobile ONNX Provider,并通过 onnxruntime-node 本地推理。第一次调用 OCR 时才会加载 OpenCV、ONNX Runtime 和模型文件。
import { Region, findText, readText, singleWord, textLine, waitForText } from "@geyj/auto-gui";
const saveButton = await findText(singleWord("保存"), {
searchRegion: new Region(0, 0, 1200, 800),
confidence: 0.8
});
const exported = await waitForText(textLine(/导出成功/), 5000);
const allText = await readText();
console.log(saveButton, exported, allText);调用方可以通过 providerRegistry.registerTextFinder(...) 替换默认 OCR Provider。
测试
根目录构建:
npm run prepare:ocr-models
npm run build:native
npm run build模块化测试项目位于 auto-gui-test/:
npm run test:api-capabilities
npm run test:clipboard-image:e2e
npm run test:inspector:e2e
cd auto-gui-test
npm install
npm run test:screen
npm run test:find-image
npm run test:find-color
npm run test:find-element
npm run test:find-text
npm run test:clipboard
npm run test:utils
npm run test:window-list
npm run test:window-active会操作真实桌面的测试请单独运行:
npm run test:mouse:e2e
npm run test:keyboard:e2e
cd auto-gui-test
npm run test:mouse
npm run test:keyboard
npm run test:window-actions根目录 npm test 会构建 TypeScript 和桌面捕获器、安装 auto-gui-test,然后运行 API 全景烟雾、Windows 图片剪贴板外部消费者 E2E、捕获器字段级 E2E,以及 auto-gui-test 的完整低影响模块集。真实鼠标、键盘和窗口动作不会混入默认测试,仍需使用上面的显式命令。
npm run test:api-capabilities 会验证根入口和全部子路径导出、基础类型和几何、图片编解码、屏幕/颜色/图片/窗口/UIA 低影响调用、OCR Provider 合约、未实现接口边界以及桌面捕获器启动/关闭。test:clipboard-image:e2e 会用独立 .NET 消费者复核图片尺寸和像素;test:inspector:e2e 会核对捕获器全部字段和“复制全部”行为。
OCR 烟雾测试:
$env:AUTO_GUI_OCR_DEBUG = "1"
npm run test:ocr:smoke -- tmp/ocr-smoke.png平台支持矩阵
| 能力 | Windows | macOS | Linux |
| --- | --- | --- | --- |
| 鼠标 | 已实现 | 已实现,需要 Accessibility 权限 | 已实现,依赖 X11 + XTest |
| 键盘 | 已实现 | 已实现,需要 Accessibility 权限 | 已实现,依赖 X11 + XTest;文本输入偏 ASCII |
| 文本剪贴板 | 已实现 | 已实现 | 已实现,需要 wl-copy、wl-paste、xclip 或 xsel |
| 图片剪贴板写入 | 已实现 | 尚未实现 | 尚未实现 |
| 屏幕截图、取色、高亮 | 已实现 | 尚未实现 | 尚未实现 |
| 窗口控制 | 已实现 | 尚未实现 | 尚未实现 |
| UI 元素读取 | 已实现,使用 UI Automation | 尚未实现 | 尚未实现 |
| 图片查找 | 已实现,依赖屏幕截图 | 受屏幕实现限制 | 受屏幕实现限制 |
| 颜色查找 | 已实现,依赖屏幕截图 | 受屏幕实现限制 | 受屏幕实现限制 |
| OCR 文字查找 | 已实现,依赖屏幕截图和内置模型 | 受屏幕实现限制 | 受屏幕实现限制 |
Electron 使用建议
桌面输入和窗口控制属于高权限能力。Electron 项目中建议只在主进程或受信任 preload 中调用 @geyj/auto-gui,再通过 IPC 暴露最小必要接口。不要把系统级鼠标、键盘、截图或剪贴板能力直接开放给远程网页、插件脚本或未验证输入。
已知限制
- 当前 npm 包没有预编译二进制,安装时会本地编译原生 addon。
- 当前
exports只配置了require条件,原生 ESM 入口尚未提供。 - 屏幕录制和流式截图入口已保留,但调用会抛出
UnsupportedScreenOperationError。 - PNG 编解码已实现,JPG 输出类型已保留但尚未实现。
- Windows 屏幕截图、窗口控制和 UI Automation 读取是同步原生调用,大区域截图或复杂元素树读取可能短暂阻塞 Node.js 事件循环。
- Windows 下单个可打印 Unicode 字符会直接使用原生键盘事件;整段文本、换行和制表符使用临时剪贴板粘贴。快速逐字符调用和整段输入均已通过真实 Notepad E2E。
完整逐项 API 测试方式见 docs/API_TEST_GUIDE.md。
当前能力、平台边界与验证状态见 docs/CAPABILITY_MAP.md,本轮实测结果和问题记录见 docs/API_TEST_REPORT.md。
版本更新记录见 CHANGELOG.md。
