English | 简体中文 | 繁體中文 | 日本語 | 한국어 | Français | Deutsch | Español | Русский | Português
Golang Desktop-Automatisierung, automatisiertes Testen und KI-gestützte Computer-Bedienung (Computer Use).
Steuerung von Maus und Tastatur, Auslesen des Bildschirms, Prozesse, Fensterhandles, Bilder und Bitmaps sowie globales Event-Listening.
RobotGo unterstützt Mac, Windows und Linux; außerdem unterstützt RobotGo arm64 und x86-amd64.
Ich entwickle jetzt Codg, ein einfach zu bedienendes KI-Agentensystem zum Programmieren und Arbeiten: automatisch, asynchron, nebenläufig, effizient und mit hoher Genauigkeit.
RobotGo-Pro bietet die JavaScript-, Python-, Lua- und weitere Versionen, technischen Support, neue Funktionen und die neueste robotgo-Version („derzeit keine Open-Source-Version“).
- Dokumentation
- Spenden
- Bindings
- Voraussetzungen
- Cgo-freie Builds
- Installation
- Aktualisierung
- Beispiele
- Typkonvertierung und Tasten
- Cross-Compiling
- Autoren
- Pläne
- Lizenz
- GoDoc
- API-Dokumentation (Veraltet, nicht aktualisiert)
Spender, Sponsoren und andere, Kontakt: vzvway@gmail.com
ADB, kapselt Android adb und iOS WDA, mit robotgo-kompatibler API.
Go 1.26+ (siehe go.mod) und ein Backend:
- Standard (Cgo):
CGO_ENABLED=1, ein C-Compiler und die unten genannten Plattformbibliotheken. - Reines Go (getestet): keine C-Toolchain; siehe Cgo-freie Builds.
Beide benötigen die funktionsspezifischen Abhängigkeiten für die jeweils genutzten Funktionen.
Go und die Xcode Command Line Tools (Clang):
brew install go
xcode-select --installBerechtigungen (Cgo und reines Go): unter Systemeinstellungen > Datenschutz & Sicherheit der App oder dem Terminal Bedienungshilfen (Eingabe) und Bildschirmaufnahme (Erfassung) erteilen.
winget install GoLang.GoDazu eine C-Toolchain. LLVM-MinGW:
winget install MartinStorsjo.LLVM-MinGW.UCRT
$env:CC = "clang"Oder MinGW-w64 (WinLibs):
winget install BrechtSanders.WinLibs.POSIX.UCRT
$env:CC = "gcc"Das bin-Verzeichnis der Toolchain (z. B. C:\mingw64\bin) muss in PATH
liegen und zu GOARCH passen. Jeder andere Cgo-kompatible Compiler, etwa ein
manuell installiertes MinGW-w64,
funktioniert ebenfalls.
Bitmap liefert libpng nur für MinGW-w64 mit; mit einer anderen Toolchain muss libpng selbst gebaut werden.
Build: GCC, libc-Header, X11/XTest-Header. Laufzeit: ein X-Server mit XTEST und
gesetztem DISPLAY. Für natives Wayland siehe Cgo-freie Builds.
Ubuntu / Debian:
# Go (Snap, falls das Distributionspaket zu alt ist)
sudo snap install go --classic
# oder: sudo apt install golang
# Kern (Cgo): Compiler, libc, X11, XTest
sudo apt install gcc libc6-dev libx11-dev xorg-dev libxtst-dev
# Zwischenablage (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:
# Kern (Cgo): Compiler, libc, X11, XTest
sudo dnf install gcc glibc-devel libX11-devel libXtst-devel
# Zwischenablage (X11)
sudo dnf install xsel xclip
# Bitmap: libpng
sudo dnf install libpng-devel
# GoHook: XKB (Fedora < 34: xorg-x11-xkb-utils-devel statt xkbcomp-devel)
sudo dnf install libxkbcommon-devel libxkbcommon-x11-devel xkbcomp-develZusätzlich zur Grundinstallation, nur für die genutzten Funktionen nötig:
-
Linux-Zwischenablage (Cgo und reines Go):
xclipoderxselunter X11,wl-clipboardunter Wayland:sudo apt install wl-clipboard # Ubuntu / Debian sudo dnf install wl-clipboard # Fedora
-
Bitmap: libpng-Header.
-
GoHook: XCB/XKB-Header unter Linux.
Bitmap und GoHook sind eigene Cgo-Pakete; ein reines Go-Backend von RobotGo hebt deren C-Anforderungen nicht auf.
Getestete reine Go-Backends bauen und cross-kompilieren mit
CGO_ENABLED=0 (ohne GCC, MinGW, Xcode oder X11-Header). Gleicher Importpfad und
gleiche API; ein Build-Tag wählt das Backend — CGO_ENABLED=0 allein wählt
nichts aus.
Ziel-GOOS |
Build-Tag | Paket | Laufzeitanforderungen |
|---|---|---|---|
windows |
win |
win | nur Win32, keine zusätzliche Laufzeit |
darwin |
mac |
darwin | System-Frameworks und Datenschutzberechtigungen |
linux |
x11 |
x11 | X-Server mit XTEST, DISPLAY gesetzt |
linux |
wayland |
wayland | wlroots-Compositor, siehe Wayland |
linux |
libei |
libei | RemoteDesktop-Portal (GNOME/KDE), siehe libei |
purego ist eine Abkürzung: mac unter macOS, win unter Windows,
wayland unter Linux. Mit zusätzlichem x11 oder libei lässt sich das unter
Linux überschreiben (-tags "purego,x11").
Ein Backend-Tag passend zu GOOS verwenden; Kombinationen wie x11,libei
lassen sich nicht kompilieren (purego plus ein Linux-Override ist die einzige
Ausnahme).
# Aktuelles Betriebssystem
CGO_ENABLED=0 go build -tags purego .
# Cross-Kompilierung
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 .
Das Modul-Stammverzeichnis (.) oder das eigene Paket bauen, nicht ./...:
examples/ und einige Unterpakete brauchen Cgo-only-APIs.
Die Laufzeitanforderungen von oben gelten weiterhin. Cgo-only-APIs wie
CaptureScreen / FreeBitmap gibt es nicht; stattdessen CaptureImg nutzen.
Nicht unterstützte Operationen geben ErrNotSupported zurück (oder ein leeres
Ergebnis).
mac: keine Fensterverwaltung —ActiveNamegibtErrNotSupportedzurück,GetTitlegibt""zurück, Minimieren/Maximieren/Schließen sind No-Ops.wayland,libei: Wayland hat kein Protokoll für die globale Cursorposition.Location()liest den echten Cursor unter Hyprland (IPC-Socket) und KDE Plasma (KWin-Skript über D-Bus), sofern diese Abfrage gelingt;waylandverlangt zudem, dass alle Ausgaben dasselbe Skalierungsverhältnis haben (unterschiedlich skalierte oder gedrehte Ausgaben fallen zurück). Andernfalls und anderswo (GNOME, Sway, andere wlroots-Compositoren) gibt es die letzte von RobotGo injizierte Position zurück, nicht den physischen Cursor. Die Zwischenablage brauchtwl-clipboard.
Ein wlroots-Compositor (Sway, Hyprland, Wayfire, ...) mit gesetztem
WAYLAND_DISPLAY und XDG_RUNTIME_DIR, der Folgendes bereitstellt:
| Funktion | Protokoll-Global |
|---|---|
| Maussteuerung | zwlr_virtual_pointer_manager_v1 |
| Tastatursteuerung | zwp_virtual_keyboard_manager_v1 |
| Bildschirmaufnahme | zwlr_screencopy_manager_v1 |
| Fensterverwaltung | zwlr_foreign_toplevel_manager_v1 |
GNOME und KDE stellen diese Protokolle nicht bereit; dort libei verwenden.
Eingaben laufen über die RemoteDesktop-D-Bus-Schnittstelle von
xdg-desktop-portal: nötig sind ein Session-Bus, xdg-desktop-portal und ein
Backend, das sie implementiert (xdg-desktop-portal-gnome, -kde oder -wlr).
Beim ersten Start erscheint ein Zustimmungsdialog; das Restore-Token wird unter
$XDG_STATE_HOME/robotgo zwischengespeichert.
Absolute Bewegungen nutzen einen verknüpften ScreenCast-Stream (Standard); mit
libei.LinkScreenCast = false gibt es nur relative Bewegungen.
Bildschirmaufnahme und Fensterverwaltung melden ErrNotSupported.
go get github.com/go-vgo/robotgoimport "github.com/go-vgo/robotgo"png.h: No such file or directory mit Bitmap: siehe dessen libpng-Anforderungen
und issues/47.
go get -u github.com/go-vgo/robotgoBeachten Sie das Problem mit dem Kompilierungs-Cache für C-Dateien in go1.10.x, golang #24355.
go mod vendor-Problem, 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")
// Rückgabefehler prüfen, ungültige Argumente liefern einen Fehler
if err := robotgo.ScrollDir(10, "forward"); err != nil {
fmt.Println("robotgo.ScrollDir error:", err)
}
// Backends unterscheiden sich: Cgo liefert einen Fehler, Pure Go macht einen einfachen Linksklick und liefert nil
if err := robotgo.Click("left", "double"); err != nil {
fmt.Println("robotgo.Click error:", err)
}
// MoveSmoothRelative meldet eine fehlgeschlagene sanfte Bewegung als ErrSmoothMove
err := robotgo.MoveSmoothRelative(10, -10)
if errors.Is(err, robotgo.ErrSmoothMove) {
fmt.Println("smooth move failed:", err)
}
// Pure-Go-Backends liefern ErrNotSupported für nicht unterstützte Operationen
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)
}
// Unbekannte Tastennamen liefern einen Fehler, statt eine falsche Taste zu drücken
if err := robotgo.KeyTap("notakey"); err != nil {
fmt.Println("robotgo.KeyTap error:", err)
}
// TypeStr liefert den ersten Tippfehler, Type nur die Anzahl
if err := robotgo.TypeStr("Hello, 世界"); err != nil {
fmt.Println("robotgo.TypeStr error:", err)
}
// Modifikator halten, dann immer loslassen und beide Fehler prüfen
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)
}- Bessere Multiscreen-Unterstützung
- Fensterhandle aktualisieren
- Die vollständige Liste der Mitwirkenden finden Sie auf der Mitwirkenden-Seite.
- Siehe Beitragsrichtlinien.
Robotgo wird primär unter den Bedingungen „der Apache-Lizenz (Version 2.0)“ vertrieben, wobei Teile von verschiedenen BSD-ähnlichen Lizenzen abgedeckt sind.
Siehe LICENSE-APACHE, LICENSE.