diff --git a/robotgo_demo/.github/copilot-instructions.md b/robotgo_demo/.github/copilot-instructions.md new file mode 100644 index 0000000..7231d88 --- /dev/null +++ b/robotgo_demo/.github/copilot-instructions.md @@ -0,0 +1,143 @@ +# Copilot Instructions for robotgo_demo + +## Overview + +`robotgo_demo/` is a Go project using [go-vgo/robotgo](https://github.com/go-vgo/robotgo) for desktop automation on **Arch Linux, X11, i3 window manager**. Robotgo provides cross-platform control of mouse, keyboard, screen, clipboard, and window management. + +## System Requirements (Arch Linux / X11) + +All dependencies must be installed before building: + +```bash +sudo pacman -S --needed gcc go libxtst libx11 libxkbcommon libxkbcommon-x11 \ + libpng xsel xclip libxcb +``` + +These provide: + +- **GCC + Go** — compiler toolchain (robotgo uses cgo) +- **libxtst, libx11, libxcb** — X11 display and XTest extension +- **libxkbcommon, libxkbcommon-x11** — keyboard hook support (gohook) +- **libpng** — bitmap/screenshot capture +- **xsel, xclip** — clipboard read/write + +## Build & Run + +```bash +cd robotgo_demo +go build -o robotgo_demo . +./robotgo_demo +``` + +To update the dependency: + +```bash +go get -u github.com/go-vgo/robotgo +go mod tidy +``` + +## Robotgo API Quick Reference + +Use `import "github.com/go-vgo/robotgo"` in Go files. Key APIs: + +### Mouse + +```go +robotgo.Move(x, y) // instant move +robotgo.MoveSmooth(x, y) // human-like smooth move +robotgo.Click("left") // click (left/right/center) +robotgo.DragSmooth(x, y) // drag to position +robotgo.ScrollDir(n, "up") // scroll direction +x, y := robotgo.Location() // current mouse position +``` + +### Keyboard + +```go +robotgo.Type("text") // type a string +robotgo.KeyTap("enter") // tap a single key +robotgo.KeyTap("a", "ctrl") // key combo (ctrl+a) +robotgo.KeyToggle("shift") // hold key down +robotgo.KeyToggle("shift", "up") // release key +``` + +### Screen + +```go +sx, sy := robotgo.GetScreenSize() // screen dimensions +color := robotgo.GetPixelColor(x, y) // hex color at pixel +bit := robotgo.CaptureScreen(x, y, w, h) // capture region +defer robotgo.FreeBitmap(bit) // always free bitmaps +img := robotgo.ToImage(bit) // convert to Go image +``` + +### Clipboard + +```go +robotgo.WriteAll("text") // write to clipboard +text, err := robotgo.ReadAll() // read from clipboard +``` + +### Window + +```go +title := robotgo.GetTitle() // active window title +pids, err := robotgo.FindIds("firefox") // find PIDs by name +robotgo.ActivePid(pid) // focus window by PID +robotgo.ActiveName("firefox") // focus window by name +``` + +### Event Hooks (via gohook) + +```go +import hook "github.com/robotn/gohook" + +hook.Register(hook.KeyDown, []string{"q", "ctrl"}, func(e hook.Event) { + hook.End() +}) +s := hook.Start() +<-hook.Process(s) +``` + +### Timing + +```go +robotgo.Sleep(1) // sleep 1 second +robotgo.MilliSleep(500) // sleep 500ms +robotgo.MouseSleep = 300 // default delay between mouse ops +robotgo.KeySleep = 100 // default delay between key ops +``` + +## Key Docs & Links + +- [Full API docs](https://github.com/go-vgo/robotgo/blob/master/docs/doc.md) +- [Key name reference](https://github.com/go-vgo/robotgo/blob/master/docs/keys.md) +- [Examples](https://github.com/go-vgo/robotgo/blob/master/examples) +- [GoDoc](https://pkg.go.dev/github.com/go-vgo/robotgo) + +## Conventions + +- Always `defer robotgo.FreeBitmap(bit)` after `CaptureScreen` to avoid memory leaks. +- Use `MoveSmooth` over `Move` when simulating human interaction. +- Add `time.Sleep` or `robotgo.MilliSleep` before typing to give the user time to focus the target window. +- Robotgo operates on X11 only — this project does **not** support Wayland. +- The compiled binary is git-ignored; always build from source. + +## Gotchas + +- **cgo required**: robotgo uses C bindings. `CGO_ENABLED=1` must be set (it's the default on native builds). +- **X11 only**: will not work under Wayland. Ensure `$DISPLAY` is set. +- **Root not needed**: runs as a regular user with X11 access. +- **Bitmap capture** may fail if no X display is available (e.g., headless/SSH without X forwarding). +- **`png.h: No such file or directory`**: install `libpng` (`sudo pacman -S libpng`). + +## Project Structure + +``` +robotgo_demo/ +├── .gitignore # ignores compiled binary +├── go.mod # Go module (robotgo_demo) +├── go.sum # dependency checksums +├── main.go # demo: mouse, keyboard, screen, clipboard, window +└── README.md # user-facing docs +``` diff --git a/robotgo_demo/.gitignore b/robotgo_demo/.gitignore new file mode 100644 index 0000000..0445040 --- /dev/null +++ b/robotgo_demo/.gitignore @@ -0,0 +1 @@ +robotgo_demo diff --git a/robotgo_demo/README.md b/robotgo_demo/README.md new file mode 100644 index 0000000..9ffaf00 --- /dev/null +++ b/robotgo_demo/README.md @@ -0,0 +1,31 @@ +# robotgo_demo + +A simple demo of [go-vgo/robotgo](https://github.com/go-vgo/robotgo) — desktop +automation for Go (mouse, keyboard, screen, clipboard, window management). + +## Requirements (Arch Linux, X11) + +```bash +sudo pacman -S --needed gcc go libxtst libx11 libxkbcommon libxkbcommon-x11 \ + libpng xsel xclip libxcb +``` + +## Build & Run + +```bash +cd robotgo_demo +go build -o robotgo_demo . +./robotgo_demo +``` + +**Note:** The program types text after a 2-second delay — focus a text editor +before running. + +## What it does + +1. Prints screen resolution +2. Reads and moves the mouse to screen center +3. Reads the pixel color at center +4. Writes/reads the clipboard +5. Types "Hello World!" into the focused window +6. Prints the active window title diff --git a/robotgo_demo/go.mod b/robotgo_demo/go.mod new file mode 100644 index 0000000..8d3fdec --- /dev/null +++ b/robotgo_demo/go.mod @@ -0,0 +1,32 @@ +module robotgo_demo + +go 1.26.1 + +require github.com/go-vgo/robotgo v1.0.1 + +require ( + github.com/dblohm7/wingoes v0.0.0-20250822163801-6d8e6105c62d // indirect + github.com/ebitengine/purego v0.9.1 // indirect + github.com/gen2brain/shm v0.1.1 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/godbus/dbus/v5 v5.2.0 // indirect + github.com/jezek/xgb v1.2.0 // indirect + github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect + github.com/otiai10/gosseract/v2 v2.4.1 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect + github.com/robotn/xgb v0.10.0 // indirect + github.com/robotn/xgbutil v0.10.0 // indirect + github.com/shirou/gopsutil/v4 v4.25.10 // indirect + github.com/tailscale/win v0.0.0-20250627215312-f4da2b8ee071 // indirect + github.com/tklauser/go-sysconf v0.3.16 // indirect + github.com/tklauser/numcpus v0.11.0 // indirect + github.com/vcaesar/gops v0.41.0 // indirect + github.com/vcaesar/imgo v0.41.0 // indirect + github.com/vcaesar/keycode v0.10.1 // indirect + github.com/vcaesar/screenshot v0.11.1 // indirect + github.com/vcaesar/tt v0.20.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 // indirect + golang.org/x/image v0.33.0 // indirect + golang.org/x/sys v0.38.0 // indirect +) diff --git a/robotgo_demo/go.sum b/robotgo_demo/go.sum new file mode 100644 index 0000000..db26e79 --- /dev/null +++ b/robotgo_demo/go.sum @@ -0,0 +1,73 @@ +github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ= +github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dblohm7/wingoes v0.0.0-20250822163801-6d8e6105c62d h1:QRKpU+9ZBDs62LyBfwhZkJdB5DJX2Sm3p4kUh7l1aA0= +github.com/dblohm7/wingoes v0.0.0-20250822163801-6d8e6105c62d/go.mod h1:SUxUaAK/0UG5lYyZR1L1nC4AaYYvSSYTWQSH3FPcxKU= +github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A= +github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/gen2brain/shm v0.1.1 h1:1cTVA5qcsUFixnDHl14TmRoxgfWEEZlTezpUj1vm5uQ= +github.com/gen2brain/shm v0.1.1/go.mod h1:UgIcVtvmOu+aCJpqJX7GOtiN7X2ct+TKLg4RTxwPIUA= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-vgo/robotgo v1.0.1 h1:4dS+dXSMPRt+VmvG4QZPlH9BNG9Jfywq4q0YjSiFN0A= +github.com/go-vgo/robotgo v1.0.1/go.mod h1:NcSL/tqNqkpWJ3rmT6YSDUVhQKZwyRsaanDMO4qkT5I= +github.com/godbus/dbus/v5 v5.2.0 h1:3WexO+U+yg9T70v9FdHr9kCxYlazaAXUhx2VMkbfax8= +github.com/godbus/dbus/v5 v5.2.0/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/jezek/xgb v1.2.0 h1:LzgkD11wOrPnxXEqo588cnjUt4NwMHrFh/tgajo50Q0= +github.com/jezek/xgb v1.2.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= +github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k= +github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/otiai10/gosseract/v2 v2.4.1 h1:G8AyBpXEeSlcq8TI85LH/pM5SXk8Djy2GEXisgyblRw= +github.com/otiai10/gosseract/v2 v2.4.1/go.mod h1:1gNWP4Hgr2o7yqWfs6r5bZxAatjOIdqWxJLWsTsembk= +github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs= +github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ= +github.com/robotn/xgb v0.10.0 h1:O3kFbIwtwZ3pgLbp1h5slCQ4OpY8BdwugJLrUe6GPIM= +github.com/robotn/xgb v0.10.0/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ= +github.com/robotn/xgbutil v0.10.0 h1:gvf7mGQqCWQ68aHRtCxgdewRk+/KAJui6l3MJQQRCKw= +github.com/robotn/xgbutil v0.10.0/go.mod h1:svkDXUDQjUiWzLrA0OZgHc4lbOts3C+uRfP6/yjwYnU= +github.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA= +github.com/shirou/gopsutil/v4 v4.25.10/go.mod h1:+kSwyC8DRUD9XXEHCAFjK+0nuArFJM0lva+StQAcskM= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tailscale/win v0.0.0-20250627215312-f4da2b8ee071 h1:qo7kOhoN5DHioXNlFytBzIoA5glW6lsb8YqV0lP3IyE= +github.com/tailscale/win v0.0.0-20250627215312-f4da2b8ee071/go.mod h1:aMd4yDHLjbOuYP6fMxj1d9ACDQlSWwYztcpybGHCQc8= +github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA= +github.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk= +github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= +github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= +github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= +github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= +github.com/vcaesar/gops v0.41.0 h1:FG748Jyw3FOuZnbzSgB+CQSx2e5LbLCPWV2JU1brFdc= +github.com/vcaesar/gops v0.41.0/go.mod h1:/3048L7Rj7QjQKTSB+kKc7hDm63YhTWy5QJ10TCP37A= +github.com/vcaesar/imgo v0.41.0 h1:kNLYGrThXhB9Dd6IwFmfPnxq9P6yat2g7dpPjr7OWO8= +github.com/vcaesar/imgo v0.41.0/go.mod h1:/LGOge8etlzaVu/7l+UfhJxR6QqaoX5yeuzGIMfWb4I= +github.com/vcaesar/keycode v0.10.1 h1:0DesGmMAPWpYTCYddOFiCMKCDKgNnwiQa2QXindVUHw= +github.com/vcaesar/keycode v0.10.1/go.mod h1:JNlY7xbKsh+LAGfY2j4M3znVrGEm5W1R8s/Uv6BJcfQ= +github.com/vcaesar/screenshot v0.11.1 h1:GgPuN89XC4Yh38dLx4quPlSo3YiWWhwIria/j3LtrqU= +github.com/vcaesar/screenshot v0.11.1/go.mod h1:gJNwHBiP1v1v7i8TQ4yV1XJtcyn2I/OJL7OziVQkwjs= +github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4= +github.com/vcaesar/tt v0.20.1/go.mod h1:cH2+AwGAJm19Wa6xvEa+0r+sXDJBT0QgNQey6mwqLeU= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY= +golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= +golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ= +golang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/robotgo_demo/main.go b/robotgo_demo/main.go new file mode 100644 index 0000000..0c28513 --- /dev/null +++ b/robotgo_demo/main.go @@ -0,0 +1,52 @@ +// Package main demonstrates basic robotgo capabilities: +// mouse control, keyboard typing, screen info, and clipboard. +package main + +import ( + "fmt" + "time" + + "github.com/go-vgo/robotgo" +) + +func main() { + // --- Screen info --- + sx, sy := robotgo.GetScreenSize() + fmt.Printf("Screen size: %d x %d\n", sx, sy) + + // --- Mouse: read position, move, click --- + x, y := robotgo.Location() + fmt.Printf("Current mouse position: (%d, %d)\n", x, y) + + targetX, targetY := sx/2, sy/2 + fmt.Printf("Moving mouse to center (%d, %d)...\n", targetX, targetY) + robotgo.MoveSmooth(targetX, targetY) + time.Sleep(500 * time.Millisecond) + + nx, ny := robotgo.Location() + fmt.Printf("Mouse is now at: (%d, %d)\n", nx, ny) + + // --- Pixel color at center --- + color := robotgo.GetPixelColor(targetX, targetY) + fmt.Printf("Pixel color at center: #%s\n", color) + + // --- Clipboard --- + robotgo.WriteAll("Hello from robotgo!") + text, err := robotgo.ReadAll() + if err != nil { + fmt.Println("Clipboard read error:", err) + } else { + fmt.Printf("Clipboard contents: %q\n", text) + } + + // --- Keyboard: type into the currently focused window --- + fmt.Println("Typing 'Hello World!' in 2 seconds (focus a text editor)...") + time.Sleep(2 * time.Second) + robotgo.Type("Hello World!") + + // --- Window: get active window title --- + title := robotgo.GetTitle() + fmt.Printf("Active window title: %q\n", title) + + fmt.Println("Done!") +}