rust-rpa
v0.2.7
Published
Rust-based RPA automation library for Node.js
Maintainers
Readme
rust-rpa
基于 Rust 的高性能 Node.js RPA(机器人流程自动化)库。
特性
- 🚀 高性能: 使用 Rust 编写,napi-rs 绑定,追求极致速度和效率
- 🔄 跨平台: 支持 Windows 和 macOS
- 📦 易于使用: 简洁的面向对象 API,支持 TypeScript
- ⚡ 非阻塞: 异步操作不会阻塞 Node.js 事件循环
- 🔒 类型安全: 完整的 TypeScript 类型定义
- 🖱️ 输入自动化: Mouse 和 Keyboard 类,完整的输入控制
- 📑 窗口管理: 基于 XCap 实现窗口枚举和信息获取
- 👁️ 窗口内容监听:
Window.watchChanges()降采样差异检测,内容变化时再截图,低开销监听 UI 变化 - 🖥️ 多显示器支持: Monitor 类,支持多显示器设置
- 📸 屏幕截图: 基于 XCap 实现全屏和窗口截图,多种图片格式(PNG/JPEG/BMP)
- 🔑 权限管理: Permission 类,自动检测并弹出系统权限授权对话框
- 🔍 OCR 文字识别: 基于 PP-OCRv5_mobile 模型和 MNN 推理框架,支持中英日文字识别
- 🎯 模板匹配: GPU 加速的图标查找功能,支持阈值和区域搜索
- 🖼️ 图像处理: 裁剪、缩放(Lanczos3)、灰度化等,支持 RGBA 原始数据访问
安装
npm install rust-rpa支持的平台:
- Windows (x64, x86)
- macOS (Intel x64, Apple Silicon ARM64)
注意: 当前版本不支持 Linux。
系统要求
Windows
- Windows 10 或更高版本 (x64 或 x86)
- 某些操作可能需要管理员权限
- 编译需要: Visual Studio Build Tools + LLVM (ocr-rs 依赖 bindgen,需要 libclang)
macOS
- macOS 10.13 或更高版本 (Intel 或 Apple Silicon)
- 需要辅助功能权限(见下文)
命令行工具
安装后可通过 rpa 命令直接使用,无需编写代码:
# 查看帮助
rpa --help
# 检查权限(macOS 自动弹出授权)
rpa permission --prompt
# 列出所有窗口
rpa window list
# 将窗口置于最前
rpa window focus Chrome
# 设置窗口位置和大小
rpa window bounds Chrome 100 100 800 600
# 截取主显示器
rpa screenshot -o desktop.png
# 截取指定窗口
rpa screenshot --window Chrome -o chrome.png
# 鼠标操作
rpa mouse position
rpa mouse move 500 300
rpa mouse move-rel 100 50
rpa mouse click right
rpa mouse scroll 0 -3
# 键盘操作
rpa keyboard type "Hello World"
rpa keyboard press enter
rpa keyboard press ctrl+c
# 剪贴板
rpa clipboard read
rpa clipboard write "Hello"
rpa clipboard paste
rpa clipboard paste-text "直接粘贴的文本"
rpa clipboard paste-image screenshot.png
# 列出所有显示器
rpa monitor list
# OCR 文字识别
rpa monitor recognize-text
rpa monitor find-text "确定"
rpa window find-text Chrome "搜索"
# 图片处理
rpa image info screenshot.png
rpa image crop screenshot.png 0 0 800 600 -o cropped.png
rpa image find-text screenshot.png "文字"
# 快捷命令(顶层)
rpa click right
rpa move 500 300
rpa type "Hello"
rpa press enter
rpa paste
rpa pause 1000所有命令支持 --help 查看详细用法,如 rpa screenshot --help。
示例代码
项目提供了丰富的示例代码,位于 examples/ 目录中:
permission-demo.js- 权限检查演示list-windows.js- 窗口管理演示screenshot-demo.js- 屏幕截图功能演示clipboard-demo.js- 剪贴板操作演示image-processing-demo.js- 图像处理功能演示find-icon-demo.js- 完整的 findIcon 功能演示find-icon-basic.js- findIcon 基础用法示例window-watch-changes-demo.js- 监听窗口内容变化(watchChanges),可选chrome/ding/qianniu
运行示例:
node examples/permission-demo.js
node examples/list-windows.js
node examples/window-watch-changes-demo.js chrome使用方法
JavaScript
const { Window, Monitor, Mouse, Keyboard, Permission } = require('rust-rpa');
async function main() {
try {
// 检查权限(macOS 上无权限会自动弹出授权对话框)
Permission.checkAccessibility();
Permission.checkScreenCapture();
// 获取所有窗口
const windows = Window.all();
console.log(`Found ${windows.length} windows`);
windows.forEach(win => {
console.log(`${win.appName()}: ${win.title()}`);
console.log(` PID: ${win.pid()}, Parent PID: ${win.parentId()}`);
console.log(` Position: (${win.x()}, ${win.y()}), Size: ${win.width()}x${win.height()}`);
});
// 将窗口置于最前
await windows[0].bringToFront();
// 获取所有显示器
const monitors = Monitor.all();
const primaryMonitor = monitors.find(m => m.isPrimary());
// 截图
const image = await primaryMonitor.captureImage();
const pngBuffer = await image.toPng();
// 鼠标和键盘控制
await Mouse.moveTo(100, 100);
await Mouse.click('left');
await Keyboard.typeText('Hello World!');
} catch (error) {
console.error('Error:', error.message);
}
}
main();API 文档
完整的 TypeScript 类型定义请参考 index.d.ts 文件。
Window 类
窗口管理类。
静态方法:
Window.all(): Window[]- 获取所有可见窗口
实例方法:
id(): number- 窗口 IDpid(): number- 进程 IDparentId(): number- 父进程 IDtitle(): string- 窗口标题appName(): string- 应用程序名称x(), y(), width(), height()- 位置和尺寸getSize(): { width, height }- 窗口尺寸isMinimized(), isMaximized(), isFocused()- 窗口状态bringToFront()- 置顶窗口maximize(), minimize()- 最大化/最小化currentMonitor(): Monitor- 获取所在显示器currentMonitorId(): number- 显示器 IDgetBounds(): { x, y, width, height }- 窗口边界setBounds(bounds)- 设置窗口边界toJSON()- 转为 JSON 对象captureImage(options?)- 截图watchChanges(options?, callback)- 监听窗口内容变化;返回WindowWatcher(stop()/isRunning()/changeOptions());启动时先建基线不调回调,仅在检测到相对上一帧的变化时调用callback(info)(info含changeRatio变化比例和changedPixels估算变化像素数);regions可指定多个逻辑像素监控区域;minChangedPixels可按原图逻辑像素数控制触发门槛;minPixelDiff可设置单像素最小通道差异(默认 30)过滤截图噪声recognizeText(options?)- OCR 识别文字findText(text, options?)- 查找文字findIcon(template, options?)- 查找图标waitText(text, options?)- 等待文字出现waitIcon(template, options?)- 等待图标出现clickText(text, options?)- 点击文字clickIcon(template, options?)- 点击图标
Window 专属 Options:
from?: 'window' | 'screen'- 截图来源('window'默认截窗口,'screen'截整屏)
Monitor 类
显示器管理类。
静态方法:
Monitor.all(): Monitor[]- 获取所有显示器
实例方法:
id(): number- 显示器 IDname(): string- 显示器名称x(), y(), width(), height()- 位置和尺寸scaleFactor(): number- 缩放因子isPrimary(): boolean- 是否主显示器captureImage(options?)- 截图recognizeText(options?)- OCR 识别文字findText(text, options?)- 查找文字findIcon(template, options?)- 查找图标waitText(text, options?)- 等待文字出现waitIcon(template, options?)- 等待图标出现clickText(text, options?)- 点击文字clickIcon(template, options?)- 点击图标
ImageData 类
图像处理类。
静态方法:
ImageData.fromFile(filePath)- 从文件加载ImageData.fromBuffer(buffer)- 从 Buffer 解码
属性:
width: number- 图像宽度height: number- 图像高度
方法:
toPng(), toJpeg(), toBmp()- 格式转换toFile(filePath)- 保存到文件crop(x, y, width, height)- 裁剪resize(width, height)- 缩放grayscale()- 灰度化getRawData(): Buffer- 获取原始像素数据metadata()- 获取图片元信息recognizeText(options?)- OCR 识别文字findText(text, options?)- 查找文字findIcon(template, options?)- 模板匹配
Mouse 类
鼠标控制类(静态方法)。
Mouse.moveTo(x, y, duration?)- 移动到坐标(duration 动画时间,秒)Mouse.moveRel(dx, dy, duration?)- 相对移动Mouse.click(button?)- 点击('left','right','middle')Mouse.doubleClick(button?)- 双击Mouse.down(button?), Mouse.up(button?)- 按下/释放Mouse.scroll(deltaX?, deltaY?)- 滚动(Y 正数向上、负数向下)Mouse.position()- 获取当前位置
Keyboard 类
键盘控制类(静态方法)。
Keyboard.typeText(text)- 输入文本Keyboard.click(key)- 按下并释放按键Keyboard.down(key), Keyboard.up(key)- 按下/释放Keyboard.sequence(keys)- 按键序列(如[Key.Ctrl, Key.C])
Key 枚举:Key.Enter, Key.Ctrl, Key.F1, Key.A 等
Clipboard 类
剪贴板控制类(静态方法)。
Clipboard.readText()- 读取剪贴板文本Clipboard.writeText(text)- 写入文本Clipboard.writeImage(source)- 写入图片(支持文件路径、base64、Buffer)Clipboard.writeFile(paths)- 写入文件路径Clipboard.paste()- 执行粘贴Clipboard.pasteText(text)- 写入并粘贴(自动恢复剪贴板)Clipboard.pasteImage(source)- 写入图片并粘贴(自动恢复)Clipboard.pasteFile(paths)- 写入文件路径并粘贴
Permission 类
权限检查类(静态方法)。
Permission.checkAccessibility(prompt?)- 检查辅助功能权限Permission.checkScreenCapture(prompt?)- 检查屏幕录制权限
说明:prompt 默认为 true,无权限时自动弹出系统授权对话框(仅 macOS)
pause 函数
pause(ms)- 等待指定毫秒数
const { pause } = require('rust-rpa');
await pause(1000); // 等待 1 秒macOS 权限要求
辅助功能权限(输入控制)
在 macOS 上使用鼠标和键盘控制功能时,需要授予辅助功能权限:
- 打开 系统偏好设置
- 进入 安全性与隐私 > 隐私 > 辅助功能
- 点击锁图标进行更改
- 将您的终端应用程序或 IDE 添加到列表中
- 重启应用程序
屏幕录制权限(截图功能)
使用截图功能时,需要授予屏幕录制权限:
- 打开 系统偏好设置
- 进入 安全性与隐私 > 隐私 > 屏幕录制
- 点击锁图标进行更改
- 勾选您的终端应用程序或 IDE
- 重启应用程序
示例
窗口管理
const { Window } = require('rust-rpa');
// 获取所有窗口
const windows = Window.all();
console.log(`Found ${windows.length} windows`);
// 遍历窗口
windows.forEach(win => {
console.log(`${win.appName()}: ${win.title()}`);
console.log(` PID: ${win.pid()}, Parent PID: ${win.parentId()}`);
console.log(` Position: (${win.x()}, ${win.y()})`);
console.log(` Size: ${win.width()}x${win.height()}`);
console.log(` Minimized: ${win.isMinimized()}, Focused: ${win.isFocused()}`);
});
// 将窗口置于最前
const target = windows.find(w => w.appName().includes('Chrome'));
if (target) {
await target.bringToFront();
}
// 获取/设置窗口边界
const bounds = windows[0].getBounds();
console.log(`Bounds: ${JSON.stringify(bounds)}`);
await windows[0].setBounds({ x: 100, y: 100, width: 800, height: 600 });
// 获取窗口所在显示器
const monitor = windows[0].currentMonitor();
console.log(`Window is on monitor: ${monitor.name()}`);
// 转为 JSON 对象
console.log(JSON.stringify(windows[0].toJSON(), null, 2));显示器管理
const { Monitor } = require('rust-rpa');
// 获取所有显示器
const monitors = Monitor.all();
monitors.forEach(m => {
console.log(`Monitor: ${m.name()}`);
console.log(` Resolution: ${m.width()}x${m.height()}`);
console.log(` Scale: ${m.scaleFactor()}x`);
console.log(` Primary: ${m.isPrimary()}`);
});
// 获取主显示器
const primary = monitors.find(m => m.isPrimary());屏幕截图
const fs = require('fs');
const { Monitor, Window, ImageData } = require('rust-rpa');
// 截取显示器
const monitors = Monitor.all();
const image = await monitors[0].captureImage();
// 截取时指定目标尺寸(自动缩放,便于后续扩展其他选项)
const imageResized = await monitors[0].captureImage({ size: { width: 800, height: 600 } });
// 保存为不同格式(方式 1:转换为 Buffer)
const pngBuffer = await image.toPng();
fs.writeFileSync('screenshot.png', pngBuffer);
const jpegBuffer = await image.toJpeg();
fs.writeFileSync('screenshot.jpg', jpegBuffer);
// 保存为不同格式(方式 2:直接保存文件)
await image.toFile('screenshot.png');
await image.toFile('screenshot.jpg');
await image.toFile('screenshot.bmp');
// 裁剪图像
const cropped = await image.crop(0, 0, 800, 600);
await cropped.toFile('cropped.png');
// 截取窗口
const windows = Window.all();
if (windows.length > 0) {
const windowImage = await windows[0].captureImage();
await windowImage.toFile('window.png');
}截图选项:captureImage(options?) 接受可选对象 CaptureImageOptions:
size?: { width, height }:截取后缩放到指定宽高,不传则返回原始尺寸。- Window 专用:
from?: 'window' | 'screen'默认截窗口,设为'screen'可截窗口所在显示器整屏再配合getBounds()与image.crop()裁剪;region?: { x, y, width, height }仅截取该逻辑像素区域;autoSize?: true在 Windows 高 DPI 下自动将图像缩放到逻辑像素宽高(与getSize/getBounds一致)。
输入自动化
const { Mouse, MouseButton, Keyboard, Key } = require('rust-rpa');
// 鼠标操作
await Mouse.moveTo(100, 200); // 瞬间移动鼠标
await Mouse.moveTo(100, 200, 0.5); // 平滑动画移动,持续 0.5 秒
await Mouse.moveRel(50, 30); // 相对移动(从当前位置向右 50、向下 30)
await Mouse.click(MouseButton.Left); // 左键点击
await Mouse.click(MouseButton.Right); // 右键点击
await Mouse.doubleClick(); // 双击
await Mouse.scroll(0, 3); // 向上滚动(正值 = 远离用户)
await Mouse.scroll(0, -3); // 向下滚动(负值 = 朝向用户)
// 获取鼠标位置
const { x, y } = await Mouse.position();
console.log(`Mouse at (${x}, ${y})`);
// 键盘操作(key 可用 Key 枚举或字符串)
await Keyboard.typeText('Hello World!'); // 输入文本
await Keyboard.click(Key.Enter); // 按 Enter
// 组合键
await Keyboard.sequence([Key.Ctrl, Key.A]); // Ctrl+A (全选)
await Keyboard.sequence([Key.Ctrl, Key.C]); // Ctrl+C (复制)
await Keyboard.sequence([Key.Meta, Key.V]); // Cmd+V (粘贴,macOS)
// 按键按下和释放
await Keyboard.down(Key.Shift);
await Keyboard.click(Key.A);
await Keyboard.up(Key.Shift);剪贴板操作
const path = require('path');
const { Clipboard, ImageData } = require('rust-rpa');
// 读取剪贴板
const text = await Clipboard.readText();
console.log('剪贴板内容:', text);
// 写入剪贴板
await Clipboard.writeText('Hello, Clipboard!');
// 写入图片到剪贴板(支持文件路径、Buffer、base64)
await Clipboard.writeImage(path.join(__dirname, 'test/images/ding_copy.png'));
// 写入文件到剪贴板(粘贴时为文件)
await Clipboard.writeFile(path.join(__dirname, 'rust-rpa.darwin-x64.node'));
// 执行粘贴操作(使用 Cmd/Ctrl+V)
await Clipboard.paste();
// pasteText / pasteImage 会自动恢复剪贴板;pasteFile 不会自动恢复
await Clipboard.pasteText('直接粘贴文本');
await Clipboard.pasteImage('image.png');
await Clipboard.pasteFile('/path/to/file.pdf');OCR 文字识别
利用 PP-OCRv5_mobile 模型,支持在 ImageData、Window 和 Monitor 上直接执行 OCR。
const { Monitor, Window, ImageData } = require('rust-rpa');
// --- ImageData 正中 OCR ---
const image = await ImageData.fromFile('screenshot.png');
// 识别图片中所有文字
const results = await image.recognizeText();
for (const result of results) {
console.log(`文字: ${result.text}`);
console.log(` 位置: (${result.x}, ${result.y}), 大小: ${result.width}x${result.height}`);
console.log(` 置信度: ${(result.confidence * 100).toFixed(1)}%`);
}
// 查找指定文字
const found = await image.findText('确定');
if (found) {
console.log(`找到"确定"在: (${found.x}, ${found.y})`);
}
// --- Monitor 上 OCR ---
const monitors = Monitor.all();
const monitorResults = await monitors[0].recognizeText();
console.log(`显示器上数到 ${monitorResults.length} 条文字`);
// 在显示器上查找文字
const monitorFound = await monitors[0].findText('文件');
if (monitorFound) {
console.log(`在显示器上找到"文件": (${monitorFound.x}, ${monitorFound.y})`);
}
// --- Window 上 OCR ---
const windows = Window.all();
const targetWindow = windows.find(w => w.appName().includes('Chrome'));
if (targetWindow) {
// 识别窗口中的文字(内部先截图)
const windowResults = await targetWindow.recognizeText();
console.log(`Chrome 窗口中有 ${windowResults.length} 条文字`);
// 在窗口中查找指定文字
const windowFound = await targetWindow.findText('搜索');
if (windowFound) {
console.log(`在窗口中找到"搜索": (${windowFound.x}, ${windowFound.y})`);
}
// 使用 notText 排除同一行的干扰文字
// 场景:同一行有"确定"和"取消"两个按钮,需要点击"确定"但排除"取消"所在行
const confirmBtn = await targetWindow.findText('确定', { notText: '取消' });
if (confirmBtn) {
console.log(`找到不与"取消"同行的"确定": (${confirmBtn.x}, ${confirmBtn.y})`);
}
// clickText 也支持 notText 参数
const clickResult = await targetWindow.clickText('发送', { notText: '草稿', timeout: 5000 });
console.log(`点击位置: (${clickResult.x}, ${clickResult.y})`);
// 使用 from 参数指定截图来源('window' 默认截窗口,'screen' 截窗口所在显示器整屏)
// 场景:窗口被其他窗口遮挡时,从屏幕截图可以获取更完整的内容
const screenResult = await targetWindow.findText('提示', { from: 'screen' });
if (screenResult) {
console.log(`在屏幕截图中找到"提示": (${screenResult.x}, ${screenResult.y})`);
}
// recognizeText 和 waitText 同样支持 from 参数
const screenTexts = await targetWindow.recognizeText({ from: 'screen' });
console.log(`屏幕截图中识别到 ${screenTexts.length} 条文字`);
const waitResult = await targetWindow.waitText('加载完成', { from: 'screen', timeout: 10000 });
console.log(`等待到文字出现: (${waitResult.x}, ${waitResult.y})`);
}平台支持
| 平台 | 架构 | 状态 | 备注 | |----------|-------------|--------|-------| | Windows | x64 | ✅ 支持 | 可能需要管理员权限 | | Windows | x86 (32位) | ✅ 支持 | 可能需要管理员权限 | | macOS | x64 (Intel) | ✅ 支持 | 需要辅助功能权限 | | macOS | ARM64 (Apple Silicon) | ✅ 支持 | 需要辅助功能权限 | | Linux | 全部 | ❌ 不支持 | 当前版本无计划 |
开发
从源码构建和开发指南请参阅 dev.md。
更新日志
0.2.7
新功能
- Window.watchChanges 新增
minChangedPixels参数: 支持按原图逻辑像素数控制变化触发,与threshold为 AND 关系minChangedPixels: 0(默认)- 不使用此条件,仅靠threshold控制minChangedPixels > 0- 估算的原图逻辑像素变化数须 >= 该值才触发回调- 示例:
{ threshold: 0.001, minChangedPixels: 500 }表示变化比例超过 0.1% 且 至少 500 个逻辑像素变化才触发
- Window.watchChanges 新增
minPixelDiff参数: 单像素最小通道差异(0-255),默认 30,用于过滤截图捕获噪声minPixelDiff: 30(默认)- R/G/B 任一通道差值 ≥ 30 才算“变化”,有效过滤截图噪声(通常差值 1-10)minPixelDiff: 0- 任意微小差异都计入(最敏感,但噪声也会触发)minPixelDiff: 1- 任意像素差异都计入(精确字节比较)- 示例:
{ threshold: 0, minChangedPixels: 2, minPixelDiff: 30 }过滤噪声同时保持对光标闪烁等微小变化的灵敏度
- Window.watchChanges 回调参数改为对象:
callback(info),info为{ changeRatio, changedPixels },其中changeRatio为相邻两帧像素变化比例(约 0.0–1.0),changedPixels为估算的原图逻辑像素变化数;启动首帧不触发回调(仅建基线);两帧缓冲区长度不一致时changeRatio为1、changedPixels为4294967295。
0.2.6
行为调整
- Window.watchChanges 启动:首帧仅建立对比基线,不调用
callback;仅在后续轮询检测到相对上一帧的变化时才触发回调。
破坏性变更
- Window.watchChanges 选项:
region已改为regions(CaptureRegion数组),可指定多个监控区域; WindowWatcher.changeOptions(options): 可按字段合并更新当前监听参数(仅传入字段覆盖,未传字段保持原值),下一轮轮询起生效;若已stop()再调用会报错。Window.watchChanges回调参数:callback(changeRatio),changeRatio为相邻两帧在降采样图上的像素变化比例(约 0.0–1.0);启动首帧不触发回调(仅建基线);两帧缓冲区长度不一致时为1。
0.2.5
改进
- Window.watchChanges 优化:
threshold参数默认值改为0.0,并优化为0时跳过图像对比threshold: 0(默认)- 跳过像素对比,每次轮询直接触发回调,最低延迟threshold > 0- 执行降采样对比,变化比例超过阈值才触发回调- 适用于已知窗口会变化、需要立即获取截图的场景
0.2.5
新功能
- findText / waitText / clickText 新增
index参数: 支持选择第几个匹配的文字结果index默认为0,返回第一个匹配结果- 正数表示第 n 个(从 0 开始):
index: 1返回第二个 - 负数表示倒数第 n 个:
index: -1返回最后一个,index: -2返回倒数第二个 - 超出匹配数量范围时返回
null - 适用场景:页面中存在多个相同文字,需要点击特定位置
- 示例:
findText('确定', { index: 1 })查找第二个「确定」,clickText('确定', { index: -2 })点击倒数第二个「确定」
类型定义更新
FindTextOptions新增index?: number字段WindowFindTextOptions新增index?: number字段MonitorFindTextOptions新增index?: number字段WindowWaitOptions新增index?: number字段MonitorWaitOptions新增index?: number字段WaitOptions新增index?: number字段
0.2.4
新功能
- Window.watchChanges(窗口内容变化监听): 后台线程降采样对比相邻帧,超过阈值才触发回调;支持
threshold、from(window/screen)、regions(多区域,逻辑像素);返回WindowWatcher,可stop()、changeOptions()运行时改参。
0.2.3
修复
- OCR
recognizeText多区域识别修复: 修复了recognizeText在指定多个regions时坐标转换错误的问题
0.2.2
新功能
- Window 文字和图标操作新增
from参数:findText、waitText、clickText、recognizeText、findIcon、waitIcon、clickIcon方法新增from选项,用于指定截图来源from: 'window'(默认)- 截取当前窗口内容from: 'screen'- 截取窗口所在显示器的整屏内容- 适用场景:窗口被其他窗口遮挡时,从屏幕截图可以获取更完整的内容
- 示例:
window.findText('提示', { from: 'screen' })、window.waitIcon(template, { from: 'screen' })
类型定义更新
- Options 类型分离: 为
Window和Monitor类分别定义独立的 Options 类型,使 API 更清晰WindowMatchOptions/MonitorMatchOptions/MatchOptionsJs- 分别用于findIconWindowFindTextOptions/MonitorFindTextOptions/FindTextOptions- 分别用于findTextWindowRecognizeTextOptions/MonitorRecognizeTextOptions/RecognizeTextOptions- 分别用于recognizeTextWindowWaitOptions/MonitorWaitOptions/WaitOptions- 分别用于waitText/waitIcon/clickText/clickIcon- 只有 Window 专用类型包含
from参数,Monitor 类型不包含(因为 Monitor 本身就是屏幕)
其他改进
- findText|waitText|clickText 匹配文字时,模糊匹配,例如 o 和 0 避免 OCR 识别不一致造成无法查找或者点击
- Window.maximize(): 最大化窗口
- Window.minimize(): 最小化窗口
0.2.1
新功能
findText / waitText / clickText 增强: 新增
notText参数,用于排除同一行中包含特定文字的匹配结果findText(text, { notText: '排除文字' })- 查找文字时,如果同一行中包含notText指定的文字,则排除该匹配结果waitText(text, { notText: '排除文字' })- 等待文字时同样支持排除逻辑clickText(text, { notText: '排除文字' })- 点击文字时同样支持排除逻辑- 适用场景:同一行内可能有多个相似文字,需要精确排除干扰项
- 同一行判断标准:两个文字区域的垂直方向有超过较小区域高度 50% 的重叠
clickText / clickIcon 返回值增强: 返回点击坐标信息
ClickResult- 返回
{ x, y, relX, relY },包含屏幕坐标和相对坐标 - 便于调试和验证点击位置
- 返回
ImageData.recognizeText 增强: 新增
options.regions参数,可指定识别区域列表
类型定义更新
FindTextOptions新增notText?: string字段WaitOptions新增notText?: string字段ClickResult类型:{ x: number, y: number, relX: number, relY: number }
0.2.0
新功能
- OCR 文字识别: 新增
recognizeText()和findText()方法- 基于 PP-OCRv5_mobile 模型(检测模型 4.7M + 识别模型 16M)
- 支持中文、英文、日文识别
ImageData.recognizeText()- 识别图片中的所有文字,返回文字列表及其位置信息ImageData.findText(text, options?)- 在图片中查找指定文字,返回匹配文字的位置信息;options.regions可指定查找区域列表以提升性能
- Window 类增强: 新增
findIcon()、recognizeText()、findText()、waitText()、waitIcon()、clickText()、clickIcon()方法- 所有方法内部先执行
captureImage({ autoSize: true }),然后在截图上执行对应操作 Window.findIcon(template, options?)- 在窗口截图中查找图标Window.recognizeText()- 识别窗口中的文字Window.findText(text, options?)- 在窗口中查找指定文字Window.waitText(text, options?)- 等待指定文字出现,超时抛出错误Window.waitIcon(template, options?)- 等待指定图标出现,超时抛出错误Window.clickText(text, options?)- 点击指定文字Window.clickIcon(template, options?)- 点击指定图标
- 所有方法内部先执行
- Monitor 类增强: 新增
findIcon()、recognizeText()、findText()、waitText()、waitIcon()、clickText()、clickIcon()方法- 所有方法内部先执行
captureImage({ autoSize: true }),然后在截图上执行对应操作 Monitor.findIcon(template, options?)- 在显示器截图中查找图标Monitor.recognizeText()- 识别显示器截图中的文字Monitor.findText(text, options?)- 在显示器截图中查找指定文字Monitor.waitText(text, options?)- 等待指定文字出现,超时抛出错误Monitor.waitIcon(template, options?)- 等待指定图标出现,超时抛出错误Monitor.clickText(text, options?)- 点击指定文字Monitor.clickIcon(template, options?)- 点击指定图标
- 所有方法内部先执行
- Mouse 类增强: 新增
moveRel()方法Mouse.moveRel(dx, dy, duration?)- 基于当前鼠标位置进行相对移动- 支持可选的
duration参数实现平滑动画移动
- CLI 命令增强: 新增多个便捷命令
rpa mouse move-rel <dx> <dy>- 相对移动鼠标rpa clipboard paste-text/rpa clipboard paste-image- 粘贴文本/图片并自动恢复剪贴板rpa image find-text/rpa image recognize-text- 图片 OCR 操作- 顶层快捷命令:
rpa click,rpa move,rpa type,rpa press,rpa paste,rpa pause
- npm 包优化: 子模块迁移至
@alibotscoped package- 更清晰的包命名空间管理
- 自动同步子模块版本与主包版本
BREAKCHANGE
captureImage的autoSize默认值改为true:Monitor.captureImage()和Window.captureImage()的autoSize选项默认值从false改为true- 现在默认自动将图像缩放到逻辑像素尺寸,与
getBounds()/getSize()返回的坐标一致 - 如需物理像素图像,需显式传入
autoSize: false - 影响范围:所有依赖截图尺寸的逻辑(OCR、模板匹配等)现在默认使用逻辑坐标
- rpa部分命令简化
- 现在默认自动将图像缩放到逻辑像素尺寸,与
API 变更
findIcon返回值调整:findIcon()方法在未找到匹配时现在返回null而非{ found: false, ... }对象- 找到匹配: 返回
MatchResult对象{ found: true, score, x, y, width, height } - 未找到匹配: 返回
null - 影响范围:
ImageData.findIcon(),Window.findIcon(),Monitor.findIcon() - 迁移指南: 使用
if (result) { ... }或if (result !== null) { ... }检查返回值
const result = await image.findIcon(template); if (result) { console.log(`找到图标: (${result.x}, ${result.y}), 置信度: ${result.score}`); } else { console.log('未找到图标'); }- 找到匹配: 返回
0.1.7
BREAKCHANGE
Mouse.scroll滚动单位改为像素:Mouse.scroll(dx, dy)的dx和dy参数现在表示像素值,而非滚动行数- 此前 Windows 和 macOS 使用不同的滚动单位,行为不一致
- 现在统一按像素处理:传入 200 表示尝试滚动约 200 像素
- Windows: 30 像素 ≈ 1 个 WHEEL_DELTA (120)
- macOS: 20 像素 ≈ 1 行滚动
- Windows 平台
Mouse.scroll方向调整:dy正数现在表示向下滚动(与 macOS 保持一致)- 此前 Windows 上正数向上滚动,与 macOS 相反
- 现在双平台方向一致:正数向下,负数向上
功能
- 所有输入操作自动添加延迟:
Mouse和Keyboard类的所有操作方法现在自动在返回前添加 50ms 延迟- 包括:
moveTo,click,doubleClick,down,up,scroll - 包括:
Keyboard.click,typeText,down,up,sequence - 确保系统有足够时间处理操作,避免后续操作立即执行导致失败
- 包括:
- 剪贴板操作自动添加延迟:
Clipboard类的写入和粘贴方法现在自动添加 50ms 延迟- 包括:
writeText,writeImage,writeFile,paste - 确保剪贴板内容写入完成后再执行后续操作
- 包括:
- 窗口操作自动添加延迟:
Window类的状态修改方法现在自动添加 50ms 延迟- 包括:
bringToFront,setBounds - 确保窗口状态变更完成后再执行后续操作
- 包括:
clickText/clickIcon返回点击坐标:Window.clickText()和Window.clickIcon()现在返回ClickResult对象- 返回
{ x, y }表示实际点击的屏幕坐标 - 便于调试和验证点击位置
- 返回
0.1.6
BREAKCHANGE
- Windows 平台鼠标坐标统一为逻辑像素:
Mouse.moveTo()和Mouse.position()现在统一使用逻辑像素坐标,与Window.getBounds()等 API 保持一致- 此前 Windows 平台上鼠标操作使用物理像素,在高 DPI 缩放环境下与窗口坐标不一致
- 现在 Windows 平台会自动处理 DPI 缩放,传入和返回的坐标均为逻辑像素
- macOS 平台不受影响(原本就使用逻辑像素)
0.1.5
功能
Mouse.moveTo增强: 新增可选duration参数,支持平滑动画移动duration为移动动画持续时间(秒),默认为 0(瞬间移动)- 当
duration > 0时,鼠标以平滑动画方式移动到目标点,使用 easeInOutCubic 缓动函数 - 动画过程中会触发 mouseMove 事件,网页等应用可正常响应鼠标移动
findIcon参数优化:options参数中的threshold和regions字段均改为可选threshold不传时默认使用 0.8regions中的区域可超出图片边界,会自动裁剪为与图片的交集范围进行查找
- Window.captureImage 选项
from:新增'window'(默认)与'screen'。设为'screen'时先截取窗口所在显示器整屏,再自动裁剪为当前窗口与显示器的交集区域(超出显示器的部分忽略)。 - Window.captureImage 选项
region:新增可选参数,仅截取指定逻辑像素区域{ x, y, width, height },不填则截取全图。 - Window.captureImage 选项
auto:新增可选参数。为true时,在 Windows 存在 DPI 缩放的情况下自动将图像缩放到逻辑像素宽高(与getSize/getBounds一致)。 - CaptureImageOptions 处理顺序:内部先执行
autoSize(缩放到逻辑像素),再执行region(按逻辑像素裁剪),最后应用size(若有)。启用autoSize后,region与逻辑像素坐标一一对应。
0.1.4
BREAKCHANGE
toJson()改为toJSON()windowtoJSON()返回对象中取消bounds- Window 数据一致性修复: 统一
getBounds()和toJSON()、setBounds()中屏幕宽高和窗口大小位置都使用逻辑像素,解决 Windows 环境下坐标不一致问题。
0.1.3
功能
- 新增
Window.getSize()方法: 返回{width, height}对象,提供便捷的窗口尺寸获取方式 - 新增
Window.currentMonitorId()方法: 获取窗口所在显示器的 ID,比currentMonitor()更轻量 Window.toJSON()增强: 现在包含monitorId字段,提供窗口所在显示器的 ID 信息
修复
bringToFront在mac中仅将当前窗口顶置,避免顶置其父窗口- windows缩放后,应用程序大小和屏幕大小使用的逻辑像素逻辑不一致,都改为使用真实逻辑像素,减少后续处理
0.1.2
修复
windows上的.node文件调用失败修复
0.1.1
新增
- CLI 命令行工具:安装后可通过
rpa命令直接使用,支持窗口/鼠标/键盘/剪贴板/截图/显示器/权限等全部功能 - Permission 类:新增
checkAccessibility()和checkScreenCapture(),macOS 自动弹出系统授权对话框,Windows 检查管理员权限 - Window.parentId():获取窗口所属进程的父进程 ID
- Window.bringToFront():将窗口置于最前,改为异步方法返回
Promise<void> - Window.setBounds():设置窗口位置和大小,改为异步方法返回
Promise<void> - Clipboard.pasteText(text):写入文本并粘贴,完成后自动恢复剪贴板原始内容
- Clipboard.pasteImage(source):写入图片并粘贴,完成后自动恢复剪贴板原始内容
- Clipboard.pasteFile(paths):写入文件并粘贴,不会自动恢复剪贴板原始内容
- ImageData.fromBase64(base64):从 base64 字符串或 data URI 创建 ImageData 对象
BreakChange
- Clipboard.writeImage(source):简化接口,不再需要手动传
width/height,支持文件路径、Buffer、base64 字符串、data URI 四种输入方式 - bringWindowToFrontById:已移除公开暴露,改为
bringToFront()实例方法内部调用 - WindowToJson / MonitorToJson:修正 TypeScript 定义中的字段命名为 camelCase(与 napi-rs 实际输出一致)
- Node.js 版本要求:最低版本从 14 提升至 18
许可证
MIT
致谢
构建基于以下项目:
- Rust - Rust 编程语言
- napi-rs - Node.js 的 Rust 绑定
- XCap - 跨平台截图库
- windows-rs - Windows 的 Rust 绑定
- core-foundation-rs - macOS 的 Rust 绑定
