robotgo

C/C++ 2025-08-12

robotgo

Golang桌面自动化。控制鼠标,键盘,读取屏幕,过程,窗口句柄,图像和位图以及全局事件侦听器。

robotgo支持Mac,Windows和Linux(X11); robotgo支持ARM64和X86-AMD64。

内容

  • 文档
  • 结合
  • 要求
  • 安装
  • 更新
  • 例子
  • 输入转换和键
  • 交叉编译
  • 作者
  • 计划
  • 贡献者
  • 执照

文档

  • 戈多克
  • API文档(已弃用,没有更新)

绑定:

ADB,包装Android ADB API。

机器人,绑定的JavaScript和其他,支持更多语言。

要求:

现在,请确保在安装robotgo之前正确安装Golang, GCC

全部:

 Golang

GCC

对于MacOS:

 brew install go

XCode命令行工具(和隐私设置:#277)

 xcode-select --install

对于Windows:

 winget install Golang.go
 winget install MartinStorsjo.LLVM-MinGW.UCRT

或mingw-w64(建议使用)或其他mingw llvm-mingw;

下载mingw,然后将系统环境变量C:\mingw64\bin设置为路径。将环境变量设置为从命令行运行GCC。

Or the other GCC (但使用位图时,您应该与自己一起编译“ libpng”。)

对于其他一切:

 GCC

X11 with the XTest extension (the Xtst library)

"Clipboard": xsel xclip


"Bitmap": libpng (Just used by the "bitmap".)

"Event-Gohook": xcb, xkb, libxkbcommon (Just used by the "hook".)

Ubuntu:
 # sudo apt install golang
sudo snap install go  --classic

# gcc
sudo apt install gcc libc6-dev

# x11
sudo apt install libx11-dev xorg-dev libxtst-dev

# Clipboard
sudo apt install xsel xclip

#
# Bitmap
sudo apt install libpng++-dev

# GoHook
sudo apt install xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev libxkbcommon-dev
软呢帽:
 # x11
sudo dnf install libXtst-devel

# Clipboard
sudo dnf install xsel xclip

#
# Bitmap
sudo dnf install libpng-devel

# GoHook
sudo dnf install libxkbcommon-devel libxkbcommon-x11-devel xorg-x11-xkb-utils-devel

安装:

使用GO模块支持(GO 1.11+),只需导入:

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

否则,要安装robotgo软件包,请运行命令:

 go get github.com/go-vgo/ robotgo

PNG.H:没有这样的文件或目录?请参阅问题/47。

更新:

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

注意GO1.10.x C文件编译缓存问题,Golang#24355。 go mod vendor问题,Golang#26366。

示例:

老鼠

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") }">
 package main

import (
  "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" )
}

键盘

robotgo" ) func main() { robotgo .TypeStr("Hello World") robotgo .TypeStr("だんしゃり", 0, 1) // robotgo .TypeStr("テストする") robotgo .TypeStr("Hi, Seattle space needle, Golden gate bridge, One world trade center.") robotgo .TypeStr("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 .TypeStr("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) } }">
 package main

import (
  "fmt"

  "github.com/go-vgo/ robotgo "
)

func main () {
  robotgo . TypeStr ( "Hello World" )
  robotgo . TypeStr ( "だんしゃり" , 0 , 1 )
  // robotgo .TypeStr("テストする")

  robotgo . TypeStr ( "Hi, Seattle space needle, Golden gate bridge, One world trade center." )
  robotgo . TypeStr ( "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 .TypeStr("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 )
  }
}

屏幕

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

位图

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"

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

OPENCV

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

事件

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

窗户

robotgo" ) func main() { fpid, err := robotgo .FindIds("Google") if err == nil { fmt.Println("pids... ", fpid) if len(fpid) > 0 { robotgo .TypeStr("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) }">
 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 . TypeStr ( "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 )
}

作者

  • 作者是VZ
  • 维护者
  • 贡献者

计划

  • 重构一些C代码(例如X11,Windows)
  • 更好的多幕支持
  • Wayland支持
  • 更新窗口句柄
  • 尝试支持Android和iOS

贡献者

  • 有关贡献者的完整列表,请参见贡献者页面。
  • 请参阅贡献指南。

执照

robotgo主要按照“ Apache许可证(2.0版)”的条款分发,其中各种BSD样许可涵盖了部分。

请参阅许可证,许可证。

下载源码

通过命令行克隆项目:

git clone https://github.com/go-vgo/robotgo.git