Skip to content

Latest commit

 

History

History
148 lines (127 loc) · 16.6 KB

AGENTS.md

File metadata and controls

148 lines (127 loc) · 16.6 KB

RobotGo

Go native cross-platform desktop automation: mouse, keyboard, screen, bitmap, process, window handle, clipboard, and global event listener. Supports macOS, Windows, Linux; amd64 and arm64.

Module: github.com/go-vgo/robotgo — go.mod declares go 1.26.0 (GitHub Actions sets up Go 1.27.x).

Build/Test/Lint Commands

Prerequisites (default Cgo backend): GCC must be installed. CGO_ENABLED=1 (default). On macOS, Xcode Command Line Tools + Accessibility/Screen Recording permissions. On Linux, X11 + XTest (libx11-dev xorg-dev libxtst-dev). The pure-Go backends (see Architecture) need none of these and build with CGO_ENABLED=0.

  • Build: go build -v .
  • Build all subpackages: go build -v ./...
  • Fetch deps: go get -v -t -d ./...
  • Test (Cgo CI smoke tests — query screen/window state, need a display session): go test -v robot_info_test.go
  • Test (full): go test -v ./... (Linux CI wraps with xvfb-run — see .circleci/config.yml)
  • Single test: go test -v -run TestGetScreenSize .
  • Format: gofmt -w . (code uses tab indentation, standard gofmt style)
  • Vet: go vet ./...
  • Run an example: cd examples/mouse && go run main.go
  • Pure-Go backend test: go test -v -tags purego . (picks mac/win/wayland per OS)
  • Pure-Go Linux tests: CGO_ENABLED=0 go test -v -tags "purego,x11" . ./x11 and CGO_ENABLED=0 go test -v -tags "purego,libei" . ./libei
  • Pure-Go cross build: CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -tags mac .; GOOS must match the backend — GOOS=windows for win, GOOS=linux for x11/wayland/libei (a mismatched GOOS leaves the root package with no backend). Build the module root ., not ./... — examples/ and some subpackages need the Cgo backend.
  • Lint: golangci-lint run ./... (v2, config .golangci.yml); pure-Go backends: CGO_ENABLED=0 golangci-lint run --build-tags=x11 . ./x11/... ./clipboard/... (mac lints ./darwin/...)

There is no Makefile / Taskfile. CI:

  • .github/workflows/go.yml (Go 1.27.x; runs on push to master and on pull_request, newer run cancels older via concurrency; permissions: contents: read, checkouts use persist-credentials: false) — job cgo (macOS/Windows/Linux): go build ./..., go vet ., go test -v . (Linux: apt X11/xvfb deps, gofmt -l . must be empty, xvfb-run go test -v ./...); job purego (CGO_ENABLED=0, one job per OS: vet + test the backend pkgs, then . once per tag — mac/purego on macOS, win/purego on Windows, x11, purego,x11, wayland, purego, libei, purego,libei on Linux); job cross (CGO_ENABLED=0 build of . for the GOOS/GOARCH pairs the purego job does not cover: darwin amd64/arm64 mac, windows arm64/386 win, linux arm64 x11/wayland/libei).
  • Coverage: the cgo job runs tests with -coverprofile=coverage.out and uploads each OS (flag cgo-<OS>) via codecov/codecov-action@v7 (CODECOV_TOKEN secret, non-fatal) for the README codecov badge; codecov.yml ignores examples/ and test/, status checks are informational.
  • .github/workflows/lint.yml — golangci-lint (README badge, replaces Go Report Card): per OS, cgo (./...) plus each native pure-Go tag (x11/wayland/libei on Linux, mac on macOS, win on Windows) with CGO_ENABLED=0.
  • .circleci/config.yml — Linux Cgo full tests: xvfb-run go test -v ./....

The old appveyor.yml has been removed.

Architecture

Single Go package robotgo at repo root (flat layout) with platform-specific files and C-binding subpackages. The default backend is Cgo wrappers over C headers vendored in subdirectories; build tags split platform implementations. In addition, five experimental pure-Go (no-Cgo) backends live in their own packages and are selected via build tags on the root package:

