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

@qulingoo/win-proxy

v1.0.0

Published

Windows 自动化原生模块 — 窗口管理、截图、鼠标键盘模拟、进程控制、以图找图

Readme

win-proxy

基于 Rust + napi-rs 构建的 Windows 自动化原生 Node.js 模块。涵盖窗口管理、截图、鼠标键盘模拟、进程控制和计算机视觉(以图找图)等能力。

GitHub: https://github.com/qulingoo/win-proxy

安装与构建

npm install
npm run build        # release 构建
npm run build:debug  # debug 构建

使用方式

const {
  // 截图
  captureScreen, captureRegion, captureWindow,
  // 窗口
  findWindow, enumWindows, getForegroundWindow,
  // 输入
  mouseClick, keyPress, keyTypeText,
  // 进程
  shellExecute, terminateProcessById,
  // CV
  findOnScreen, findAllOnScreen, loadImage, saveImage,
  // 颜色
  getColorOnScreen, findColorOnScreen,
} = require("./index.js");

截图 API

captureScreen()

截取全屏,返回 ImageData

const screen = captureScreen();
console.log(screen.width, screen.height, screen.buffer.length);

captureRegion(x, y, width, height)

截取指定屏幕区域。

const region = captureRegion(100, 100, 400, 300);

captureWindow(hwnd)

截取指定窗口。hwnd 为窗口句柄(i64)。

const hwnd = findWindow(null, "计算器");
const img = captureWindow(hwnd);

返回类型 ImageData

| 字段 | 类型 | 说明 | |------|------|------| | width | number | 图像宽度(像素) | | height | number | 图像高度(像素) | | buffer | Buffer | RGBA 像素数据 |


窗口 API

查找与枚举

findWindow(className?, windowName?)

根据类名或窗口标题查找顶层窗口,返回窗口句柄。未找到返回 0

const hwnd = findWindow(null, "记事本");
const hwnd = findWindow("Notepad", null);

findWindowEx(parent, afterChild, className?, windowName?)

在父窗口内查找子窗口。afterChild 为从前一个子窗口之后开始搜索,传 0 从头搜索。

const child = findWindowEx(parentHwnd, 0, "Edit", null);

enumWindows()

枚举所有顶层窗口,返回句柄数组。

const handles = enumWindows();

enumChildWindows(parent)

枚举指定窗口的所有子窗口。

const children = enumChildWindows(parentHwnd);

windowFromPoint(x, y)

获取屏幕坐标处的窗口句柄。

getDesktopWindow()

获取桌面窗口句柄。

getForegroundWindow()

获取当前前台窗口句柄。

getTopWindow(hwnd)

获取指定窗口的 Z 序顶部子窗口。

getWindow(hwnd, cmd)

获取与指定窗口有特定关系的窗口。cmdGW_* 常量(如 GW_OWNER = 4, GW_HWNDNEXT = 2)。

窗口信息

getWindowText(hwnd)

获取窗口标题文本。

setWindowText(hwnd, text)

设置窗口标题文本。

getClassName(hwnd)

获取窗口类名。

getWindowRect(hwnd)

获取窗口在屏幕上的矩形区域,返回 Rect { left, top, right, bottom }

getClientRect(hwnd)

获取窗口客户区矩形,返回 Rect

isWindow(hwnd)

判断句柄是否为有效窗口。

isWindowVisible(hwnd)

判断窗口是否可见。

isWindowEnabled(hwnd)

判断窗口是否启用(可交互)。

getParent(hwnd)

获取父窗口句柄。

getAncestor(hwnd, flags)

获取祖先窗口句柄。flagsGA_* 常量(GA_PARENT = 1, GA_ROOT = 2, GA_ROOTOWNER = 3)。

getWindowThreadProcessId(hwnd)

获取窗口所属线程和进程 ID,返回 ThreadProcessId { threadId, processId }

getWindowLongPtr(hwnd, index)

获取窗口长指针值。indexGWLP_* 常量。

setWindowLongPtr(hwnd, index, value)

