第06章 - 屏幕与像素操作
让自动化程序“看见”屏幕,是实现智能化决策的前提。RobotGo 提供了读取屏幕尺寸、获取像素颜色、查询多显示器信息以及处理高分屏缩放等一系列与屏幕相关的能力。本章聚焦于这些“读取屏幕信息”的函数,截图与图像处理则留到下一章。
6.1 获取屏幕尺寸
最基础的屏幕信息是分辨率(宽和高):
sx, sy := robotgo.GetScreenSize()
fmt.Println("屏幕尺寸:", sx, sy) // 例如 1920 1080
GetScreenSize 返回主显示器的宽度和高度(像素)。在编写自动化脚本时,常用它来做坐标的相对计算,例如“点击屏幕正中央”:
sx, sy := robotgo.GetScreenSize()
robotgo.Move(sx/2, sy/2)
robotgo.Click()
通过相对屏幕尺寸计算坐标,比硬编码绝对坐标更能适应不同分辨率的机器。
6.2 获取像素颜色
GetPixelColor 返回指定坐标处像素的颜色,结果是一个不带 # 前缀的十六进制字符串(如 ffffff 表示白色):
color := robotgo.GetPixelColor(100, 200)
fmt.Println("颜色:", color) // 例如 "ff0000"
像素颜色检测是一种轻量级的“界面状态识别”手段。例如,判断某个开关按钮是否处于“开启”状态,可以读取它的颜色并与预期值比较:
func isButtonOn(x, y int) bool {
return robotgo.GetPixelColor(x, y) == "4caf50" // 绿色表示开启
}
6.2.1 等待某个像素变色
结合轮询,可以实现“等待界面进入某状态再继续”的逻辑:
func waitColor(x, y int, target string, timeoutMs int) bool {
elapsed := 0
for elapsed < timeoutMs {
if robotgo.GetPixelColor(x, y) == target {
return true
}
robotgo.MilliSleep(100)
elapsed += 100
}
return false
}
这种模式在自动化脚本中极为常见:先点击,再等待界面给出预期的视觉反馈,然后进行下一步。比固定 Sleep 更稳健。
6.3 获取鼠标位置
虽然属于鼠标范畴,但读取鼠标坐标常与屏幕操作配合使用:
x, y := robotgo.Location()
fmt.Println("鼠标位置:", x, y)
一个实用的小技巧:在编写脚本前,可以写一个循环不断打印鼠标坐标,用它来“拾取”目标元素的精确坐标:
package main
import (
"fmt"
"github.com/go-vgo/robotgo"
)
func main() {
for {
x, y := robotgo.Location()
color := robotgo.GetPixelColor(x, y)
fmt.Printf("坐标: (%d, %d) 颜色: %s\n", x, y, color)
robotgo.MilliSleep(500)
}
}
把鼠标移动到你关心的 UI 元素上,控制台就会实时打印它的坐标和颜色,非常方便后续硬编码或调试。
6.4 多显示器支持
现代开发环境常常配备多块显示器。RobotGo 提供了一组函数来处理多屏。
6.4.1 显示器数量
num := robotgo.DisplaysNum()
fmt.Println("显示器数量:", num)
6.4.2 当前操作的显示器:DisplayID
RobotGo 用全局变量 DisplayID 来指定后续截图等操作针对哪一块显示器(默认值通常为 -1 或 0,表示主屏):
robotgo.DisplayID = 1 // 切换到第 2 块显示器
6.4.3 显示器边界:GetDisplayBounds
GetDisplayBounds 返回指定显示器的边界(起始坐标与宽高):
num := robotgo.DisplaysNum()
for i := 0; i < num; i++ {
x, y, w, h := robotgo.GetDisplayBounds(i)
fmt.Printf("显示器 %d: 起点(%d, %d) 尺寸 %dx%d\n", i, x, y, w, h)
}
通过 GetDisplayBounds,你可以准确地知道每块屏幕在整个虚拟桌面坐标系中的位置和大小,从而正确地在某块副屏上定位、截图或点击。例如,要截取第 i 块屏幕的完整内容:
x, y, w, h := robotgo.GetDisplayBounds(i)
img, _ := robotgo.CaptureImg(x, y, w, h)
robotgo.Save(img, fmt.Sprintf("display_%d.png", i))
(CaptureImg 与 Save 的细节见下一章。)
6.5 高分屏与缩放(DPI / Retina)
在 Retina(macOS)或开启了系统缩放(如 Windows 150%、200%)的高分屏上,需要注意“逻辑像素”与“物理像素”的区别。例如 macOS Retina 屏上,截图得到的物理像素分辨率可能是逻辑坐标的两倍。
RobotGo 提供了一些辅助函数来处理缩放,例如获取缩放比例的 Scale、ScaleF,以及在不同坐标体系间转换的相关函数。处理高分屏时的通用建议:
- 统一坐标体系:明确你拿到的坐标是逻辑坐标还是物理坐标,避免混用。
- 以截图为准做图像匹配:图像查找(第 8 章)基于截图的物理像素,确保模板图与截图来自相同缩放环境。
- 实测校准:在目标机器上用 6.3 节的“坐标拾取”脚本实测,确认坐标与缩放的对应关系。
6.6 综合示例
下面把屏幕信息读取的能力集中演示一遍:
package main
import (
"fmt"
"github.com/go-vgo/robotgo"
)
func main() {
// 主屏尺寸
sx, sy := robotgo.GetScreenSize()
fmt.Println("主屏尺寸:", sx, sy)
// 鼠标位置与像素颜色
x, y := robotgo.Location()
fmt.Println("鼠标位置:", x, y)
fmt.Println("该点颜色:", robotgo.GetPixelColor(x, y))
// 遍历所有显示器
num := robotgo.DisplaysNum()
fmt.Println("显示器数量:", num)
for i := 0; i < num; i++ {
dx, dy, dw, dh := robotgo.GetDisplayBounds(i)
fmt.Printf("显示器 %d: 起点(%d, %d) 尺寸 %dx%d\n", i, dx, dy, dw, dh)
}
}
6.7 实战技巧与注意事项
- 优先相对坐标:用
GetScreenSize做相对计算,提升脚本在不同分辨率下的适配性。 - 轮询代替死等:用“轮询像素颜色”的方式等待界面状态,比固定
Sleep更稳定可靠。 - 颜色比对容差:屏幕渲染、抗锯齿可能导致颜色有细微差异。严格相等比较有时会失败,必要时可解析十六进制为 RGB 后做“近似匹配”(允许一定误差范围)。
- 多屏坐标基准:处理副屏时务必用
GetDisplayBounds拿到该屏的偏移,再做坐标换算。 - 高分屏先校准:在 Retina / 高缩放环境下,先用拾取脚本确认坐标与像素的真实关系,再编写正式逻辑。
6.8 小结
本章我们掌握了 RobotGo 读取屏幕信息的能力:获取屏幕尺寸、读取像素颜色、查询鼠标位置、处理多显示器(数量、DisplayID、GetDisplayBounds)以及高分屏缩放的注意事项。我们还学习了用“轮询像素”实现稳健的状态等待,以及用“坐标拾取脚本”辅助调试。下一章我们将进入截图与图像处理,把屏幕内容真正“拍下来”用于后续分析。