Tag Package Root wiring file Notes
win win/ windows_n.go Win32 via tailscale/win
mac darwin/ darwin.go Quartz/CoreGraphics via ebitengine/purego; window mgmt (GetTitle, GetBounds, ActivePid/ActiveName, MinWindow/MaxWindow/CloseWindow) via Accessibility (AXUIElement) + AppKit in darwin/window.go, needs the Accessibility permission (CheckAccess)
x11 x11/ x11_n.go XTEST/EWMH via jezek/xgb + xgbutil
wayland wayland/ wayland_n.go wlroots virtual-input/screencopy protocols
libei libei/ libei.go xdg-desktop-portal RemoteDesktop (GNOME/KDE)
purego — — shortcut: mac on darwin, win on windows, wayland on linux; combine with x11 or libei on Linux to override

Default Cgo files carry //go:build !wayland && !win && !libei && !mac && !x11 && !purego (robotgo.go, key.go, robotgo_fn_v1.go, robot_info_test.go, ...) so any pure-Go tag disables the Cgo backend. Select at most one backend tag per build (purego may be paired with one Linux override): the constraints do not enforce mutual exclusion, e.g. -tags "x11,libei" compiles both x11_n.go and libei.go and fails with duplicate declarations. When adding a new pure-Go tag, extend these exclusions everywhere.

robotgo/
├── robotgo.go              # default Cgo API + preamble; excluded by any pure-Go tag
├── robotgo_pub.go          # portable (untagged): Version, MouseSleep, KeySleep, DisplayID, Scale...
├── doc.go                  # package doc + supported key names
├── robotgo_mac.go          # darwin && !mac && !purego
├── robotgo_mac_unix.go     # !windows, Cgo only (darwin + Cgo X11)
├── robotgo_mac_win.go      # (darwin || windows) && !win && !mac && !purego
├── robotgo_win.go          # windows (shared by Cgo and win backends)
├── robotgo_x11.go          # Cgo X11: !darwin && !windows && no pure-Go tag
├── robotgo_android.go, robotgo_adb.go
├── robotgo_ocr.go          # //go:build ocr only — not in normal builds (gosseract OCR)
├── darwin.go               # darwin && (mac || purego) — wires darwin/
├── windows_n.go            # windows && (win || purego) — wires win/
├── x11_n.go                # linux && x11 — wires x11/
├── wayland_n.go            # linux && (wayland || purego) && !libei && !x11 — wires wayland/
├── libei.go                # linux && libei — wires libei/
├── key.go                  # Cgo only: KeyTap/KeyToggle/Type/UnicodeType; keycode.go, screen.go, img.go, ps.go untagged
├── key_pub.go              # portable (untagged): KeyDown/KeyUp (wrap KeyToggle), KeyPress (wraps keyPress hook) + arg helpers
├── robotgo_fn_v1.go        # deprecated v1 aliases (kept for compat), Cgo only
├── robot_info_test.go      # Cgo smoke tests (used by GitHub Actions)
├── robot_mac_test.go       # darwin && (mac || purego) tests
├── key_c_test.go           # Cgo-only key/mouse-arg unit tests; img_test.go, key_pub_test.go untagged
├── robotgo_test.go         # interactive tests, (darwin || windows) Cgo only
├── base/       # C helpers (MMBitmap, rgb, microsleep, types, os, pubs, xdisplay)
├── mouse/      # Go pkg + C (mouse.h, mouse_c.h) with *_darwin.go/_windows.go/_x11.go
├── key/        # Go pkg + C (keycode.h, keycode_c.h, keypress.h, keypress_c.h, key_windows.go)
├── screen/     # Go pkg + C (goScreen.h, screen.go, screen_c.h, screengrab_c.h)
├── window/     # Go pkg + C (goWindow.h, window.h, alert_c.h, win_sys.h, pub.h)
├── clipboard/  # Go pkg (darwin/unix/windows variants) + cmd/gocopy, cmd/gopaste, example/
├── win/        # pure-Go Windows backend (no Cgo); //go:build windows
├── darwin/     # pure-Go macOS backend (purego + objc, app.go/cg.go); //go:build darwin
├── x11/        # pure-Go X11 backend (xgb/xgbutil); //go:build linux
├── wayland/    # pure-Go wlroots Wayland backend; internal/protocols/wlr_{foreign_toplevel,screencopy,virtual_keyboard,virtual_pointer}; libei/ (empty)
├── libei/      # pure-Go libei/xdg-portal backend (GNOME/KDE); //go:build linux
├── pub/        # pure-Go shared config/helpers: KeySleep, MouseSleep, DisplayID, MilliSleep, Sleep, SetDelay
├── mcp/        # MCP server package (mcp.go, a bare `package mcp` stub)
├── cuse/       # computer/, browser/, gui/ — empty placeholder dirs
├── event/      # C headers for android/ios global hooks (event_c.h)
├── cv/         # OpenCV helper (gocv.go)
├── examples/   # main.go + mouse, key, screen, window, scale — runnable main.go
├── lang/       # translated READMEs (de, es, fr, ja, ko, pt, ru, zh, zht)
├── skills/     # SKILL.md (agent skill descriptor)
├── docs/       # install.md, keys.md, CHANGELOG.md, README.md, robotgo-logo.svg, archive/
├── test/       # index.html; tmp/, logs/ are git-ignored scratch dirs
└── .github/workflows/go.yml, .circleci/config.yml