设置窗口长指针值。

getClassLongPtr(hwnd, index)

获取类长指针值。

getWindowPlacement(hwnd) / setWindowPlacement(hwnd, placement)

获取/设置窗口放置信息,返回/接受 WindowPlacement 对象。

const placement = getWindowPlacement(hwnd);
console.log(placement.showCmd); // 1=正常, 2=最小化, 3=最大化

窗口操作

showWindow(hwnd, cmd)

控制窗口显示状态。cmdSW_* 常量:

  • SW_HIDE = 0 — 隐藏
  • SW_SHOW = 5 — 显示
  • SW_MINIMIZE = 6 — 最小化
  • SW_MAXIMIZE = 3 — 最大化
  • SW_RESTORE = 9 — 还原

setForegroundWindow(hwnd)

将窗口设为前台窗口。

moveWindow(hwnd, x, y, width, height, repaint)

移动并调整窗口大小。repaint 是否重绘。

setWindowPos(hwnd, after, x, y, width, height, flags)

设置窗口 Z 序和位置。after 可用 HWND_TOPMOST (0xFFFFFFFF) 等值。

closeWindow(hwnd)

最小化窗口(不是关闭,Win32 API 行为)。

bringWindowToTop(hwnd)

将窗口提到 Z 序顶部。

enableWindow(hwnd, enable)

启用/禁用窗口。

setFocus(hwnd) / getFocus()

设置/获取键盘焦点窗口。

updateWindow(hwnd)

强制窗口更新客户区。

窗口消息

sendMessage(hwnd, msg, wparam, lparam)

同步发送窗口消息,返回消息结果。

postMessage(hwnd, msg, wparam, lparam)

异步投递窗口消息到队列,返回是否成功。


鼠标 API

光标

getCursorPos()

获取光标位置,返回 Point { x, y }

const pos = getCursorPos();
console.log(pos.x, pos.y);

setCursorPos(x, y)

设置光标位置。

getCursorInfo()

获取光标详细信息,返回 CursorInfo { flags, showing, handle, x, y }

showCursor(show)

显示/隐藏光标。true 显示,false 隐藏。

鼠标点击

按钮编号:0 = 左键,1 = 右键,2 = 中键。

mouseDown(button)

按下鼠标按键。

mouseUp(button)

释放鼠标按键。

mouseClick(button)

单击鼠标按键(按下+释放)。

mouseClick(0); // 左键单击

mouseDoubleClick(button)

双击鼠标按键。

鼠标移动

mouseMoveTo(x, y)

绝对移动光标到屏幕坐标。

mouseMoveRelative(dx, dy)

相对当前光标位置移动。

滚轮

mouseScroll(delta)

垂直滚轮。正值向上滚动,负值向下滚动。通常步进为 120WHEEL_DELTA)。

mouseScroll(120);   // 向上滚一格
mouseScroll(-120);  // 向下滚一格
mouseScroll(360);   // 向上滚三格

mouseScrollHorizontal(delta)

水平滚轮。正值向右,负值向左。


键盘 API

按键操作

vk 参数为虚拟键码(Virtual Key Code),常见值:

  • 0x08 Backspace, 0x0D Enter, 0x1B Escape
  • 0x10 Shift, 0x11 Ctrl, 0x12 Alt
  • 0x20 Space, 0x2D Insert, 0x2E Delete
  • 0x41~0x5A A~Z, 0x30~0x39 0~9
  • VK_F1~VK_F12: 0x70~0x7B

keyDown(vk)

按下按键。

keyUp(vk)

释放按键。

keyPress(vk)

按下并释放按键(单击)。

keyPress(0x0D); // 按下 Enter
keyPress(0x1B); // 按下 Escape

keyCombo(modifiers, key)

组合键。先按住所有修饰键,再点击主键,最后释放所有修饰键。

keyCombo([0x11], 0x43);          // Ctrl+C (复制)
keyCombo([0x11], 0x56);          // Ctrl+V (粘贴)
keyCombo([0x11, 0x10], 0x1B);    // Ctrl+Shift+Esc (任务管理器)
keyCombo([0x12], 0x09);          // Alt+Tab

