在桌面自动化领域,Python 的 PyAutoGUI 或许是大家最熟悉的工具。但在 Go 语言生态中,一直缺乏一个既能处理底层驱动级输入,又能完美支持现代 Windows 特性(如高 DPI、多屏)的专业库。
今天我们将介绍 winput ------ 一个轻量级、无 CGO 依赖的 Go 语言 Windows 自动化库。它不仅支持标准的后台消息投递,还集成了内核级 HID 驱动模拟,是解决游戏反作弊、Electron 应用自动化等场景的利器。
winput 是什么?
winput 是一个专为 Windows 平台设计的 Go 语言输入自动化库。它的核心设计理念是 "确定性" 与 "双后端架构" :
-
双后端 (Dual Backend) :
- Message Backend :基于
PostMessage,适合后台静默操作,不占用鼠标。 - HID Backend :基于
Interception驱动,模拟物理硬件信号,能绕过绝大多数软件屏蔽。
- Message Backend :基于
-
现代特性:原生支持 Per-Monitor DPI 感知、多显示器负坐标、虚拟桌面截图。
-
纯 Go:不需要安装 GCC,开箱即用。
环境安装与配置
基础安装
由于 winput 是纯 Go 编写,直接 go get 即可:
arduino
go get github.com/rpdg/winput
驱动配置 (可选,仅 HID 模式需要)
如果你需要模拟驱动级输入 (例如在游戏中操作),你需要安装 Interception 驱动。
- 下载并安装 Interception 驱动。
- 将
interception.dll放在你的项目根目录或指定路径。
核心功能详解
鼠标控制
winput 提倡面向对象的操作。你首先获取一个窗口对象,然后对它进行操作。
scss
// 查找记事本窗口
w, err := winput.FindByTitle("无标题 - 记事本")
if err != nil {
log.Fatal(err)
}
// 1. 移动鼠标 (客户端坐标,即相对于窗口左上角)
w.Move(100, 100)
// 2. 点击
w.Click(100, 100) // 左键单击
w.ClickRight(100, 100) // 右键单击
w.DoubleClick(100, 100) // 双击 (驱动级优化,极稳)
键盘操作
支持字符串输入和快捷键。
scss
// 1. 输入文本 (自动处理 Shift 大小写)
w.Type("Hello winput!")
// 2. 按键 (按下并松开)
w.Press(winput.KeyEnter)
// 3. 组合键 (Ctrl + S)
w.PressHotkey(winput.KeyCtrl, winput.KeyS)
屏幕处理能力
自动化不仅仅是"模拟点击",更需要"看见"。
go
import "github.com/rpdg/winput/screen"
// 1. 获取所有显示器信息
monitors, _ := screen.Monitors()
for _, m := range monitors {
fmt.Printf("显示器: %s, 区域: %v\n", m.DeviceName, m.Bounds)
}
// 2. 截取整个虚拟桌面 (包含所有扩展屏)
img, err := screen.CaptureVirtualDesktop()
// img 是标准的 *image.RGBA,可以直接丢给 OpenCV 处理
实战应用场景:基于视觉的自动化点击
这是一个典型的"找图点击"实战:截屏 -> OpenCV 找图 -> 换算坐标 -> 驱动级点击。 (假设你已经配置好了 GoCV 或其他图像匹配库)
go
package main
import (
"log"
"github.com/rpdg/winput"
"github.com/rpdg/winput/screen"
// 假设你使用某个 cv 库
"your/cv/library"
)
func main() {
// 【关键】第一步:开启 DPI 感知
// 否则在高分屏下,截图坐标和点击坐标会对不上!
winput.EnablePerMonitorDPI()
// 1. 设置为 HID 驱动模式 (模拟真实硬件,防检测)
winput.SetHIDLibraryPath("libs/interception.dll")
if err := winput.SetBackend(winput.BackendHID); err != nil {
log.Fatal("驱动初始化失败,请检查DLL路径:", err)
}
// 2. 截取屏幕
img, err := screen.CaptureVirtualDesktop()
if err != nil {
log.Fatal(err)
}
// 3. 视觉识别 (伪代码)
// 在全屏截图中寻找 "LoginButton.png"
matchX, matchY, found := library.FindTemplate(img, "LoginButton.png")
if !found {
log.Fatal("未找到登录按钮")
}
// 4. 坐标转换
// 视觉库返回的是图片内的像素坐标 (0,0 开始)
// winput 需要的是虚拟桌面的绝对坐标 (可能是负数,如副屏)
targetX, targetY := screen.ImageToVirtual(int32(matchX), int32(matchY))
// 5. 执行点击
log.Printf("点击目标: %d, %d", targetX, targetY)
winput.MoveMouseTo(targetX, targetY)
winput.ClickMouseAt(targetX, targetY)
}
高级技巧与最佳实践
坐标系统与分辨率适配
Windows 的坐标系相对比较复杂(DPI 缩放、负坐标、虚拟桌面)。
- 永远调用
winput.EnablePerMonitorDPI():这是保证坐标精确的唯一法宝。 - 使用
screen.ImageToVirtual:不要自己手动加减坐标,因为主显示器不一定在左上角,直接加减在多屏环境下 100% 会出错。
错误处理与稳定性
winput 拒绝静默失败。利用这一点构建健壮的脚本:
go
// 尝试使用 HID 模式,如果失败则自动降级到消息模式
if err := winput.SetBackend(winput.BackendHID); err != nil {
log.Println("警告:HID 驱动未就绪,切换回普通消息模式。部分游戏可能无法响应。" )
// 无需操作,默认就是 Message 模式
}
err := w.Click(100, 100)
if err != nil {
// 可能是窗口被关闭了
if err == winput.ErrWindowGone {
// 重新查找窗口逻辑...
}
}
限制与注意事项
虽然 winput 很强,但也不是万能的:
- HID 模式的阻塞性 :为了模拟人类真实的鼠标轨迹,HID 模式下的
Move是阻塞的,且耗时(约几百毫秒,视距离而定,接近人类操作感)。如果你需要极速瞬移,请改用 Message 模式。 - 独占全屏游戏:部分独占全屏(Exclusive Fullscreen)游戏可能无法被 GDI 截图。此时你可能需要改用 OBS 采集卡或 DXGI 截图方案(winput 暂未内置 DXGI)。
- 系统权限:如果目标程序以管理员权限运行,你的 Go 程序也必须以管理员权限运行,否则会因 UIPI 权限不足被操作系统拦截。
结语
桌面自动化不再是简单的"模拟点击",而是一门需要处理驱动、图形学和操作系统特性的工程技术。
winput 通过双后端设计,让你在 "简单好用" (Message 模式)和 "无坚不摧" (HID 模式)之间自由切换。无论你是想写一个自动填表脚本,还是想攻克一个基于 Electron 的复杂应用,winput 都是 Go 语言生态下值得信赖的基础设施。
项目地址 : github.com/rpdg/winput