Key subpackage relationships: the root robotgo package pulls C code from screen/goScreen.h, mouse/mouse_c.h, window/goWindow.h. The key/ and clipboard/ directories are importable Go packages; base/ is header-only C support. The pure-Go win/, darwin/, x11/, wayland/ and libei/ packages each mirror the robotgo API surface (mouse/keyboard/screen/window/process, plus errors.go/ErrNotSupported where applicable) so a backend can be swapped per platform with a build tag; the root wiring files forward robotgo.* calls to them.

Code Style

  • Copyright header: every Go and C file starts with the 10-line Copyright (c) 2016-2026 AtomAI... block (see CONTRIBUTING.md). Preserve it verbatim when editing; add a second header only if authorship changes.
  • Indentation: tabs (Go default). Run gofmt before committing.
  • Build tags: use both forms together — //go:build darwin plus legacy // +build darwin lines — matching existing files (e.g. robotgo_mac_win.go uses one // +build line per AND-ed term).
  • Cgo: import "C" immediately follows a /* ... */ comment block containing #cgo directives and #includes. Keep LDFLAGS per-OS (#cgo darwin LDFLAGS, #cgo linux LDFLAGS, #cgo windows LDFLAGS).
  • Naming: exported CamelCase; key constants prefixed Key (e.g. KeyA, KeyEnter); C-type aliases prefixed C (CBitmap, CHex). Mirror existing patterns.
  • Imports: stdlib first, blank line, then third-party (github.com/...). Internal subpackage imported as github.com/go-vgo/robotgo/clipboard (full module path, not relative).
  • Comments: godoc-style // FuncName does X on every exported symbol. Package doc lives in doc.go / top of robotgo.go.
  • Error handling: return error as last result; use errors.New / fmt.Errorf. Try(fn, handler) helper wraps panics via recover. Do not swallow errors.
  • Types: existing code uses interface{} (pre-generics) — match local style when editing that file, but prefer any in new code. Do not mass-rewrite; gopls emits hints, not errors.