文字输入

keyTypeChar(ch)

输入单个 Unicode 字符。

keyTypeText(text)

输入一段文字字符串。

keyTypeText("Hello, 世界!");

键盘状态

getAsyncKeyState(vk)

异步获取按键状态(是否正在被按下)。

if (getAsyncKeyState(0x01)) { /* 鼠标左键正在按下 */ }

getKeyState(vk)

获取按键状态。bit 15 = 是否按下,bit 0 = 是否切换(如 CapsLock)。

getKeyboardState()

获取全部 256 个虚拟键的状态,返回 Buffer(256 字节)。

键码映射

mapVirtualKey(code, mapType)

虚拟键码↔扫描码↔字符映射。mapType0 = VK→扫描码, 1 = 扫描码→VK, 2 = VK→字符, 3 = 扫描码→VK(区分左右)。

vkKeyScan(ch)

字符→虚拟键码。低字节为 VK 码,高字节为修饰键状态(bit 0=Shift, bit 1=Ctrl, bit 2=Alt)。


进程 API

启动进程

shellExecute(verb?, file, args?, directory?, show)

通过 ShellExecuteEx 启动程序。返回 ProcessInfo { processId, threadId, handle }

| 参数 | 说明 | |------|------| | verb | 操作:"open"(默认)、"runas"(管理员)、"print" 等,传 null 为默认 | | file | 要打开的文件或程序路径 | | args | 命令行参数 | | directory | 工作目录 | | show | 显示方式:1=正常, 0=隐藏, 3=最大化, 6=最小化 |

const proc = shellExecute(null, "notepad.exe", null, null, 1);
console.log(proc.processId, proc.handle);

// 以管理员权限运行
shellExecute("runas", "cmd.exe", null, null, 1);

createProcess(application?, commandLine?, show)

通过 CreateProcess 启动程序,返回 ProcessInfo

const proc = createProcess("C:\\Windows\\notepad.exe", null, 1);

终止进程

terminateProcessById(pid, exitCode)

通过进程 ID 终止进程。

terminateProcessById(1234, 0);

terminateProcess(handle, exitCode)

通过进程句柄终止进程。

closeHandle(handle)

关闭句柄(不会终止进程)。

进程信息

isProcessActive(handle)

检查进程是否仍在运行。

if (isProcessActive(proc.handle)) {
  console.log("进程仍在运行");
}

getProcessId(handle)

从进程句柄获取 PID。

waitForProcess(handle, timeoutMs)

等待进程退出。timeoutMs0xFFFFFFFF 表示无限等待。

waitForInputIdle(handle, timeoutMs)

等待进程初始化完成(用于启动后等待窗口就绪)。

进程列表

enumProcesses()

枚举所有运行中的进程,返回 ProcessEntry[]

const procs = enumProcesses();
for (const p of procs) {
  console.log(`PID: ${p.processId}  父PID: ${p.parentProcessId}  线程: ${p.threadCount}  ${p.exeFile}`);
}

findProcesses(name)

按进程名模糊搜索(不区分大小写)。

const notepads = findProcesses("notepad");

killProcessesByName(name, exitCode)

按名称批量终止进程,返回被终止的 PID 列表。

const killed = killProcessesByName("notepad", 0);
console.log(`已终止 ${killed.length} 个进程`);

计算机视觉 (CV) API

模板匹配(以图找图)

基于 NCC(归一化互相关)算法 + rayon 多线程两阶段搜索。1920x1080 全屏搜索约 400ms。

findImage(source, srcW, srcH, template, tplW, tplH, options?)

在源图像 buffer 中搜索模板,返回第一个匹配(或 null)。

const src = loadImage("screenshot.png");
const tpl = loadImage("target.png");
const match = findImage(src.buffer, src.width, src.height, tpl.buffer, tpl.width, tpl.height, {
  threshold: 0.9,
});
if (match) {
  console.log(`找到: (${match.x}, ${match.y}) 匹配度: ${(match.score * 100).toFixed(1)}%`);
}

