znlgis 博客

GIS开发与技术分享 — GDAL · GeoServer · PostGIS · QGIS · OpenLayers · Cesium · FreeCAD · NPOI

第09章 - 剪贴板操作

剪贴板是桌面自动化中一个看似简单却极其实用的能力。它不仅能在程序之间传递文本,更是“高效输入大段文本”和“读取界面内容”的关键手段。本章讲解 RobotGo 的剪贴板读写函数、它在自动化中的高级用法,以及相关的平台依赖与注意事项。

9.1 剪贴板的两个核心函数

RobotGo 主库提供了两个简洁的剪贴板函数:

  • WriteAll(text string) error:把文本写入系统剪贴板。
  • ReadAll() (string, error):从系统剪贴板读取文本。

基本用法:

package main

import (
    "fmt"

    "github.com/go-vgo/robotgo"
)

func main() {
    // 写入剪贴板
    err := robotgo.WriteAll("通过 RobotGo 写入的文本")
    if err != nil {
        fmt.Println("写入失败:", err)
        return
    }

    // 读取剪贴板
    text, err := robotgo.ReadAll()
    if err != nil {
        fmt.Println("读取失败:", err)
        return
    }
    fmt.Println("剪贴板内容:", text)
}

两个函数都返回 error,在实际代码中应当检查错误,尤其是在 Linux 上(剪贴板依赖外部命令,环境不全时可能失败)。

9.2 高级用法一:用剪贴板快速输入大段文本

第 5 章提到,Type 是逐字符输入,输入长文本既慢又容易因输入法干扰而出错。利用剪贴板“写入 + 粘贴”可以瞬间完成大段文本输入:

func pasteText(text string) error {
    if err := robotgo.WriteAll(text); err != nil {
        return err
    }
    robotgo.MilliSleep(100) // 给系统一点时间完成写入

    // 粘贴:Windows/Linux 用 ctrl,macOS 用 cmd
    robotgo.KeyTap("v", "ctrl")
    return nil
}

这种方式与文本长度几乎无关,无论是几个字还是几千字,粘贴都是一瞬间完成,而且不受输入法状态影响,是自动化填表、批量录入的首选方案。

9.3 高级用法二:用剪贴板读取界面内容

反过来,剪贴板也是“读取屏幕上文本”的有效途径。很多 GUI 控件无法直接读取其文本,但可以通过“全选 + 复制”把内容送进剪贴板,再用 ReadAll 读出来:

func grabSelectedText() (string, error) {
    // 复制当前选中内容
    robotgo.KeyTap("c", "ctrl")
    robotgo.MilliSleep(100) // 等待系统完成复制
    return robotgo.ReadAll()
}

func grabAllText() (string, error) {
    robotgo.KeyTap("a", "ctrl") // 全选
    robotgo.MilliSleep(50)
    robotgo.KeyTap("c", "ctrl") // 复制
    robotgo.MilliSleep(100)
    return robotgo.ReadAll()
}

这是在无法通过常规 API 读取内容时的“万能读取法”,在自动化测试中用于断言界面文本尤为常见。

9.4 高级用法三:保护与恢复用户剪贴板

自动化脚本使用剪贴板会覆盖用户原本的剪贴板内容,这可能造成困扰。礼貌的做法是在操作前备份、操作后恢复:

func withClipboard(temp string, action func()) error {
    // 备份原剪贴板
    backup, _ := robotgo.ReadAll()

    // 写入临时内容并执行操作
    if err := robotgo.WriteAll(temp); err != nil {
        return err
    }
    robotgo.MilliSleep(50)
    action()

    // 恢复原剪贴板
    robotgo.MilliSleep(50)
    return robotgo.WriteAll(backup)
}

这样用户在脚本运行前复制的内容不会被你的脚本“吃掉”。

9.5 实战示例:文本扩展工具

把剪贴板与输入结合,可以做一个简单的“文本扩展”小工具:输入一个缩写,自动替换为预设的长文本。下面演示核心逻辑(热键触发部分见第 11 章):

package main

import (
    "github.com/go-vgo/robotgo"
)

var snippets = map[string]string{
    "/addr":  "北京市海淀区中关村大街 1 号",
    "/email": "example@example.com",
    "/sign":  "此致\n敬礼\n张三",
}

func expand(key string) {
    text, ok := snippets[key]
    if !ok {
        return
    }
    // 删除已输入的缩写(按退格 len(key) 次)
    for range key {
        robotgo.KeyTap("backspace")
    }
    // 通过剪贴板粘贴展开后的文本
    robotgo.WriteAll(text)
    robotgo.MilliSleep(50)
    robotgo.KeyTap("v", "ctrl")
}

9.6 平台依赖与注意事项

9.6.1 Linux 需要 xsel / xclip

在 Linux(X11)上,RobotGo 的剪贴板功能依赖外部命令 xselxclip。如果未安装,WriteAll / ReadAll 会返回错误。安装方式:

# Ubuntu / Debian
sudo apt install xsel xclip

# Fedora
sudo dnf install xsel xclip

9.6.2 跨平台粘贴键

粘贴快捷键在不同系统不同:

import "runtime"

func pasteKey() string {
    if runtime.GOOS == "darwin" {
        return "cmd"
    }
    return "ctrl"
}

// 使用
robotgo.KeyTap("v", pasteKey())

9.6.3 时序问题

剪贴板的写入、系统粘贴、应用读取之间存在异步性。在 WriteAll 之后、KeyTap("v", ...) 之前,以及 KeyTap("c", ...) 之后、ReadAll 之前,加入适当的 MilliSleep(通常 50~150ms)能显著提升稳定性,避免“粘贴出旧内容”或“读到空值”。

9.6.4 仅支持文本

RobotGo 主库的 WriteAll / ReadAll 面向纯文本。如果需要处理图片、富文本等其他剪贴板格式,需要借助平台特定的方案或其他库,这超出了 RobotGo 主库的范围。

9.7 实战技巧小结

  1. 长文本走粘贴:大段文本一律用 WriteAll + 粘贴,不要用 Type 逐字打。
  2. 读不到就复制:读不到控件文本时,用“全选 + 复制 + ReadAll”的组合。
  3. 善待用户剪贴板:需要时备份并恢复用户原有的剪贴板内容。
  4. 加延时:剪贴板相关操作前后加 MilliSleep 保证时序稳定。
  5. 检查错误:始终检查 WriteAll / ReadAll 返回的 error,尤其在 Linux 上。
  6. 装好依赖:Linux 上务必安装 xsel / xclip

9.8 小结

本章我们学习了 RobotGo 的剪贴板操作:用 WriteAll / ReadAll 读写文本,并掌握了三种高级用法——用剪贴板快速输入大段文本、用剪贴板读取界面内容、备份与恢复用户剪贴板。我们还做了一个文本扩展小工具的示例,并讨论了 Linux 依赖、跨平台粘贴键、时序问题等注意事项。下一章我们将进入进程与窗口管理,让自动化程序能够定位、激活和操作特定的应用程序窗口。