Testing

  • Framework: stdlib testing + github.com/vcaesar/tt (tt.Expect(t, want, got)).
  • Test files: *_test.go beside sources. Package declared as robotgo_test (external) for API-surface tests, or robotgo for internal.
  • Cgo smoke tests live in robot_info_test.go — explicitly selected by GitHub Actions on macOS/Windows. They query screen size/location/scale/window title (not truly headless) and are excluded from pure-Go test runs by build tags. Keep new lightweight Cgo tests here; match build tags to the APIs being tested.
  • Pure-Go tests: root robot_mac_test.go (darwin mac/purego) plus each backend's */robotgo_test.go (win/, darwin/, x11/, wayland/ + keyboard_wire_test.go, libei/). GitHub Actions runs -tags purego . on macOS/Windows and the x11/libei suites on Linux with CGO_ENABLED=0.
  • Interactive / display-required tests go in robotgo_test.go; its tags restrict it to darwin/windows Cgo, so CircleCI's Linux xvfb-run go test -v ./... does not include it (Linux root coverage there comes from robot_info_test.go, key_c_test.go, img_test.go).
  • Other unit tests: key_c_test.go (Cgo), img_test.go and key_pub_test.go (untagged, also run in pure-Go root jobs), clipboard/*_test.go.
  • Run one test: go test -v -run TestGetScreenSize .
  • No fixtures, snapshots, or golden files in use. Screenshots produced by examples are .gitignored.

Key Patterns

  • Cgo + platform split is mandatory. Any new OS-specific function must be gated by //go:build tags and have implementations (even stub) for darwin, linux, windows — examine mouse/mouse_darwin.go, mouse_windows.go, mouse_x11.go as the template.
  • Keep backends in sync: a new public robotgo API added to the build-tagged Cgo surface (e.g. robotgo.go, key.go, robotgo_mac*.go) needs a forwarder in each pure-Go wiring file (darwin.go, windows_n.go, x11_n.go, wayland_n.go, libei.go) and an implementation (or ErrNotSupported) in the matching backend package, otherwise -tags purego builds break. APIs in untagged portable files (robotgo_pub.go, key_pub.go, ps.go, screen.go, img.go, keycode.go) are already shared by every backend — do not redeclare them in wiring files. E.g. KeyDown/KeyUp/KeyPress live in key_pub.go: KeyDown/KeyUp call the root KeyToggle (Cgo key.go or the wiring forwarder), and KeyPress calls the unexported keyPress hook (Cgo key.go: down + 1-3 ms + up; wiring files: the backend KeyPress, i.e. its atomic KeyTap, so the x11 mutex covers the whole tap). Wiring files forward KeyTap/KeyToggle/keyPress; backend KeyToggle must default to "down" and accept a leading "up".
  • Free C-allocated bitmaps: every CaptureScreen, ToCBitmap, etc. must be paired with defer robotgo.FreeBitmap(bit) or robotgo.FreeBitmapArr(...). Leaking is a memory bug on all platforms.
  • Global tunables are package-level vars, not config structs: MouseSleep, KeySleep, DisplayID, NotPid, Scale. Callers mutate them directly (see README examples). Do not hide them behind getters.
  • robotgo_fn_v1.go contains deprecated v1 aliases — do not add new APIs there, but do not delete existing ones (backwards compatibility).
  • Version string lives in robotgo_pub.go as const Version = "v2.00.0.1658, MT. Baker!" (moved out of robotgo.go). Bump it when releasing; TestGetVer asserts it matches GetVersion(). The pure-Go backends carry their own const Version (win/ v0.1.0-windows, darwin/ v0.1.0-darwin, x11/ v0.1.0-x11, wayland/ v0.1.0-wayland, libei/ v0.1.0-libei).
  • Windows pid vs hwnd: set robotgo.NotPid = true to pass window handles instead of pids into the window/key APIs on Windows.
  • macOS permissions: most screen/input APIs silently fail without Accessibility + Screen Recording grants (both the Cgo and pure-Go darwin/ backends). When reproducing bugs on darwin, verify System Settings → Privacy & Security first.
  • Do not vendor: vendor/ is in .gitignore; also avoid go mod vendor (upstream note in README references golang/go#26366).
  • C artifacts (*.cgo1.go, *.cgo2.c, _cgo_*, *.o, *.a except whitelisted cdeps/... libpng archives) are git-ignored — do not commit them.
  • Commit sign-off is expected (see CONTRIBUTING.md); PRs require ≥2 maintainer review (LGTM).

Dependencies

  • github.com/jezek/xgb, github.com/jezek/xgbutil — X11 protocol on Linux (also the x11/ pure-Go backend).
  • github.com/vcaesar/go-wayland — Wayland protocol client (used by the wayland/ pure-Go backend).
  • github.com/godbus/dbus/v5 — D-Bus, used on Linux for Wayland/desktop ops and the libei/ xdg-portal backend.
  • github.com/tailscale/win, golang.org/x/sys (direct); github.com/dblohm7/wingoes, github.com/yusufpapurcu/wmi, github.com/go-ole/go-ole (indirect) — Windows system APIs (also used by the win/ pure-Go backend).
  • github.com/ebitengine/purego — direct; dlopen + objc runtime for the darwin/ pure-Go backend. github.com/gen2brain/shm — indirect shared-memory helper for screenshot paths.
  • github.com/vcaesar/keycode — cross-platform keycode mapping (used by key/).
  • github.com/vcaesar/imgo, golang.org/x/image — image encode/decode (PNG/JPEG save).
  • github.com/vcaesar/screenshot — screenshot backend.
  • github.com/vcaesar/gops (direct, imported by ps.go), github.com/shirou/gopsutil/v4 (indirect) — process enumeration (FindIds, PidExists, Kill).
  • github.com/vcaesar/tt — testing assertions.
  • github.com/otiai10/gosseract/v2 — OCR (used by robotgo_ocr.go; needs libtesseract).
  • Companion repos (not in go.mod, referenced in README/examples): github.com/vcaesar/bitmap, github.com/vcaesar/gcv (OpenCV), github.com/jezek/gohook (global event hook).