findAllImages(source, srcW, srcH, template, tplW, tplH, options?)

查找所有匹配位置,返回 MatchResult[]

findOnScreen(template, tplW, tplH, options?)

直接在屏幕上搜索模板(自动截图),返回第一个匹配。

const tpl = loadImage("button.png");
const match = findOnScreen(tpl.buffer, tpl.width, tpl.height, {
  threshold: 0.85,
});
if (match) {
  mouseMoveTo(match.x + match.width / 2, match.y + match.height / 2);
  mouseClick(0);
}

findAllOnScreen(template, tplW, tplH, options?)

在屏幕上搜索所有匹配位置。

MatchOptions 参数:

| 字段 | 类型 | 默认值 | 说明 | |------|------|--------|------| | threshold | number | 0.8 | 匹配阈值 (0~1),越高越严格 | | maxResults | number | 10 | 最大返回数量(仅 findAll* 有效) | | step | number | 自动 | 搜索步长(内部自动两阶段优化) | | regionX | number | 0 | 搜索区域 X 起点 | | regionY | number | 0 | 搜索区域 Y 起点 | | regionWidth | number | 全屏 | 搜索区域宽度 | | regionHeight | number | 全屏 | 搜索区域高度 |

MatchResult 返回值:

| 字段 | 类型 | 说明 | |------|------|------| | x | number | 匹配位置 X(左上角) | | y | number | 匹配位置 Y(左上角) | | width | number | 模板宽度 | | height | number | 模板高度 | | score | number | 匹配分数 (0~1) |

颜色操作

getColorAt(image, width, x, y)

获取图像 buffer 中指定坐标的颜色,返回 Color { r, g, b, a }

const screen = captureScreen();
const color = getColorAt(screen.buffer, screen.width, 100, 200);
console.log(`rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`);

getColorOnScreen(x, y)

直接获取屏幕上指定坐标的颜色(自动截图 1x1 区域)。

findColor(image, width, height, r, g, b, tolerance?)

在图像 buffer 中查找指定颜色,返回 Point { x, y }null

const screen = captureScreen();
const pt = findColor(screen.buffer, screen.width, screen.height, 255, 0, 0, 30);
if (pt) console.log(`找到红色: (${pt.x}, ${pt.y})`);

findColorOnScreen(r, g, b, tolerance?)

直接在屏幕上查找指定颜色。tolerance 默认 10,值越大容差越大。

图片 I/O

loadImage(path)

从文件加载图片(支持 PNG、JPEG、BMP 等),返回 LoadedImage { width, height, buffer }

const img = loadImage("template.png");

saveImage(path, buffer, width, height)

将 RGBA buffer 保存为图片文件(根据扩展名决定格式)。

const screen = captureScreen();
saveImage("screenshot.png", screen.buffer, screen.width, screen.height);

类型汇总

interface ImageData { width: number; height: number; buffer: Buffer }
interface LoadedImage { width: number; height: number; buffer: Buffer }
interface Rect { left: number; top: number; right: number; bottom: number }
interface Point { x: number; y: number }
interface WindowPlacement {
  flags: number; showCmd: number;
  minPosition: Point; maxPosition: Point; normalPosition: Rect;
}
interface ThreadProcessId { threadId: number; processId: number }
interface CursorInfo { flags: number; showing: boolean; handle: number; x: number; y: number }
interface ProcessInfo { processId: number; threadId: number; handle: number }
interface ProcessEntry { processId: number; parentProcessId: number; threadCount: number; exeFile: string }
interface MatchResult { x: number; y: number; width: number; height: number; score: number }
interface MatchOptions {
  threshold?: number; step?: number; maxResults?: number;
  regionX?: number; regionY?: number; regionWidth?: number; regionHeight?: number;
}
interface Color { r: number; g: number; b: number; a: number }

反馈

遇到 Bug、有功能建议或使用疑问,欢迎提交 Issue,会尽快回复。

许可证

ISC