原生能力
native/ 下的四个包提供 Gio 没有的系统能力。它们不依赖界面模块,可以单独使用。
| 包 | 能力 | 需要的权限 |
|---|---|---|
native/permission |
检查、申请权限 | 无 |
native/screen |
列出显示器;截图 | 截图需要屏幕录制 |
native/input |
移动鼠标、点击、按键 | 读取鼠标位置以外的操作都需要辅助功能 |
native/hotkey |
全局快捷键 | 无 |
支持三个平台,其他平台以及关闭 cgo 构建的 macOS 上,所有函数返回 native.ErrUnsupported,程序照常编译。
| 平台 | 实现 | 说明 |
|---|---|---|
| macOS 14+ | cgo 调用系统框架 | 需要用户授权,见下文 |
| Windows 10+ | 直接调用 user32、gdi32,不需要 cgo | 不需要授权;坐标按主显示器的 DPI 换算成逻辑点 |
| Linux | 纯 Go 实现 X11 协议,不需要 cgo | 需要 X11 会话;合成输入需要 X 服务器的 XTEST 扩展;逻辑点按 Xft.dpi 换算 |
Linux 的 Wayland 会话不允许普通程序截取整个屏幕或向其他程序注入输入。有 XWayland(DISPLAY 已设置)时可以调用,但只能看到、操作 X11 程序的窗口;没有 DISPLAY 时返回 ErrUnsupported。
错误
所有错误都包装自 native 包里的哨兵值,用 errors.Is 判断:
| 错误 | 含义 |
|---|---|
ErrUnsupported |
当前平台没有实现 |
ErrPermissionDenied |
缺少所需权限 |
ErrInvalidArgument |
参数不合法,比如未知按键名、显示器 ID 为 0 |
ErrTimeout |
系统调用超时(截图超过 10 秒) |
ErrConflict |
全局快捷键已被本进程或其他程序占用 |
ErrFailed |
其他系统错误,错误信息里带状态码 |
if _, err := screen.Capture(id); errors.Is(err, native.ErrPermissionDenied) {
permission.Request(permission.ScreenRecording)
}
permission:权限
ok, err := permission.Granted(permission.Accessibility) // 只查,不弹窗
ok, err := permission.Request(permission.Accessibility) // 可能弹出系统授权框
| 常量 | 系统设置里的名字 | 谁需要 |
|---|---|---|
Accessibility |
辅助功能 | input 包 |
ScreenRecording |
屏幕录制(macOS 15 起叫"屏幕与系统录音") | screen.Capture |
InputMonitoring |
输入监控 | 目前没有功能用到,预留 |
Windows 和 Linux 没有这几种授权,Granted 和 Request 总是返回 true。
在 macOS 上使用时要注意三点:
Request不等用户回答。 它弹框后立刻返回当时的授权状态,通常是false。用户在系统设置里打开开关后,你需要再调Granted确认。false不区分"拒绝过"和"还没问过"。 macOS 不提供这个信息。- 授权记在哪个程序名下。 打包成
.app运行时,授权记在这个 app 名下;在终端里go run,macOS 通常把授权记在终端程序(终端、iTerm、VS Code)名下。屏幕录制权限授予后,一般要重启程序才生效。
screen:显示器与截图
displays, err := screen.Displays()
for _, d := range displays {
fmt.Println(d.ID, d.X, d.Y, d.Width, d.Height, d.PixelWidth, d.PixelHeight, d.Primary)
}
X、Y、Width、Height 是逻辑点坐标,原点在主显示器左上角,副屏可能是负坐标。input 包用同一套坐标。
png, err := screen.Capture(d.ID)
- 返回 PNG 字节,尺寸为
PixelWidth × PixelHeight,不含鼠标指针。 - macOS 上需要屏幕录制权限,自己不会弹框,没有权限直接返回
ErrPermissionDenied。 - 最多阻塞 10 秒。不要在回调里调用,它会让所有窗口卡住。放进 goroutine,结果用
core.Update送回界面。 - macOS 上不能在主线程调用,否则返回
ErrFailed。main函数在window.Main()之前运行在主线程上,也不能在那里调用。
input:合成键鼠
x, y, err := input.MousePosition() // 不需要权限
input.MouseMove(100, 200) // 以下都需要辅助功能权限
input.Click(input.Left) // 在当前鼠标位置点击;Left / Right / Middle
input.Tap("enter") // 按下并松开
input.KeyDown("cmd"); input.Tap("c"); input.KeyUp("cmd") // ⌘C
按键名按美式键盘的物理位置,与当前输入法和键盘布局无关(Linux 例外:X11 按当前布局查找能打出这个字符的键):
- 字母、数字、符号:
a–z、0–9、-=[]\;',./` - 功能键:
entertabspacebackspacedeleteescapehomeendpageuppagedownupdownleftrightf1–f12 - 修饰键:
cmdshiftaltctrl。Windows 和 Linux 上cmd是 Windows 键(Super)。
KeyDown 和 KeyUp 必须成对调用,否则系统会认为这个键一直按着。
hotkey:全局快捷键
其他应用在前台时也能触发。窗口有焦点时才生效的快捷键用 window.Options.Shortcuts。
unregister, err := hotkey.Register("cmd+shift+k", func() {
core.Update(func() { status.SetText("触发了") })
})
defer unregister()
- 写法是
修饰键+按键,至少要一个修饰键。修饰键:cmdctrlalt(或option)shift;按键名同input包。 - 回调在独立的 goroutine 里执行,不持有界面锁,改界面必须包进
core.Update。 - 回调还在执行时又按了几次,只会再触发一次,不会排队。
- 组合键已被占用时返回
ErrConflict。 unregister可以重复调用,只有第一次生效。
cmd 在 Windows 和 Linux 上是 Windows 键(Super)。跨平台的快捷键通常写成 macOS 用 cmd、其他平台用 ctrl。
macOS 上需要 window.Main() 在运行:快捷键事件由主线程的事件循环派发。Windows 和 Linux 有自己的消息线程,不受这个限制。macOS 上不开窗口的纯后台程序暂时用不了,见常见问题。
notification:系统通知
native/notification 提供 Available、RequestPermission、Post 和 Remove,完成回调在独立 goroutine 执行。当前实现 macOS .app 的授权、按 ID 投递/替换和撤回,以及 Linux 桌面 D-Bus 后端;Windows 和其他未支持平台明确返回不支持。kit.Notifier 通过应用适配器接入,macOS 已实现原生前台展示与 Message.OnClick,kit 可通过交互后端接收系统点击并请求 Window.Raise,Linux 已支持声明 actions 的服务的默认点击,Wayland ActivationToken 与 Windows 后端仍未完成,完整用法与验收步骤见 模块文档。