GitHub Hot Board

GitHub Hot Board · 저장소 아카이브

go-vgo/robotgo

RobotGo, Go Native cross-platform RPA, GUI automation, Auto test and Computer use @vcaesar (소개는 저장소 자체 문서에서 왔습니다.)

데이터 기준 October 27go-vgo

최고 순위

#403

종합 · Go 언어별

11K

누적 스타

969

포크 수

0

최근 30일 기록 일수

프로젝트 상태라이선스: Apache-2.0최근 push: October 22열린 이슈(PR 포함): 4

2026-10-25부터 수집. 미확인 = 아직 미수집

README에 뱃지를 붙여보세요 · go-vgo/robotgo[![README에 뱃지를 붙여보세요](https://git.vaiox.xyz/api/badge/go-vgo/robotgo.svg)](https://git.vaiox.xyz/ko/repo/go-vgo/robotgo)

Badge · 任何仓库都可以挂 —— 未上榜的仓库显示灰章,上完榜会自动点亮。

<a href="https://git.vaiox.xyz/ko/repo/go-vgo/robotgo"><img src="https://git.vaiox.xyz/api/badge/go-vgo/robotgo.svg" alt="README에 뱃지를 붙여보세요" height="20"></a>

프로젝트 문서

Robotgo

RobotGo 로고 — 마우스 포인터가 있는 로봇

Build Status CircleCI Status codecov golangci-lint GoDoc GitHub release Join the Discord chat at https://discord.gg/npPb3NzE4A

English | 简体中文 | 繁體中文 | 日本語 | 한국어 | Français | Deutsch | Español | Русский | Português

Golang 데스크톱 자동화, 자동 테스트 및 AI 컴퓨터 사용(Computer Use).
마우스와 키보드 제어, 화면 읽기, 프로세스, 윈도우 핸들, 이미지와 비트맵, 그리고 전역 이벤트 리스너.

RobotGo는 Mac, Windows, Linux를 지원하며, arm64와 x86-amd64 아키텍처도 지원합니다.

저는 지금 Codg를 만들고 있습니다. 간편하게 코딩하고 작업할 수 있는 AI 에이전트(Agent) 시스템으로, 자동화, 비동기, 동시성, 고효율 그리고 높은 정확도를 갖추고 있습니다.

Codg Demo

RobotGo-Pro는 JavaScript, Python, Lua 등 다른 언어 버전과 기술 지원, 새로운 기능, 그리고 최신 robotgo 버전("현재 오픈소스 버전 없음")을 제공합니다.

목차

Docs

Donate

기부자, 후원자 및 기타 문의: vzvway@gmail.com

Binding

ADB, Android adb와 iOS WDA를 래핑하고 robotgo 호환 API를 제공하는 패키지.

Requirements

Go 1.26+(go.mod 참조)와 백엔드 하나가 필요합니다:

  • 기본(Cgo): CGO_ENABLED=1, C 컴파일러, 그리고 아래의 플랫폼 라이브러리.
  • 순수 Go(테스트됨): C 툴체인 불필요. Cgo 없는 빌드 참조.

두 방식 모두 사용하는 기능에 맞는 기능별 의존성이 필요합니다.

Default Cgo setup

macOS

Go와 Xcode 명령줄 도구(Clang):

brew install go
xcode-select --install

권한(Cgo와 순수 Go 공통): 시스템 설정 > 개인정보 보호 및 보안에서 앱 또는 터미널에 손쉬운 사용(입력)과 화면 기록(캡처) 권한을 부여하세요.

Windows

winget install GoLang.Go

추가로 C 툴체인 하나가 필요합니다. LLVM-MinGW:

winget install MartinStorsjo.LLVM-MinGW.UCRT
$env:CC = "clang"

또는 MinGW-w64 (WinLibs):

winget install BrechtSanders.WinLibs.POSIX.UCRT
$env:CC = "gcc"

툴체인의 bin 경로(예: C:\mingw64\bin)가 PATH에 있어야 하고 GOARCH와 일치해야 합니다. 수동으로 설치한 MinGW-w64 처럼 Cgo와 호환되는 다른 컴파일러도 사용할 수 있습니다.

Bitmap은 MinGW-w64용 libpng만 포함합니다. 다른 툴체인을 쓸 때는 libpng를 직접 빌드하세요.

Linux (X11)

빌드: GCC, libc 헤더, X11/XTest 헤더. 런타임: XTEST를 지원하는 X 서버와 DISPLAY 설정. 네이티브 Wayland는 Cgo 없는 빌드를 참조하세요.

Ubuntu / Debian:

# Go (배포판 패키지가 너무 오래되었으면 Snap 사용)
sudo snap install go --classic
# 또는: sudo apt install golang

# 핵심(Cgo): 컴파일러, libc, X11, XTest
sudo apt install gcc libc6-dev libx11-dev xorg-dev libxtst-dev

# 클립보드(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-dev

Fedora:

# 핵심(Cgo): 컴파일러, libc, X11, XTest
sudo dnf install gcc glibc-devel libX11-devel libXtst-devel

# 클립보드(X11)
sudo dnf install xsel xclip

# Bitmap: libpng
sudo dnf install libpng-devel

# GoHook: XKB (Fedora 34 미만: xkbcomp-devel 대신 xorg-x11-xkb-utils-devel)
sudo dnf install libxkbcommon-devel libxkbcommon-x11-devel xkbcomp-devel

Feature-specific dependencies

핵심 설정에 더해, 사용하는 기능에만 필요합니다:

  • Linux 클립보드(Cgo와 순수 Go 공통): X11에서는 xclip 또는 xsel, Wayland에서는 wl-clipboard:

    sudo apt install wl-clipboard   # Ubuntu / Debian
    sudo dnf install wl-clipboard   # Fedora
  • Bitmap: libpng 헤더.

  • GoHook: Linux에서는 XCB/XKB 헤더.

Bitmap과 GoHook은 별도의 Cgo 패키지입니다. 순수 Go RobotGo 백엔드를 써도 이들의 C 의존성은 없어지지 않습니다.

Cgo-free Builds

테스트된 순수 Go 백엔드는 CGO_ENABLED=0으로 빌드 및 크로스 컴파일됩니다 (GCC, MinGW, Xcode, X11 헤더 불필요). import 경로와 API는 동일하며 빌드 태그로 백엔드를 선택합니다 — CGO_ENABLED=0만으로는 아무것도 선택되지 않습니다.

대상 GOOS 빌드 태그 패키지 런타임 요구 사항
windows win win Win32만 사용, 추가 런타임 없음
darwin mac darwin 시스템 프레임워크와 개인정보 권한
linux x11 x11 XTEST를 지원하는 X 서버, DISPLAY 설정
linux wayland wayland wlroots 컴포지터, Wayland 참조
linux libei libei RemoteDesktop portal(GNOME/KDE), libei 참조

**purego**는 단축 태그입니다: macOS에서는 mac, Windows에서는 win, Linux에서는 wayland. Linux에서 재정의하려면 x11 또는 libei를 추가하세요(-tags "purego,x11").

GOOS에 맞는 백엔드 태그 하나만 사용하세요. x11,libei 같은 조합은 컴파일에 실패합니다(purego와 Linux 재정의 하나를 함께 쓰는 경우만 예외).

Build commands

# 현재 OS
CGO_ENABLED=0 go build -tags purego .

# 크로스 컴파일
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 .

./...가 아니라 모듈 루트(.) 또는 직접 만든 패키지를 빌드하세요. examples/와 일부 하위 패키지는 Cgo 전용 API가 필요합니다.

Limitations

위의 런타임 요구 사항은 그대로 적용됩니다. CaptureScreen / FreeBitmap 같은 Cgo 전용 API는 존재하지 않으므로 CaptureImg를 사용하세요. 지원되지 않는 동작은 ErrNotSupported를 반환합니다(또는 빈 결과).

  • mac: 창 관리 없음 — ActiveName은 ErrNotSupported를 반환하고, GetTitle은 ""를 반환하며, 최소화/최대화/닫기는 아무 동작도 하지 않습니다.
  • wayland, libei: Wayland에는 전역 커서 위치를 위한 프로토콜이 없습니다. Location()은 Hyprland(IPC 소켓)와 KDE Plasma(D-Bus를 통한 KWin 스크립트)에서 해당 조회가 성공하면 실제 커서를 읽습니다. wayland는 추가로 모든 출력의 배율 비율이 같아야 합니다(배율이 다르거나 회전된 출력은 대체 동작). 그렇지 않거나 그 외 환경(GNOME, Sway, 기타 wlroots 컴포지터)에서는 실제 커서가 아니라 RobotGo가 마지막으로 주입한 위치를 반환합니다. 클립보드에는 wl-clipboard가 필요합니다.

Wayland

WAYLAND_DISPLAY와 XDG_RUNTIME_DIR가 설정되어 있고 다음을 노출하는 wlroots 컴포지터(Sway, Hyprland, Wayfire 등):

기능 프로토콜 global
마우스 제어 zwlr_virtual_pointer_manager_v1
키보드 제어 zwp_virtual_keyboard_manager_v1
화면 캡처 zwlr_screencopy_manager_v1
창 관리 zwlr_foreign_toplevel_manager_v1

GNOME과 KDE는 이러한 프로토콜을 제공하지 않으므로, 그곳에서는 libei를 사용하세요.

libei (GNOME / KDE)

입력은 xdg-desktop-portal의 RemoteDesktop D-Bus 인터페이스를 통해 전달됩니다. 세션 버스, xdg-desktop-portal, 그리고 이를 구현하는 백엔드 (xdg-desktop-portal-gnome, -kde, -wlr)가 필요합니다. 첫 실행 시 동의 대화상자가 표시되며, 복원 토큰은 $XDG_STATE_HOME/robotgo에 캐시됩니다.

절대 좌표 이동은 연결된 ScreenCast 스트림을 사용합니다(기본값). 상대 이동만 쓰려면 libei.LinkScreenCast = false로 설정하세요. 화면 캡처와 창 관리는 ErrNotSupported를 반환합니다.

Installation

go get github.com/go-vgo/robotgo
import "github.com/go-vgo/robotgo"

Bitmap에서 png.h: No such file or directory가 발생하면 해당 프로젝트의 libpng 요구 사항과 issues/47을 참조하세요.

Update

go get -u github.com/go-vgo/robotgo

go1.10.x의 C 파일 컴파일 캐시 문제에 주의하세요, golang #24355. 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")

  // 반환된 오류를 확인합니다. 잘못된 인자는 오류를 반환합니다
  if err := robotgo.ScrollDir(10, "forward"); err != nil {
    fmt.Println("robotgo.ScrollDir error:", err)
  }

  // 백엔드마다 다릅니다: Cgo는 오류를 반환하고, 순수 Go는 왼쪽 단일 클릭 후 nil을 반환합니다
  if err := robotgo.Click("left", "double"); err != nil {
    fmt.Println("robotgo.Click error:", err)
  }

  // MoveSmoothRelative는 부드러운 이동 실패를 ErrSmoothMove로 보고합니다
  err := robotgo.MoveSmoothRelative(10, -10)
  if errors.Is(err, robotgo.ErrSmoothMove) {
    fmt.Println("smooth move failed:", err)
  }

  // 순수 Go 백엔드는 지원하지 않는 작업에 ErrNotSupported를 반환합니다
  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)
  }

  // 알 수 없는 키 이름은 잘못된 키를 누르지 않고 오류를 반환합니다
  if err := robotgo.KeyTap("notakey"); err != nil {
    fmt.Println("robotgo.KeyTap error:", err)
  }

  // TypeStr는 첫 번째 입력 오류를 반환하고, Type은 입력한 문자 수만 반환합니다
  if err := robotgo.TypeStr("Hello, 世界"); err != nil {
    fmt.Println("robotgo.TypeStr error:", err)
  }

  // 수정 키를 누른 뒤 항상 해제하고 두 오류를 모두 확인합니다
  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)
}

Authors

Plans

  • 더 나은 멀티 스크린 지원
  • 윈도우 핸들 업데이트

Contributors

License

Robotgo는 주로 "the Apache License (Version 2.0)" 조건에 따라 배포되며, 일부 내용은 다양한 BSD 계열 라이선스의 적용을 받습니다.

LICENSE-APACHE, LICENSE를 참조하세요.

현재 순위

  • 403

    종합 랭킹 · 역대 최강 · Go

    11K 스타 · 969 fork · 총 스타 수

    종합 · Go →

최근 30일 추이

최근 30일간 기록이 없습니다.

비슷한 프로젝트 · 공유 토픽

← 랭킹으로