feat: robotgo improvements in phone focus bluetooth and printer scripts

This commit is contained in:
Krzysztof kuhy Rudnicki 2026-03-09 18:34:15 +01:00
parent 1d3e9750e7
commit 87864ae615
6 changed files with 332 additions and 0 deletions

View File

@ -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
```

1
robotgo_demo/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
robotgo_demo

31
robotgo_demo/README.md Normal file
View File

@ -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

32
robotgo_demo/go.mod Normal file
View File

@ -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
)

73
robotgo_demo/go.sum Normal file
View File

@ -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=

52
robotgo_demo/main.go Normal file
View File

@ -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!")
}