English | 简体中文 | 繁體中文 | 日本語 | 한국어 | Français | Deutsch | Español | Русский | Português
Automação de desktop em Golang, testes automatizados e uso de computador por IA (AI Computer Use).
Controle o mouse e o teclado, leia a tela, processos, identificadores de janela (Window Handle), imagens e bitmaps, e o ouvinte global de eventos.
O RobotGo é compatível com Mac, Windows e Linux; e o robotgo também suporta arm64 e x86-amd64.
Estou construindo o Codg agora, um sistema de agentes de IA fácil de programar e usar: automático, assíncrono, concorrente, eficiente e de alta precisão.
O RobotGo-Pro oferece versões em JavaScript, Python, Lua e outras linguagens, suporte técnico, novos recursos e a versão mais recente do robotgo ("sem versão open-source no momento").
- Documentação
- Doar
- Binding
- Requisitos
- Builds sem Cgo
- Instalação
- Atualização
- Exemplos
- Conversão de tipos e teclas
- Compilação cruzada
- Autores
- Planos
- Licença
- GoDoc
- Documentação da API (Obsoleta, sem atualizações)
Doadores, patrocinadores ou outros, contato: vzvway@gmail.com
ADB, encapsulamento do adb do Android e do WDA do iOS, com API compatível com o robotgo.
Go 1.26+ (veja go.mod) e um backend:
- Padrão (Cgo):
CGO_ENABLED=1, um compilador C e as bibliotecas da plataforma listadas abaixo. - Go puro (experimental): sem toolchain C; veja Builds sem Cgo.
Ambos precisam das dependências por recurso dos recursos que você usar.
Go e as Xcode Command Line Tools (Clang):
brew install go
xcode-select --installPermissões (Cgo e Go puro): em Ajustes do Sistema > Privacidade e Segurança, conceda ao app ou ao terminal Acessibilidade (entrada) e Gravação de Tela (captura).
winget install GoLang.GoMais uma toolchain C. LLVM-MinGW:
winget install MartinStorsjo.LLVM-MinGW.UCRT
$env:CC = "clang"winget install BrechtSanders.WinLibs.POSIX.UCRT
$env:CC = "gcc"O diretório bin da toolchain (por exemplo, C:\mingw64\bin) precisa estar no
PATH e corresponder ao GOARCH. Qualquer outro compilador compatível com Cgo
também funciona, como uma instalação manual do
MinGW-w64.
O Bitmap inclui a libpng apenas para MinGW-w64; com outra toolchain, compile a libpng por conta própria.
Build: GCC, cabeçalhos da libc e cabeçalhos X11/XTest. Execução: um servidor X
com XTEST e DISPLAY definido. Para Wayland nativo, veja
Builds sem Cgo.
Ubuntu / Debian:
# Go (Snap, se o pacote da distribuição for muito antigo)
sudo snap install go --classic
# ou: sudo apt install golang
# Base (Cgo): compilador, libc, X11, XTest
sudo apt install gcc libc6-dev libx11-dev xorg-dev libxtst-dev
# Área de transferência (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-devFedora:
# Base (Cgo): compilador, libc, X11, XTest
sudo dnf install gcc glibc-devel libX11-devel libXtst-devel
# Área de transferência (X11)
sudo dnf install xsel xclip
# Bitmap: libpng
sudo dnf install libpng-devel
# GoHook: XKB (Fedora < 34: xorg-x11-xkb-utils-devel em vez de xkbcomp-devel)
sudo dnf install libxkbcommon-devel libxkbcommon-x11-devel xkbcomp-develNecessárias além da configuração base, apenas para os recursos que você usar:
-
Área de transferência no Linux (Cgo e Go puro):
xclipouxselno X11;wl-clipboardno Wayland:sudo apt install wl-clipboard # Ubuntu / Debian sudo dnf install wl-clipboard # Fedora
-
Bitmap: cabeçalhos da libpng.
-
GoHook: cabeçalhos XCB/XKB no Linux.
Bitmap e GoHook são pacotes Cgo separados; um backend do RobotGo em Go puro não elimina os requisitos de C deles.
Os backends experimentais em Go puro compilam e fazem compilação cruzada com
CGO_ENABLED=0 (sem GCC, MinGW, Xcode ou cabeçalhos X11). Mesmo caminho de
importação e mesma API; uma tag de build seleciona o backend —
CGO_ENABLED=0 sozinho não seleciona nada.
GOOS de destino |
Tag de build | Pacote | Requisitos de execução |
|---|---|---|---|
windows |
win |
win | Apenas Win32, sem runtime extra |
darwin |
mac |
darwin | Frameworks do sistema e permissões de privacidade |
linux |
x11 |
x11 | Servidor X com XTEST, DISPLAY definido |
linux |
wayland |
wayland | Compositor wlroots, veja Wayland |
linux |
libei |
libei | Portal RemoteDesktop (GNOME/KDE), veja libei |
purego é um atalho: mac no macOS, win no Windows, wayland no Linux.
Adicione x11 ou libei para substituir no Linux (-tags "purego,x11").
Use uma única tag de backend correspondente ao GOOS; combinações como
x11,libei não compilam (purego mais uma substituição no Linux é a única
exceção).
# Sistema operacional atual
CGO_ENABLED=0 go build -tags purego .
# Compilação cruzada
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 .
Compile a raiz do módulo (.) ou o seu próprio pacote, não ./...: examples/
e alguns subpacotes precisam de APIs exclusivas do Cgo.
Os requisitos de execução acima continuam valendo. APIs exclusivas do Cgo, como
CaptureScreen / FreeBitmap, não existem; use CaptureImg. Operações sem
suporte retornam ErrNotSupported (ou um resultado vazio).
mac: sem gerenciamento de janelas —ActiveNameretornaErrNotSupported,GetTitleretorna""e minimizar/maximizar/fechar não fazem nada.wayland,libei:Location()retorna a última posição injetada pelo RobotGo, não a do cursor físico. A área de transferência precisa dowl-clipboard.
Um compositor wlroots (Sway, Hyprland, Wayfire, ...) com WAYLAND_DISPLAY e
XDG_RUNTIME_DIR definidos, expondo:
| Recurso | Global do protocolo |
|---|---|
| Controle do mouse | zwlr_virtual_pointer_manager_v1 |
| Controle do teclado | zwp_virtual_keyboard_manager_v1 |
| Captura de tela | zwlr_screencopy_manager_v1 |
| Gerenciamento de janelas | zwlr_foreign_toplevel_manager_v1 |
GNOME e KDE não fornecem esses protocolos; neles, use libei.
A entrada passa pela interface D-Bus RemoteDesktop do xdg-desktop-portal:
precisa de um barramento de sessão, do xdg-desktop-portal e de um backend que
o implemente (xdg-desktop-portal-gnome, -kde ou -wlr). A primeira execução
exibe um diálogo de consentimento; o token de restauração fica em cache em
$XDG_STATE_HOME/robotgo.
O movimento absoluto usa um stream ScreenCast vinculado (padrão); defina
libei.LinkScreenCast = false para apenas movimento relativo. Captura de tela e
gerenciamento de janelas retornam ErrNotSupported.
go get github.com/go-vgo/robotgoimport "github.com/go-vgo/robotgo"png.h: No such file or directory com o Bitmap: veja os requisitos de libpng
dele e issues/47.
go get -u github.com/go-vgo/robotgoObserve o problema de cache de compilação de arquivos C no go1.10.x, golang #24355.
Problema com go mod vendor, golang #26366.
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")
// Verifique os erros retornados, argumentos inválidos retornam um erro
if err := robotgo.ScrollDir(10, "forward"); err != nil {
fmt.Println("robotgo.ScrollDir error:", err)
}
// Depende do backend: Cgo retorna um erro, Go puro faz um clique esquerdo simples e retorna nil
if err := robotgo.Click("left", "double"); err != nil {
fmt.Println("robotgo.Click error:", err)
}
// MoveSmoothRelative informa um movimento suave com falha como ErrSmoothMove
err := robotgo.MoveSmoothRelative(10, -10)
if errors.Is(err, robotgo.ErrSmoothMove) {
fmt.Println("smooth move failed:", err)
}
// Os backends em Go puro retornam ErrNotSupported para operações não suportadas
err = robotgo.Move(100, 200)
if errors.Is(err, robotgo.ErrNotSupported) {
fmt.Println("robotgo.Move is not supported by this backend")
}
}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)
}
// Nomes de tecla desconhecidos retornam um erro em vez de pressionar a tecla errada
if err := robotgo.KeyTap("notakey"); err != nil {
fmt.Println("robotgo.KeyTap error:", err)
}
// TypeStr retorna o primeiro erro de digitação, Type retorna apenas a contagem
if err := robotgo.TypeStr("Hello, 世界"); err != nil {
fmt.Println("robotgo.TypeStr error:", err)
}
// Segure um modificador, depois sempre solte-o e verifique os dois erros
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)
}
}
}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")
}
}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")
}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)
}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")
}
}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)
}- Melhor suporte a múltiplas telas
- Atualizar o Window Handle
- Veja a página de contribuidores para a lista completa de contribuidores.
- Veja as Diretrizes de Contribuição.
O Robotgo é distribuído principalmente sob os termos da "Apache License (Version 2.0)", com partes cobertas por diversas licenças no estilo BSD.
Veja LICENSE-APACHE, LICENSE.