robotgo

go-vgoApache-2.0活跃维护

用 Go 写的跨平台 RPA 与 GUI 自动化库,能控制鼠标键盘、截屏找图、监听事件,适合做桌面自动化和自动化测试。

RobotGo, Go Native cross-platform RPA, GUI automation, Auto test and Computer use @vcaesar

v1.3.7发布于 2026-10-22 20:53 UTC10,902star +1 / 7 天966fork同步于 2026-11-10 17:29 UTC

怎么上手

由 README 提炼,执行前请确认
go get github.com/go-vgo/robotgo
硬件要求按 README 说明

README 未说明显存或 GPU 要求;支持 macOS、Windows、Linux,架构覆盖 arm64 与 x86-amd64。Linux 需 X 服务器并设置 DISPLAY,Wayland 需 wlroots 合成器或 xdg-desktop-portal。

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

Go 原生跨平台桌面自动化库,用代码控制鼠标键盘、读屏和窗口,做 RPA 与自动测试

用 Go 写的跨平台 RPA 与 GUI 自动化库,能控制鼠标键盘、截屏找图、监听事件,适合做桌面自动化和自动化测试。

核心能力

  • 跨平台控制鼠标键盘,支持平滑移动与拖拽
  • 读取屏幕图像与位图,支持截屏处理
  • 监听全局事件,获取窗口句柄与进程信息
  • 提供纯 Go 后端,CGO_ENABLED=0 可交叉编译
  • 支持 Linux Wayland 与 libei 输入注入

容易踩的坑

默认 Cgo 后端需 C 编译器和平台库,Linux 还要装 X11/XTest 头文件;纯 Go 构建必须加 -tags(如 purego/win/mac/x11),只设 CGO_ENABLED=0 不会选中后端;macOS 需手动授予辅助功能与屏幕录制权限,Bitmap 和 GoHook 是独立 Cgo 包仍需 libpng/XCB 头文件

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v1.3.7
  1. v1.3.7最新正式版2026-10-22 · 2026-10-22 20:53 UTC

    What's Changed

    Full Changelog: https://github.com/go-vgo/robotgo/compare/v1.3.6...v1.3.7

  2. v1.3.62026-10-16 · 2026-10-16 20:06 UTC
    查看更新说明

    What's Changed

    Full Changelog: https://github.com/go-vgo/robotgo/compare/v1.3.5...v1.3.6

  3. v1.3.52026-10-07 · 2026-10-07 10:33 UTC
    查看更新说明

    What's Changed

    Full Changelog: https://github.com/go-vgo/robotgo/compare/v1.3.4...v1.3.5

  4. v1.3.42026-10-07 · 2026-10-07 07:55 UTC
    查看更新说明

    What's Changed

    Full Changelog: https://github.com/go-vgo/robotgo/compare/v1.3.3...v1.3.4

  5. v1.3.32026-10-05 · 2026-10-05 19:26 UTC
    查看更新说明

    What's Changed

    Full Changelog: https://github.com/go-vgo/robotgo/compare/v1.3.2...v1.3.3

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    Robotgo

    Build Status CircleCI Status codecov golangci-lint GoDoc GitHub release

    English | 简体中文 | 繁體中文 | 日本語 | 한국어 | Français | Deutsch | Español | Русский | Português

    Golang Desktop Automation, auto test and AI Computer Use. Control the mouse, keyboard, read the screen, process, Window Handle, image and bitmap and global event listener.

    RobotGo supports Mac, Windows, and Linux; and robotgo supports arm64 and x86-amd64.

    I build Codg now, Easy code and work AI agent system: auto, asynchronous, concurrency, efficiently and High accuracy

    RobotGo-Pro get the JavaScript, Python, Lua and others version, tech supports, new features and newest robotgo version ("no open-source version now").

    Contents

    Docs

    Donate

    Donors and sponsors, or others, Contact: [email protected]

    Binding

    ADB, packaging android adb and ios wda, robotgo compatible API.

    Requirements

    Go 1.26+ (see go.mod) and one backend:

    • Default (Cgo): CGO_ENABLED=1, a C compiler and the platform libraries below.
    • Pure Go (tested): no C toolchain; see Cgo-free Builds.

    Both need the feature-specific dependencies for the features you use.

    Default Cgo setup

    macOS

    Go and the Xcode Command Line Tools (Clang):

    brew install go
    xcode-select --install
    

    Permissions (Cgo and pure Go): in System Settings > Privacy & Security, grant the app or terminal Accessibility (input) and Screen Recording (capture).

    Windows
    winget install GoLang.Go
    

    Plus one C toolchain. LLVM-MinGW:

    winget install MartinStorsjo.LLVM-MinGW.UCRT
    $env:CC = "clang"
    

    Or MinGW-w64 (WinLibs):

    winget install BrechtSanders.WinLibs.POSIX.UCRT
    $env:CC = "gcc"
    

    The toolchain's bin (e.g. C:\mingw64\bin) must be on PATH and match GOARCH. Any other Cgo-compatible compiler, such as a manual MinGW-w64 install, also works.

    Bitmap ships libpng for MinGW-w64 only; with another toolchain, build libpng yourself.

    Linux (X11)

    Build: GCC, libc headers, X11/XTest headers. Runtime: an X server with XTEST and DISPLAY set. For native Wayland, see Cgo-free Builds.

    Ubuntu / Debian:

    # Go (Snap if the distro package is too old)
    sudo snap install go --classic
    # or: sudo apt install golang
    
    # Core (Cgo): compiler, libc, X11, XTest
    sudo apt install gcc libc6-dev libx11-dev xorg-dev libxtst-dev
    
    # Clipboard (X11)
    sudo apt install xsel xclip
    
    # Bitmap: libpng
    sudo apt install libpng++-dev
    
    # GoHook: XCB, XKB
    sudo apt install xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev libxkbcommon-dev
    

    Fedora:

    # Core (Cgo): compiler, libc, X11, XTest
    sudo dnf install gcc glibc-devel libX11-devel libXtst-devel
    
    # Clipboard (X11)
    sudo dnf install xsel xclip
    
    # Bitmap: libpng
    sudo dnf install libpng-devel
    
    # GoHook: XKB (Fedora < 34: xorg-x11-xkb-utils-devel instead of xkbcomp-devel)
    sudo dnf install libxkbcommon-devel libxkbcommon-x11-devel xkbcomp-devel
    

    Feature-specific dependencies

    Needed on top of the core setup, only for the features you use:

    • Linux clipboard (Cgo and pure Go): xclip or xsel on X11; wl-clipboard on Wayland:

      sudo apt install wl-clipboard   # Ubuntu / Debian
      sudo dnf install wl-clipboard   # Fedora
      
    • Bitmap: libpng headers.

    • GoHook: XCB/XKB headers on Linux.

    Bitmap and GoHook are separate Cgo packages; a pure-Go RobotGo backend does not remove their C requirements.

    Cgo-free Builds

    Tested pure-Go backends build and cross-compile with CGO_ENABLED=0 (no GCC, MinGW, Xcode or X11 headers). Same import path and API; a build tag selects the backend — CGO_ENABLED=0 alone selects nothing.

    Target GOOSBuild tagPackageRuntime requirements
    windowswinwinWin32 only, no extra runtime
    darwinmacdarwinSystem frameworks and privacy permissions
    linuxx11x11X server with XTEST, DISPLAY set
    linuxwaylandwaylandwlroots compositor, see Wayland
    linuxlibeilibeiRemoteDesktop portal (GNOME/KDE), see libei

    purego is a shortcut: mac on macOS, win on Windows, wayland on Linux. Add x11 or libei to override on Linux (-tags "purego,x11").

    Use one backend tag matching GOOS; combinations such as x11,libei fail to compile (purego plus one Linux override is the only exception).

    Build commands

    # Current OS
    CGO_ENABLED=0 go build -tags purego .
    
    # Cross-compile
    CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -tags win .
    CGO_ENABLED=0 GOOS=darwin  GOARCH=arm64 go build -tags mac .
    CGO_ENABLED=0 GOOS=linux   GOARCH=amd64 go build -tags x11 .
    CGO_ENABLED=0 GOOS=linux   GOARCH=amd64 go build -tags wayland .
    CGO_ENABLED=0 GOOS=linux   GOARCH=amd64 go build -tags libei .
    

    PowerShell: $env:CGO_ENABLED = "0"; go build -tags purego .

    Build the module root (.) or your own package, not ./...: examples/ and some subpackages need Cgo-only APIs.

    Limitations

    The runtime requirements above still apply. Cgo-only APIs such as CaptureScreen / FreeBitmap do not exist; use CaptureImg. Unsupported operations return ErrNotSupported (or an empty result).

    • mac: window management (GetTitle, GetBounds, ActivePid, ActiveName, MinWindow, MaxWindow, CloseWindow) uses Accessibility and needs the Accessibility permission; MaxWindow toggles native full screen and GetClient equals GetBounds.
    • wayland, libei: Wayland has no protocol for the global cursor position. Location() reads the real cursor from Hyprland (IPC socket) and KDE Plasma (KWin script over D-Bus) when that query succeeds; wayland also needs every output to share one scale ratio (differently scaled or rotated outputs fall back). Otherwise, and elsewhere (GNOME, Sway, other wlroots compositors), it returns the last position injected by RobotGo, not the physical cursor. Clipboard needs wl-clipboard.
    Wayland

    A wlroots compositor (Sway, Hyprland, Wayfire, ...) with WAYLAND_DISPLAY and XDG_RUNTIME_DIR set, exposing:

    FeatureProtocol global
    Mouse controlzwlr_virtual_pointer_manager_v1
    Keyboard controlzwp_virtual_keyboard_manager_v1
    Screen capturezwlr_screencopy_manager_v1
    Window managementzwlr_foreign_toplevel_manager_v1

    GNOME and KDE do not provide these protocols; use libei there.

    libei (GNOME / KDE)

    Input goes through the xdg-desktop-portal RemoteDesktop D-Bus interface: needs a session bus, xdg-desktop-portal and a backend implementing it (xdg-desktop-portal-gnome, -kde or -wlr). The first run shows a consent dialog; the restore token is cached under $XDG_STATE_HOME/robotgo.

    Absolute motion uses a linked ScreenCast stream (default); set libei.LinkScreenCast = false for relative motion only. Screen capture and window management report ErrNotSupported.

    Installation

    go get github.com/go-vgo/robotgo
    
    import "github.com/go-vgo/robotgo"
    

    png.h: No such file or directory with Bitmap: see its libpng requirements and issues/47.

    Update

    go get -u github.com/go-vgo/robotgo
    

    Note go1.10.x C file compilation cache problem, golang #24355. go mod vendor problem, golang #26366.

    Examples

    Mouse
    package main
    
    import (
      "errors"
      "fmt"
    
      "github.com/go-vgo/robotgo"
    )
    
    func main() {
      robotgo.MouseSleep = 300
    
      robotgo.Move(100, 100)
      fmt.Println(robotgo.Location())
      robotgo.Move(100, -200) // multi screen supported
      robotgo.MoveSmooth(120, -150)
      fmt.Println(robotgo.Location())
    
      robotgo.ScrollDir(10, "up")
      robotgo.ScrollDir(20, "right")
    
      robotgo.Scroll(0, -10)
      robotgo.Scroll(100, 0)
    
      robotgo.MilliSleep(100)
      robotgo.ScrollSmooth(-10, 6)
      // robotgo.ScrollRelative(10, -100)
    
      robotgo.Move(10, 20)
      robotgo.MoveRelative(0, -10)
      robotgo.DragSmooth(10, 10)
    
      robotgo.Click("wheelRight")
      robotgo.Click("left", true)
      robotgo.MoveSmooth(100, 200, 1.0, 10.0)
    
      robotgo.Toggle("left")
      robotgo.Toggle("left", "up")
    
      // Check the returned errors, invalid arguments return an error
      if err := robotgo.ScrollDir(10, "forward"); err != nil {
        fmt.Println("robotgo.ScrollDir error:", err)
      }
    
      // Backends differ: Cgo returns an error, pure Go does a single left click and returns nil
      if err := robotgo.Click("left", "double"); err != nil {
        fmt.Println("robotgo.Click error:", err)
      }
    
      // MoveSmoothRelative reports a failed smooth move as ErrSmoothMove
      err := robotgo.MoveSmoothRelative(10, -10)
      if errors.Is(err, robotgo.ErrSmoothMove) {
        fmt.Println("smooth move failed:", err)
      }
    
      // Pure-Go backends return ErrNotSupported for unsupported operations
      err = robotgo.Move(100, 200)
      if errors.Is(err, robotgo.ErrNotSupported) {
        fmt.Println("robotgo.Move is not supported by this backend")
      }
    }
    
    Keyboard
    package main
    
    import (
      "errors"
      "fmt"
    
      "github.com/go-vgo/robotgo"
    )
    
    func main() {
      robotgo.Type("Hello World")
      robotgo.Type("だんしゃり", 0, 1)
      // robotgo.Type("テストする")
    
      robotgo.Type("Hi, Seattle space needle, Golden gate bridge, One world trade center.")
      robotgo.Type("Hi galaxy, hi stars, hi MT.Rainier, hi sea. こんにちは世界.")
      robotgo.Sleep(1)
    
      // ustr := uint32(robotgo.CharCodeAt("Test", 0))
      // robotgo.UnicodeType(ustr)
    
      robotgo.KeySleep = 100
      robotgo.KeyTap("enter")
      // robotgo.Type("en")
      robotgo.KeyTap("i", "alt", "cmd")
    
      arr := []string{"alt", "cmd"}
      robotgo.KeyTap("i", arr)
    
      robotgo.MilliSleep(100)
      robotgo.KeyToggle("a")
      robotgo.KeyToggle("a", "up")
    
      robotgo.WriteAll("Test")
      text, err := robotgo.ReadAll()
      if err == nil {
        fmt.Println(text)
      }
    
      // Unknown key names return an error instead of pressing a wrong key
      if err := robotgo.KeyTap("notakey"); err != nil {
        fmt.Println("robotgo.KeyTap error:", err)
      }
    
      // TypeStr returns the first typing error, Type only returns the count
      if err := robotgo.TypeStr("Hello, 世界"); err != nil {
        fmt.Println("robotgo.TypeStr error:", err)
      }
    
      // Hold a modifier, then always release it and check both errors
      if err := robotgo.KeyDown("shift"); err == nil {
        err = errors.Join(robotgo.KeyTap("a"), robotgo.KeyUp("shift"))
        if err != nil {
          fmt.Println("shift + a error:", err)
        }
      }
    }
    
    Screen
    package main
    
    import (
      "fmt"
      "strconv"
    
      "github.com/go-vgo/robotgo"
      "github.com/vcaesar/imgo"
    )
    
    func main() {
      x, y := robotgo.Location()
      fmt.Println("pos: ", x, y)
    
      color := robotgo.GetPixelColor(100, 200)
      fmt.Println("color---- ", color)
    
      sx, sy := robotgo.GetScreenSize()
      fmt.Println("get screen size: ", sx, sy)
    
      bit := robotgo.CaptureScreen(10, 10, 30, 30)
      defer robotgo.FreeBitmap(bit)
    
      img := robotgo.ToImage(bit)
      imgo.Save("test.png", img)
    
      num := robotgo.DisplaysNum()
      for i := 0; i < num; i++ {
        robotgo.DisplayID = i
        img1, _ := robotgo.CaptureImg()
        path1 := "save_" + strconv.Itoa(i)
        robotgo.Save(img1, path1+".png")
        robotgo.SaveJpeg(img1, path1+".jpeg", 50)
    
        img2, _ := robotgo.CaptureImg(10, 10, 20, 20)
        robotgo.Save(img2, "test_"+strconv.Itoa(i)+".png")
    
        x, y, w, h := robotgo.GetDisplayBounds(i)
        img3, err := robotgo.CaptureImg(x, y, w, h)
        fmt.Println("Capture error: ", err)
        robotgo.Save(img3, path1+"_1.png")
      }
    }
    
    Bitmap
    package main
    
    import (
      "fmt"
    
      "github.com/go-vgo/robotgo"
      "github.com/vcaesar/bitmap"
    )
    
    func main() {
      bit := robotgo.CaptureScreen(10, 20, 30, 40)
      // use `defer robotgo.FreeBitmap(bit)` to free the bitmap
      defer robotgo.FreeBitmap(bit)
    
      fmt.Println("bitmap...", bit)
      img := robotgo.ToImage(bit)
      // robotgo.SavePng(img, "test_1.png")
      robotgo.Save(img, "test_1.png")
    
      bit2 := robotgo.ToCBitmap(robotgo.ImgToBitmap(img))
      fx, fy := bitmap.Find(bit2)
      fmt.Println("FindBitmap------ ", fx, fy)
      robotgo.Move(fx, fy)
    
      arr := bitmap.FindAll(bit2)
      fmt.Println("Find all bitmap: ", arr)
    
      fx, fy = bitmap.Find(bit)
      fmt.Println("FindBitmap------ ", fx, fy)
    
      bitmap.Save(bit, "test.png")
    }
    
    OpenCV
    package main
    
    import (
      "fmt"
      "math/rand"
    
      "github.com/go-vgo/robotgo"
      "github.com/vcaesar/gcv"
      "github.com/vcaesar/bitmap"
    )
    
    func main() {
      opencv()
    }
    
    func opencv() {
      name := "test.png"
      name1 := "test_001.png"
      robotgo.SaveCapture(name1, 10, 10, 30, 30)
      robotgo.SaveCapture(name)
    
      fmt.Print("gcv find image: ")
      fmt.Println(gcv.FindImgFile(name1, name))
      fmt.Println(gcv.FindAllImgFile(name1, name))
    
      bit := bitmap.Open(name1)
      defer robotgo.FreeBitmap(bit)
      fmt.Print("find bitmap: ")
      fmt.Println(bitmap.Find(bit))
    
      // bit0 := robotgo.CaptureScreen()
      // img := robotgo.ToImage(bit0)
      // bit1 := robotgo.CaptureScreen(10, 10, 30, 30)
      // img1 := robotgo.ToImage(bit1)
      // defer robotgo.FreeBitmapArr(bit0, bit1)
      img, _ := robotgo.CaptureImg()
      img1, _ := robotgo.CaptureImg(10, 10, 30, 30)
    
      fmt.Print("gcv find image: ")
      fmt.Println(gcv.FindImg(img1, img))
      fmt.Println()
    
      res := gcv.FindAllImg(img1, img)
      fmt.Println(res[0].TopLeft.Y, res[0].Rects.TopLeft.X, res)
      x, y := res[0].TopLeft.X, res[0].TopLeft.Y
      robotgo.Move(x, y-rand.Intn(5))
      robotgo.MilliSleep(100)
      robotgo.Click()
    
      res = gcv.FindAll(img1, img) // use find template and sift
      fmt.Println("find all: ", res)
      res1 := gcv.Find(img1, img)
      fmt.Println("find: ", res1)
    
      img2, _, _ := robotgo.DecodeImg("test_001.png")
      x, y = gcv.FindX(img2, img)
      fmt.Println(x, y)
    }
    
    Event
    package main
    
    import (
      "fmt"
    
      // "github.com/go-vgo/robotgo"
      hook "github.com/robotn/gohook"
    )
    
    func main() {
      add()
      low()
      event()
    }
    
    func add() {
      fmt.Println("--- Please press ctrl + shift + q to stop hook ---")
      hook.Register(hook.KeyDown, []string{"q", "ctrl", "shift"}, func(e hook.Event) {
        fmt.Println("ctrl-shift-q")
        hook.End()
      })
    
      fmt.Println("--- Please press w---")
      hook.Register(hook.KeyDown, []string{"w"}, func(e hook.Event) {
        fmt.Println("w")
      })
    
      s := hook.Start()
      <-hook.Process(s)
    }
    
    func low() {
    	evChan := hook.Start()
    	defer hook.End()
    
    	for ev := range evChan {
    		fmt.Println("hook: ", ev)
    	}
    }
    
    func event() {
      ok := hook.AddEvents("q", "ctrl", "shift")
      if ok {
        fmt.Println("add events...")
      }
    
      keve := hook.AddEvent("k")
      if keve {
        fmt.Println("you press... ", "k")
      }
    
      mleft := hook.AddEvent("mleft")
      if mleft {
        fmt.Println("you press... ", "mouse left button")
      }
    }
    
    Window
    package main
    
    import (
      "fmt"
    
      "github.com/go-vgo/robotgo"
    )
    
    func main() {
      fpid, err := robotgo.FindIds("Google")
      if err == nil {
        fmt.Println("pids... ", fpid)
    
        if len(fpid) > 0 {
          robotgo.Type("Hi galaxy!", fpid[0])
          robotgo.KeyTap("a", fpid[0], "cmd")
    
          robotgo.KeyToggle("a", fpid[0])
          robotgo.KeyToggle("a", fpid[0], "up")
    
          robotgo.ActivePid(fpid[0])
    
          robotgo.Kill(fpid[0])
        }
      }
    
      robotgo.ActiveName("chrome")
    
      isExist, err := robotgo.PidExists(100)
      if err == nil && isExist {
        fmt.Println("pid exists is", isExist)
    
        robotgo.Kill(100)
      }
    
      abool := robotgo.Alert("test", "robotgo")
      if abool {
     	  fmt.Println("ok@@@ ", "ok")
      }
    
      title := robotgo.GetTitle()
      fmt.Println("title@@@ ", title)
    }
    

    Authors

    Plans

    • Better multiscreen support
    • Update Window Handle

    Contributors

    License

    Robotgo is primarily distributed under the terms of "the Apache License (Version 2.0)", with portions covered by various BSD-like licenses.

    See LICENSE-APACHE, LICENSE.