npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

rust-rpa

v0.2.7

Published

Rust-based RPA automation library for Node.js

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 - 窗口 ID
  • pid(): number - 进程 ID
  • parentId(): number - 父进程 ID
  • title(): string - 窗口标题
  • appName(): string - 应用程序名称
  • x(), y(), width(), height() - 位置和尺寸
  • getSize(): { width, height } - 窗口尺寸
  • isMinimized(), isMaximized(), isFocused() - 窗口状态
  • bringToFront() - 置顶窗口
  • maximize(), minimize() - 最大化/最小化
  • currentMonitor(): Monitor - 获取所在显示器
  • currentMonitorId(): number - 显示器 ID
  • getBounds(): { x, y, width, height } - 窗口边界
  • setBounds(bounds) - 设置窗口边界
  • toJSON() - 转为 JSON 对象
  • captureImage(options?) - 截图
  • watchChanges(options?, callback) - 监听窗口内容变化;返回 WindowWatcherstop() / isRunning() / changeOptions());启动时先建基线调回调,仅在检测到相对上一帧的变化时调用 callback(info)infochangeRatio 变化比例和 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 - 显示器 ID
  • name(): 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 上使用鼠标和键盘控制功能时,需要授予辅助功能权限:

  1. 打开 系统偏好设置
  2. 进入 安全性与隐私 > 隐私 > 辅助功能
  3. 点击锁图标进行更改
  4. 将您的终端应用程序或 IDE 添加到列表中
  5. 重启应用程序

屏幕录制权限(截图功能)

使用截图功能时,需要授予屏幕录制权限:

  1. 打开 系统偏好设置
  2. 进入 安全性与隐私 > 隐私 > 屏幕录制
  3. 点击锁图标进行更改
  4. 勾选您的终端应用程序或 IDE
  5. 重启应用程序

示例

窗口管理

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 模型,支持在 ImageDataWindowMonitor 上直接执行 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 为估算的原图逻辑像素变化数;启动首帧不触发回调(仅建基线);两帧缓冲区长度不一致时 changeRatio1changedPixels4294967295

0.2.6

行为调整

  • Window.watchChanges 启动:首帧仅建立对比基线,调用 callback;仅在后续轮询检测到相对上一帧的变化时才触发回调。

破坏性变更

  • Window.watchChanges 选项: region 已改为 regionsCaptureRegion 数组),可指定多个监控区域;
  • 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(窗口内容变化监听): 后台线程降采样对比相邻帧,超过阈值才触发回调;支持 thresholdfromwindow/screen)、regions(多区域,逻辑像素);返回 WindowWatcher,可 stop()changeOptions() 运行时改参。

0.2.3

修复

  • OCR recognizeText 多区域识别修复: 修复了 recognizeText 在指定多个 regions 时坐标转换错误的问题

0.2.2

新功能

  • Window 文字和图标操作新增 from 参数: findTextwaitTextclickTextrecognizeTextfindIconwaitIconclickIcon 方法新增 from 选项,用于指定截图来源
    • from: 'window'(默认)- 截取当前窗口内容
    • from: 'screen' - 截取窗口所在显示器的整屏内容
    • 适用场景:窗口被其他窗口遮挡时,从屏幕截图可以获取更完整的内容
    • 示例:window.findText('提示', { from: 'screen' })window.waitIcon(template, { from: 'screen' })

类型定义更新

  • Options 类型分离: 为 WindowMonitor 类分别定义独立的 Options 类型,使 API 更清晰
    • WindowMatchOptions / MonitorMatchOptions / MatchOptionsJs - 分别用于 findIcon
    • WindowFindTextOptions / MonitorFindTextOptions / FindTextOptions - 分别用于 findText
    • WindowRecognizeTextOptions / MonitorRecognizeTextOptions / RecognizeTextOptions - 分别用于 recognizeText
    • WindowWaitOptions / 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 包优化: 子模块迁移至 @alibot scoped package
    • 更清晰的包命名空间管理
    • 自动同步子模块版本与主包版本

BREAKCHANGE

  • captureImageautoSize 默认值改为 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)dxdy 参数现在表示像素值,而非滚动行数
    • 此前 Windows 和 macOS 使用不同的滚动单位,行为不一致
    • 现在统一按像素处理:传入 200 表示尝试滚动约 200 像素
    • Windows: 30 像素 ≈ 1 个 WHEEL_DELTA (120)
    • macOS: 20 像素 ≈ 1 行滚动
  • Windows 平台 Mouse.scroll 方向调整: dy 正数现在表示向下滚动(与 macOS 保持一致)
    • 此前 Windows 上正数向上滚动,与 macOS 相反
    • 现在双平台方向一致:正数向下,负数向上

功能

  • 所有输入操作自动添加延迟: MouseKeyboard 类的所有操作方法现在自动在返回前添加 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 参数中的 thresholdregions 字段均改为可选
    • threshold 不传时默认使用 0.8
    • regions 中的区域可超出图片边界,会自动裁剪为与图片的交集范围进行查找
  • 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()
  • window toJSON() 返回对象中取消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

致谢

构建基于以下项目: