Compare commits

..

No commits in common. "master" and "v1.0.0-beta4.1" have entirely different histories.

55 changed files with 972 additions and 1547 deletions

View File

@ -5,7 +5,7 @@ jobs:
docker: docker:
# using custom image, see .circleci/images/primary/Dockerfile # using custom image, see .circleci/images/primary/Dockerfile
# - image: govgo/robotgoci:1.10.3 # - image: govgo/robotgoci:1.10.3
- image: golang:1.23.0 - image: golang:1.17.6
working_directory: /gopath/src/github.com/go-vgo/robotgo working_directory: /gopath/src/github.com/go-vgo/robotgo
steps: steps:
- checkout - checkout
@ -20,6 +20,7 @@ jobs:
- run: apt -y install xvfb - run: apt -y install xvfb
# #
# override: # override:
# - run: go get -u github.com/go-vgo/robotgo
- run: go get -v -t -d ./... - run: go get -v -t -d ./...
- run: xvfb-run go test -v ./... - run: xvfb-run go test -v ./...
# #

View File

@ -1,5 +1,5 @@
# FROM golang:1.10.1 # FROM golang:1.10.1
FROM golang:1.24.2-stretch AS build FROM golang:1.17.6-stretch AS build
# FROM govgo/go:1.11.1 # FROM govgo/go:1.11.1
RUN apt update && apt install -y --no-install-recommends \ RUN apt update && apt install -y --no-install-recommends \

View File

@ -1,4 +1,4 @@
1. Please **speak English (English only)**, this is the language everybody of us can speak and write. 1. Please **speak English**, this is the language everybody of us can speak and write.
2. Please take a moment to **search** that an issue **doesn't already exist**. 2. Please take a moment to **search** that an issue **doesn't already exist**.
3. Please make sure `Golang, GCC` is installed correctly before installing RobotGo. 3. Please make sure `Golang, GCC` is installed correctly before installing RobotGo.
<!-- 4. Please ask questions or config/deploy problems on our Gitter channel: https://gitter.im/go-vgo/robotgo --> <!-- 4. Please ask questions or config/deploy problems on our Gitter channel: https://gitter.im/go-vgo/robotgo -->

View File

@ -5,7 +5,7 @@ The pull request will be closed without any reasons if it does not satisfy any o
3. Please read contributing guidelines: [CONTRIBUTING](https://github.com/go-vgo/robotgo/blob/master/CONTRIBUTING.md) 3. Please read contributing guidelines: [CONTRIBUTING](https://github.com/go-vgo/robotgo/blob/master/CONTRIBUTING.md)
4. Describe what your pull request does and which issue you're targeting (if any and **Please use English**) 4. Describe what your pull request does and which issue you're targeting (if any and **Please use English**)
5. ... if it is not related to any particular issues, explain why we should not reject your pull request. 5. ... if it is not related to any particular issues, explain why we should not reject your pull request.
6. The Commits must **use English**, must be test and No useless submissions. 6. The Commits must use English, must be test and No useless submissions.
**You MUST delete the content above including this line before posting, otherwise your pull request will be invalid.** **You MUST delete the content above including this line before posting, otherwise your pull request will be invalid.**

View File

@ -10,10 +10,10 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Set up Go 1.24.0 - name: Set up Go 1.17
uses: actions/setup-go@v1 uses: actions/setup-go@v1
with: with:
go-version: 1.24.0 go-version: 1.17
id: go id: go
- name: Check out code into the Go module directory - name: Check out code into the Go module directory

View File

@ -15,9 +15,7 @@ go:
# - 1.14.x # - 1.14.x
# - 1.15.x # - 1.15.x
# - 1.16.x # - 1.16.x
# - 1.17.x - 1.17.x
# - 1.18.x
- 1.19.x
# - tip # - tip
addons: addons:

View File

@ -24,7 +24,7 @@ This process gives everyone a chance to validate the design, helps prevent dupli
## Testing redux ## Testing redux
Before sending code out for review, run all the tests for the whole tree to make sure the changes don't break other usage and keep the compatibility on upgrade. You must be test on Mac, Windows, Linux and other. You should install the CLI for Circle CI, as we are using the server for continuous testing. Before sending code out for review, run all the tests for the whole tree to make sure the changes don't break other usage and keep the compatibility on upgrade. You must be test on Mac, Windows, Linux and other. You should install the CLI for Circle CI, as we are using the server for continous testing.
## Code review ## Code review

152
README.md
View File

@ -4,33 +4,29 @@
<!--[![Build Status](https://travis-ci.org/go-vgo/robotgo.svg)](https://travis-ci.org/go-vgo/robotgo) <!--[![Build Status](https://travis-ci.org/go-vgo/robotgo.svg)](https://travis-ci.org/go-vgo/robotgo)
[![codecov](https://codecov.io/gh/go-vgo/robotgo/branch/master/graph/badge.svg)](https://codecov.io/gh/go-vgo/robotgo)--> [![codecov](https://codecov.io/gh/go-vgo/robotgo/branch/master/graph/badge.svg)](https://codecov.io/gh/go-vgo/robotgo)-->
<!--<a href="https://circleci.com/gh/go-vgo/robotgo/tree/dev"><img src="https://img.shields.io/circleci/project/go-vgo/robotgo/dev.svg" alt="Build Status"></a>--> <!--<a href="https://circleci.com/gh/go-vgo/robotgo/tree/dev"><img src="https://img.shields.io/circleci/project/go-vgo/robotgo/dev.svg" alt="Build Status"></a>-->
[![Build Status](https://github.com/go-vgo/robotgo/workflows/Go/badge.svg)](https://github.com/go-vgo/robotgo/commits/master) [![Build Status](https://github.com/go-vgo/robotgo/workflows/Go/badge.svg)](https://github.com/go-vgo/robotgo/commits/master)
[![CircleCI Status](https://circleci.com/gh/go-vgo/robotgo.svg?style=shield)](https://circleci.com/gh/go-vgo/robotgo) [![CircleCI Status](https://circleci.com/gh/go-vgo/robotgo.svg?style=shield)](https://circleci.com/gh/go-vgo/robotgo)
[![Build Status](https://travis-ci.org/go-vgo/robotgo.svg)](https://travis-ci.org/go-vgo/robotgo) [![Build Status](https://travis-ci.org/go-vgo/robotgo.svg)](https://travis-ci.org/go-vgo/robotgo)
![Appveyor](https://ci.appveyor.com/api/projects/status/github/go-vgo/robotgo?branch=master&svg=true) ![Appveyor](https://ci.appveyor.com/api/projects/status/github/go-vgo/robotgo?branch=master&svg=true)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-vgo/robotgo)](https://goreportcard.com/report/github.com/go-vgo/robotgo) [![Go Report Card](https://goreportcard.com/badge/github.com/go-vgo/robotgo)](https://goreportcard.com/report/github.com/go-vgo/robotgo)
[![GoDoc](https://pkg.go.dev/badge/github.com/go-vgo/robotgo?status.svg)](https://pkg.go.dev/github.com/go-vgo/robotgo?tab=doc) [![GoDoc](https://godoc.org/github.com/go-vgo/robotgo?status.svg)](https://godoc.org/github.com/go-vgo/robotgo)
[![GitHub release](https://img.shields.io/github/release/go-vgo/robotgo.svg)](https://github.com/go-vgo/robotgo/releases/latest) [![GitHub release](https://img.shields.io/github/release/go-vgo/robotgo.svg)](https://github.com/go-vgo/robotgo/releases/latest)
[![Join the chat at https://gitter.im/go-vgo/robotgo](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-vgo/robotgo?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/go-vgo/robotgo](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-vgo/robotgo?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!-- [![Release](https://github-release-version.herokuapp.com/github/go-vgo/robotgo/release.svg?style=flat)](https://github.com/go-vgo/robotgo/releases/latest) --> <!-- [![Release](https://github-release-version.herokuapp.com/github/go-vgo/robotgo/release.svg?style=flat)](https://github.com/go-vgo/robotgo/releases/latest) -->
<!-- <a href="https://github.com/go-vgo/robotgo/releases"><img src="https://img.shields.io/badge/%20version%20-%206.0.0%20-blue.svg?style=flat-square" alt="Releases"></a> --> <!-- <a href="https://github.com/go-vgo/robotgo/releases"><img src="https://img.shields.io/badge/%20version%20-%206.0.0%20-blue.svg?style=flat-square" alt="Releases"></a> -->
> Golang Desktop Automation. Control the mouse, keyboard, read the screen, process, Window Handle, image and bitmap and global event listener. > Golang Desktop Automation. Control the mouse, keyboard, bitmap and image, read the screen, process, Window Handle and global event listener.
RobotGo supports Mac, Windows, and Linux(X11); and robotgo supports arm64 and x86-amd64. RobotGo supports Mac, Windows, and Linux(X11); and robotgo supports arm64 and x86-amd64.
## Contents ## Contents
- [Docs](#docs) - [Docs](#docs)
- [Binding](#binding) - [Binding](#binding)
- [Requirements](#requirements) - [Requirements](#requirements)
- [Installation](#installation) - [Installation](#installation)
- [Update](#update) - [Update](#update)
- [Examples](#examples) - [Examples](#examples)
- [Type Conversion and keys](https://github.com/go-vgo/robotgo/blob/master/docs/keys.md) - [Cross-Compiling](#crosscompiling)
- [Cross-Compiling](https://github.com/go-vgo/robotgo/blob/master/docs/install.md#crosscompiling)
- [Authors](#authors) - [Authors](#authors)
- [Plans](#plans) - [Plans](#plans)
- [Donate](#donate) - [Donate](#donate)
@ -38,12 +34,10 @@ RobotGo supports Mac, Windows, and Linux(X11); and robotgo supports arm64 and x8
- [License](#license) - [License](#license)
## Docs ## Docs
- [GoDoc](https://godoc.org/github.com/go-vgo/robotgo) <br> - [GoDoc](https://godoc.org/github.com/go-vgo/robotgo) <br>
- [API Docs](https://github.com/go-vgo/robotgo/blob/master/docs/doc.md) (Deprecated, no updated) - [API Docs](https://github.com/go-vgo/robotgo/blob/master/docs/doc.md) (Deprecated, no updated)
## Binding: ## Binding:
[ADB](https://github.com/vcaesar/adb), packaging android adb API. [ADB](https://github.com/vcaesar/adb), packaging android adb API.
[Robotn](https://github.com/vcaesar/robotn), binding JavaScript and other, support more language. [Robotn](https://github.com/vcaesar/robotn), binding JavaScript and other, support more language.
@ -53,17 +47,13 @@ RobotGo supports Mac, Windows, and Linux(X11); and robotgo supports arm64 and x8
Now, Please make sure `Golang, GCC` is installed correctly before installing RobotGo. Now, Please make sure `Golang, GCC` is installed correctly before installing RobotGo.
### ALL: ### ALL:
``` ```
Golang Golang
GCC GCC
``` ```
#### For MacOS: #### For Mac OS X:
```
brew install go
```
Xcode Command Line Tools (And Privacy setting: [#277](https://github.com/go-vgo/robotgo/issues/277) ) Xcode Command Line Tools (And Privacy setting: [#277](https://github.com/go-vgo/robotgo/issues/277) )
@ -72,21 +62,13 @@ xcode-select --install
``` ```
#### For Windows: #### For Windows:
```
winget install Golang.go [MinGW-w64](https://sourceforge.net/projects/mingw-w64/files) (Use recommended)
```
``` ```
winget install MartinStorsjo.LLVM-MinGW.UCRT Or the other GCC (But you should compile the "libpng" with yourself when use the bitmap.)
``` ```
Or [MinGW-w64](https://sourceforge.net/projects/mingw-w64/files) (Use recommended) or others Mingw [llvm-mingw](https://github.com/mstorsjo/llvm-mingw);
Download the Mingw, then set system environment variables `C:\mingw64\bin` to the Path.
[Set environment variables to run GCC from command line](https://www.youtube.com/results?search_query=Set+environment+variables+to+run+GCC+from+command+line).
`Or the other GCC` (But you should compile the "libpng" with yourself when use the [bitmap](https://github.com/vcaesar/bitmap).)
#### For everything else: #### For everything else:
``` ```
@ -94,55 +76,52 @@ GCC
X11 with the XTest extension (the Xtst library) X11 with the XTest extension (the Xtst library)
"Clipboard": xsel xclip
"Bitmap":
"Bitmap": libpng (Just used by the "bitmap".) libpng (Just used by bitmap)
"Event-Gohook": xcb, xkb, libxkbcommon (Just used by the "hook".) "Event":
xcb, xkb, libxkbcommon
"Clipboard":
xsel xclip
``` ```
##### Ubuntu: ##### Ubuntu:
```yml ```yml
# sudo apt install golang
sudo snap install go --classic
# gcc # gcc
sudo apt install gcc libc6-dev sudo apt install gcc libc6-dev
# x11 # x11
sudo apt install libx11-dev xorg-dev libxtst-dev sudo apt install libx11-dev xorg-dev libxtst-dev
# Clipboard
sudo apt install xsel xclip
#
# Bitmap # Bitmap
sudo apt install libpng++-dev sudo apt install libpng++-dev
# GoHook # Hook
sudo apt install xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev libxkbcommon-dev sudo apt install xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev libxkbcommon-dev
# Clipboard
sudo apt install xsel xclip
``` ```
##### Fedora: ##### Fedora:
```yml ```yml
# x11
sudo dnf install libXtst-devel sudo dnf install libXtst-devel
# Clipboard
sudo dnf install xsel xclip
#
# Bitmap # Bitmap
sudo dnf install libpng-devel sudo dnf install libpng-devel
# GoHook # Hook
sudo dnf install libxkbcommon-devel libxkbcommon-x11-devel xorg-x11-xkb-utils-devel sudo dnf install libxkbcommon-devel libxkbcommon-x11-devel xorg-x11-xkb-utils-devel
# Clipboard
sudo dnf install xsel xclip
``` ```
## Installation: ## Installation:
@ -162,7 +141,6 @@ go get github.com/go-vgo/robotgo
png.h: No such file or directory? Please see [issues/47](https://github.com/go-vgo/robotgo/issues/47). png.h: No such file or directory? Please see [issues/47](https://github.com/go-vgo/robotgo/issues/47).
## Update: ## Update:
``` ```
go get -u github.com/go-vgo/robotgo go get -u github.com/go-vgo/robotgo
``` ```
@ -170,6 +148,7 @@ go get -u github.com/go-vgo/robotgo
Note go1.10.x C file compilation cache problem, [golang #24355](https://github.com/golang/go/issues/24355). Note go1.10.x C file compilation cache problem, [golang #24355](https://github.com/golang/go/issues/24355).
`go mod vendor` problem, [golang #26366](https://github.com/golang/go/issues/26366). `go mod vendor` problem, [golang #26366](https://github.com/golang/go/issues/26366).
## [Examples:](https://github.com/go-vgo/robotgo/blob/master/examples) ## [Examples:](https://github.com/go-vgo/robotgo/blob/master/examples)
#### [Mouse](https://github.com/go-vgo/robotgo/blob/master/examples/mouse/main.go) #### [Mouse](https://github.com/go-vgo/robotgo/blob/master/examples/mouse/main.go)
@ -178,21 +157,14 @@ Note go1.10.x C file compilation cache problem, [golang #24355](https://github.c
package main package main
import ( import (
"fmt"
"github.com/go-vgo/robotgo" "github.com/go-vgo/robotgo"
) )
func main() { func main() {
robotgo.MouseSleep = 300 robotgo.MouseSleep = 100
robotgo.Move(100, 100) robotgo.ScrollMouse(10, "up")
fmt.Println(robotgo.Location()) robotgo.ScrollMouse(20, "right")
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(0, -10)
robotgo.Scroll(100, 0) robotgo.Scroll(100, 0)
@ -227,11 +199,10 @@ import (
func main() { func main() {
robotgo.TypeStr("Hello World") robotgo.TypeStr("Hello World")
robotgo.TypeStr("だんしゃり", 0, 1) robotgo.TypeStr("だんしゃり", 1)
// robotgo.TypeStr("テストする") // robotgo.TypeStr("テストする")
robotgo.TypeStr("Hi, Seattle space needle, Golden gate bridge, One world trade center.") robotgo.TypeStr("Hi galaxy. こんにちは世界.")
robotgo.TypeStr("Hi galaxy, hi stars, hi MT.Rainier, hi sea. こんにちは世界.")
robotgo.Sleep(1) robotgo.Sleep(1)
// ustr := uint32(robotgo.CharCodeAt("Test", 0)) // ustr := uint32(robotgo.CharCodeAt("Test", 0))
@ -264,14 +235,13 @@ package main
import ( import (
"fmt" "fmt"
"strconv"
"github.com/go-vgo/robotgo" "github.com/go-vgo/robotgo"
"github.com/vcaesar/imgo" "github.com/vcaesar/imgo"
) )
func main() { func main() {
x, y := robotgo.Location() x, y := robotgo.GetMousePos()
fmt.Println("pos: ", x, y) fmt.Println("pos: ", x, y)
color := robotgo.GetPixelColor(100, 200) color := robotgo.GetPixelColor(100, 200)
@ -289,23 +259,18 @@ func main() {
num := robotgo.DisplaysNum() num := robotgo.DisplaysNum()
for i := 0; i < num; i++ { for i := 0; i < num; i++ {
robotgo.DisplayID = i robotgo.DisplayID = i
img1, _ := robotgo.CaptureImg() img1 := robotgo.CaptureImg()
path1 := "save_" + strconv.Itoa(i) path1 := "save_" + strconv.Itoa(i)
robotgo.Save(img1, path1+".png") robotgo.Save(img1, path1+".png")
robotgo.SaveJpeg(img1, path1+".jpeg", 50) robotgo.SaveJpeg(img1, path1+".jpeg", 50)
img2, _ := robotgo.CaptureImg(10, 10, 20, 20) img2 := robotgo.CaptureImg(10, 10, 20, 20)
robotgo.Save(img2, "test_"+strconv.Itoa(i)+".png") 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")
} }
} }
``` ```
#### [Bitmap](https://github.com/vcaesar/bitmap/blob/main/examples/main.go) #### [Bitmap](https://github.com/vcaesar/bitmap/blob/master/examples/main.go)
```Go ```Go
package main package main
@ -380,8 +345,8 @@ func opencv() {
// bit1 := robotgo.CaptureScreen(10, 10, 30, 30) // bit1 := robotgo.CaptureScreen(10, 10, 30, 30)
// img1 := robotgo.ToImage(bit1) // img1 := robotgo.ToImage(bit1)
// defer robotgo.FreeBitmapArr(bit0, bit1) // defer robotgo.FreeBitmapArr(bit0, bit1)
img, _ := robotgo.CaptureImg() img := robotgo.CaptureImg()
img1, _ := robotgo.CaptureImg(10, 10, 30, 30) img1 := robotgo.CaptureImg(10, 10, 30, 30)
fmt.Print("gcv find image: ") fmt.Print("gcv find image: ")
fmt.Println(gcv.FindImg(img1, img)) fmt.Println(gcv.FindImg(img1, img))
@ -483,13 +448,7 @@ func main() {
fmt.Println("pids... ", fpid) fmt.Println("pids... ", fpid)
if len(fpid) > 0 { if len(fpid) > 0 {
robotgo.TypeStr("Hi galaxy!", fpid[0]) robotgo.ActivePID(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.Kill(fpid[0])
} }
@ -514,19 +473,48 @@ func main() {
} }
``` ```
## Authors ## CrossCompiling
- [The author is vz](https://github.com/vcaesar) ##### Windows64 to windows32
- [Maintainers](https://github.com/orgs/go-vgo/people) ```Go
- [Contributors](https://github.com/go-vgo/robotgo/graphs/contributors) SET CGO_ENABLED=1
SET GOARCH=386
go build main.go
```
#### Other to windows
Install Requirements (Ubuntu, Just used by bitmap.):
```bash
sudo apt install gcc-multilib
sudo apt install gcc-mingw-w64
# fix err: zlib.h: No such file or directory
sudo apt install libz-mingw-w64-dev
```
Build the binary:
```Go
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ go build -x ./
```
```
// CC=mingw-w64\x86_64-7.2.0-win32-seh-rt_v5-rev1\mingw64\bin\gcc.exe
// CXX=mingw-w64\x86_64-7.2.0-win32-seh-rt_v5-rev1\mingw64\bin\g++.exe
```
Some discussions and questions, please see [issues/228](https://github.com/go-vgo/robotgo/issues/228), [issues/143](https://github.com/go-vgo/robotgo/issues/143).
## Authors
* [The author is vz](https://github.com/vcaesar)
* [Maintainers](https://github.com/orgs/go-vgo/people)
* [Contributors](https://github.com/go-vgo/robotgo/graphs/contributors)
## Plans ## Plans
- Refactor some C code to Go (such as x11, windows) - Refactor some C code to Go (such as x11, windows)
- Better multiscreen support - Better multiscreen support
- Wayland support - Waylad supports
- Update Window Handle - Update Window Handle
- Try to support Android and IOS - Try support Android and IOS
## Contributors ## Contributors

View File

@ -1,7 +1,5 @@
# Robotgo # Robotgo
## !!! Warning: this page not updated !!!
[![Build Status](https://github.com/go-vgo/robotgo/workflows/Go/badge.svg)](https://github.com/go-vgo/robotgo/commits/master) [![Build Status](https://github.com/go-vgo/robotgo/workflows/Go/badge.svg)](https://github.com/go-vgo/robotgo/commits/master)
[![CircleCI Status](https://circleci.com/gh/go-vgo/robotgo.svg?style=shield)](https://circleci.com/gh/go-vgo/robotgo) [![CircleCI Status](https://circleci.com/gh/go-vgo/robotgo.svg?style=shield)](https://circleci.com/gh/go-vgo/robotgo)
[![Build Status](https://travis-ci.org/go-vgo/robotgo.svg)](https://travis-ci.org/go-vgo/robotgo) [![Build Status](https://travis-ci.org/go-vgo/robotgo.svg)](https://travis-ci.org/go-vgo/robotgo)
@ -69,7 +67,7 @@ xcode-select --install
``` ```
Or the other GCC (But you should compile the "libpng" with yourself. Or the other GCC (But you should compile the "libpng" with yourself.
Or you can removed the bitmap.go.) Or you can removed the bitmap.go )
``` ```
#### For everything else (Linux 等其他系统): #### For everything else (Linux 等其他系统):

View File

@ -34,7 +34,7 @@ environment:
PATH: C:\msys64\mingw32\bin\;C:\Program Files (x86)\NSIS\;%PATH% PATH: C:\msys64\mingw32\bin\;C:\Program Files (x86)\NSIS\;%PATH%
# - COMPILER: MINGW_W64 # - COMPILER: MINGW_W64
# ARCHITECTURE: x64 # ARCHITECTURE: x64
GOVERSION: 1.23.0 GOVERSION: 1.17.6
# GOPATH: c:\gopath # GOPATH: c:\gopath
# scripts that run after cloning repository # scripts that run after cloning repository

View File

@ -11,7 +11,6 @@ struct _MMBitmap {
uint8_t *imageBuffer; /* Pixels stored in Quad I format; */ uint8_t *imageBuffer; /* Pixels stored in Quad I format; */
int32_t width; /* Never 0, unless image is NULL. */ int32_t width; /* Never 0, unless image is NULL. */
int32_t height; /* Never 0, unless image is NULL. */ int32_t height; /* Never 0, unless image is NULL. */
int32_t bytewidth; /* The aligned width (width + padding). */ int32_t bytewidth; /* The aligned width (width + padding). */
uint8_t bitsPerPixel; /* Should be either 24 or 32. */ uint8_t bitsPerPixel; /* Should be either 24 or 32. */
uint8_t bytesPerPixel; /* For convenience; should be bitsPerPixel / 8. */ uint8_t bytesPerPixel; /* For convenience; should be bitsPerPixel / 8. */

View File

@ -22,12 +22,12 @@
return TRUE; return TRUE;
} }
HWND GetHwndByPid(DWORD dwProcessId) { HWND GetHwndByPId(DWORD dwProcessId) {
WNDINFO info = {0}; WNDINFO info = {0};
info.hWnd = NULL; info.hWnd = NULL;
info.dwPid = dwProcessId; info.dwPid = dwProcessId;
EnumWindows(EnumWindowsProc, (LPARAM)&info); EnumWindows(EnumWindowsProc, (LPARAM)&info);
// printf("%d\n", info.hWnd);
return info.hWnd; return info.hWnd;
} }
#endif #endif

View File

@ -3,6 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
/* /*
Package clipboard read/write on clipboard Package clipboard read/write on clipboard
*/ */
package clipboard package clipboard

View File

@ -1,14 +1,14 @@
package main package main
import ( import (
"io" "io/ioutil"
"os" "os"
"github.com/go-vgo/robotgo/clipboard" "github.com/go-vgo/robotgo/clipboard"
) )
func main() { func main() {
out, err := io.ReadAll(os.Stdin) out, err := ioutil.ReadAll(os.Stdin)
if err != nil { if err != nil {
panic(err) panic(err)
} }

2
doc.go
View File

@ -54,7 +54,7 @@ Keys are supported:
"f23" "f23"
"f24" "f24"
"cmd" this is the "win" key for windows "cmd" is the "win" key for windows
"lcmd" left command "lcmd" left command
"rcmd" right command "rcmd" right command
// "command" // "command"

View File

@ -1,33 +0,0 @@
## CrossCompiling
##### Windows64 to windows32
```Go
SET CGO_ENABLED=1
SET GOARCH=386
go build main.go
```
#### Other to windows
Install Requirements (Ubuntu):
```bash
sudo apt install gcc-multilib
sudo apt install gcc-mingw-w64
# fix err: zlib.h: No such file or directory, Just used by bitmap.
sudo apt install libz-mingw-w64-dev
```
Build the binary:
```Go
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ go build -x ./
```
```
// CC=mingw-w64\x86_64-7.2.0-win32-seh-rt_v5-rev1\mingw64\bin\gcc.exe
// CXX=mingw-w64\x86_64-7.2.0-win32-seh-rt_v5-rev1\mingw64\bin\g++.exe
```
Some discussions and questions, please see [issues/228](https://github.com/go-vgo/robotgo/issues/228), [issues/143](https://github.com/go-vgo/robotgo/issues/143).

View File

@ -1,25 +1,3 @@
## Type Conversion
| | type conversion | func |
| --- | --------------------------------- | ----------------------- |
| \* | robotgo.Bitmap -> robotgo.CBitmap | robotgo.ToCBitmap() |
| | robotgo.Bitmap -> \*image.RGBA | robotgo.ToRGBAGo() |
| \* | robotgo.CBitmap -> C.MMBitmapRef | robotgo.ToMMBitmapRef() |
| | robotgo.CBitmap -> robotgo.Bitmap | robotgo.ToBitmap() |
| | robotgo.CBitmap -> image.Image | robotgo.ToImage() |
| | robotgo.CBitmap -> \*image.RGBA | robotgo.ToRGBA() |
| \* | C.MMBitmapRef -> robotgo.CBitmap | robotgo.CBitmap() |
| \* | image.Image -> robotgo.Bitmap | robotgo.ImgToBitmap() |
| | image.Image -> robotgo.CBitmap | robotgo.ImgToCBitmap() |
| | image.Image -> []byte | robotgo.ToByteImg() |
| | image.Image -> string | robotgo.ToStringImg() |
| \* | \*image.RGBA -> robotgo.Bitmap | robotgo.RGBAToBitmap() |
| \* | []byte -> image.Image | robotgo.ByteToImg() |
| | []byte-> robotgo.CBitmap | robotgo.ByteToCBitmap() |
| | []byte -> string | string() |
| \* | string -> image.Image | robotgo.StrToImg() |
| | string -> byte | []byte() |
# Keys # Keys
```Go ```Go

View File

@ -68,7 +68,7 @@ import (
) )
func main() { func main() {
x, y := robotgo.Location() x, y := robotgo.GetMousePos()
fmt.Println("pos:", x, y) fmt.Println("pos:", x, y)
color := robotgo.GetPixelColor(100, 200) color := robotgo.GetPixelColor(100, 200)
fmt.Println("color----", color) fmt.Println("color----", color)

View File

@ -18,16 +18,15 @@ import (
) )
func typeStr() { func typeStr() {
// typing "Hello World" // importing "Hello World"
robotgo.TypeStr("Hello World!", 0, 1) robotgo.TypeStr("Hello World!", 1)
robotgo.KeySleep = 100 robotgo.KeySleep = 100
robotgo.TypeStr("だんしゃり") robotgo.TypeStr("だんしゃり")
robotgo.TypeStr("Hi galaxy, hi stars, hi MT.Rainier, hi sea. こんにちは世界.") robotgo.TypeStr("Hi galaxy. こんにちは世界. 你好, 再见!")
robotgo.TypeStr("So, hi, bye! 你好, 再见!")
robotgo.Sleep(1) robotgo.Sleep(1)
robotgo.TypeStr("Hi, Seattle space needle, Golden gate bridge, One world trade center.") robotgo.TypeStr("So, hi, bye!")
robotgo.MilliSleep(100) robotgo.MilliSleep(100)
ustr := uint32(robotgo.CharCodeAt("So, hi, bye!", 0)) ustr := uint32(robotgo.CharCodeAt("So, hi, bye!", 0))
@ -74,14 +73,6 @@ func keyTap() {
robotgo.KeyTap("a", "control") robotgo.KeyTap("a", "control")
} }
func special() {
robotgo.TypeStr("{}")
robotgo.KeyTap("[", "]")
robotgo.KeyToggle("(")
robotgo.KeyToggle("(", "up")
}
func keyToggle() { func keyToggle() {
// robotgo.KeySleep = 150 // robotgo.KeySleep = 150
robotgo.KeyToggle(robotgo.KeyA) robotgo.KeyToggle(robotgo.KeyA)
@ -121,7 +112,6 @@ func key() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
typeStr() typeStr()
special()
keyTap() keyTap()
keyToggle() keyToggle()

View File

@ -25,7 +25,9 @@ func move() {
// move the mouse to 100, 200 // move the mouse to 100, 200
robotgo.Move(100, 200) robotgo.Move(100, 200)
// drag mouse with smooth // robotgo.Drag(10, 10)
// robotgo.Drag(20, 20, "right")
//
robotgo.DragSmooth(10, 10) robotgo.DragSmooth(10, 10)
robotgo.DragSmooth(100, 200, 1.0, 100.0) robotgo.DragSmooth(100, 200, 1.0, 100.0)
@ -35,7 +37,7 @@ func move() {
robotgo.MoveSmoothRelative(10, -100, 1.0, 30.0) robotgo.MoveSmoothRelative(10, -100, 1.0, 30.0)
for i := 0; i < 1080; i += 1000 { for i := 0; i < 1080; i += 1000 {
fmt.Println("i: ", i) fmt.Println(i)
// MoveMouse(800, i) // MoveMouse(800, i)
robotgo.Move(800, i) robotgo.Move(800, i)
} }
@ -55,7 +57,7 @@ func click() {
func get() { func get() {
// gets the mouse coordinates // gets the mouse coordinates
x, y := robotgo.Location() x, y := robotgo.GetMousePos()
fmt.Println("pos:", x, y) fmt.Println("pos:", x, y)
if x == 456 && y == 586 { if x == 456 && y == 586 {
fmt.Println("mouse...", "586") fmt.Println("mouse...", "586")
@ -66,15 +68,12 @@ func get() {
func toggleAndScroll() { func toggleAndScroll() {
// scrolls the mouse either up // scrolls the mouse either up
robotgo.ScrollDir(10, "up") robotgo.ScrollMouse(10, "up")
robotgo.ScrollDir(10, "right") robotgo.ScrollMouse(10, "right")
robotgo.Scroll(100, 10) robotgo.Scroll(100, 10)
robotgo.Scroll(0, -10) robotgo.Scroll(0, -10)
robotgo.Toggle("left")
robotgo.Toggle("left", "up")
// toggles the right mouse button // toggles the right mouse button
robotgo.Toggle("right") robotgo.Toggle("right")
robotgo.Toggle("right", "up") robotgo.Toggle("right", "up")

View File

@ -7,43 +7,28 @@ import (
) )
func main() { func main() {
//
// syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call() // syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call()
width, height := robotgo.GetScaleSize() width, height := robotgo.GetScaleSize()
fmt.Println("get scale screen size: ", width, height) fmt.Println("get scale screen size: ", width, height)
bitmap := robotgo.CaptureScreen(0, 0, width, height) bitmap := robotgo.CaptureScreen(0, 0, width, height)
defer robotgo.FreeBitmap(bitmap) // robotgo.SaveBitmap(bitmap, "test.png")
// bitmap.Save(bitmap, "test.png")
robotgo.Save(robotgo.ToImage(bitmap), "test.png") robotgo.Save(robotgo.ToImage(bitmap), "test.png")
robotgo.Scale = true sx := robotgo.ScaleX()
robotgo.Move(10, 10) s := robotgo.Scale()
robotgo.MoveSmooth(100, 100)
fmt.Println(robotgo.Location())
num := robotgo.DisplaysNum()
for i := 0; i < num; i++ {
rect := robotgo.GetScreenRect(i)
fmt.Println("rect: ", rect)
}
}
func old() {
sx := robotgo.ScaleX() // Deprecated
s := robotgo.Scale1() // Deprecated, use the ScaleF() function
robotx, roboty := 35*s/100, 25*s/100 robotx, roboty := 35*s/100, 25*s/100
fmt.Println("scale: ", sx, s, " pos: ", robotx, roboty) fmt.Println("scale: ", sx, s, " pos: ", robotx, roboty)
mx, my := robotgo.Location() mx, my := robotgo.GetMousePos()
sx, sy := mx*s/100, my*s/100 sx, sy := mx*s/100, my*s/100
rx, ry, rw, rh := sx, sy, robotx, roboty rx, ry, rw, rh := sx, sy, robotx, roboty
// bit1 := robotgo.CaptureScreen(10, 20, robotw, roboth) // bit1 := robotgo.CaptureScreen(10, 20, robotw, roboth)
bit1 := robotgo.CaptureScreen(rx, ry, rw, rh) bit1 := robotgo.CaptureScreen(rx, ry, rw, rh)
defer robotgo.FreeBitmap(bit1) // robotgo.SaveBitmap(bit1, "test2.png")
// bitmap.Save(bit1, "test2.png")
robotgo.Save(robotgo.ToImage(bit1), "test2.png") robotgo.Save(robotgo.ToImage(bit1), "test2.png")
clo := robotgo.GetPixelColor(robotx, roboty) clo := robotgo.GetPixelColor(robotx, roboty)

View File

@ -20,38 +20,30 @@ import (
func bitmap() { func bitmap() {
bit := robotgo.CaptureScreen() bit := robotgo.CaptureScreen()
defer robotgo.FreeBitmap(bit)
fmt.Println("abitMap...", bit) fmt.Println("abitMap...", bit)
gbit := robotgo.ToBitmap(bit) gbit := robotgo.ToBitmap(bit)
fmt.Println("bitmap...", gbit.Width) fmt.Println("bitmap...", gbit.Width)
gbitMap := robotgo.CaptureGo() gbitMap := robotgo.CaptureGo()
fmt.Println("Go CaptureScreen...", gbitMap.Width) fmt.Println("Go CaptureScreen...", gbitMap.Width)
// fmt.Println("...", gbitmap.Width, gbitmap.BytesPerPixel) // fmt.Println("...", gbitmap.Width, gbitmap.BytesPerPixel)
robotgo.SaveCapture("saveCapture.png", 10, 20, 100, 100) // robotgo.SaveCapture("saveCapture.png", 10, 20, 100, 100)
img, err := robotgo.CaptureImg() img := robotgo.CaptureImg()
fmt.Println("error: ", err)
robotgo.Save(img, "save.png") robotgo.Save(img, "save.png")
num := robotgo.DisplaysNum() num := robotgo.DisplaysNum()
for i := 0; i < num; i++ { for i := 0; i < num; i++ {
robotgo.DisplayID = i robotgo.DisplayID = i
img1, _ := robotgo.CaptureImg() img1 := robotgo.CaptureImg()
path1 := "save_" + strconv.Itoa(i) path1 := "save_" + strconv.Itoa(i)
robotgo.Save(img1, path1+".png") robotgo.Save(img1, path1+".png")
robotgo.SaveJpeg(img1, path1+".jpeg", 50) robotgo.SaveJpeg(img1, path1+".jpeg", 50)
img2, _ := robotgo.CaptureImg(10, 10, 20, 20) img2 := robotgo.CaptureImg(10, 10, 20, 20)
path2 := "test_" + strconv.Itoa(i) path2 := "test_" + strconv.Itoa(i)
robotgo.Save(img2, path2+".png") robotgo.Save(img2, path2+".png")
robotgo.SaveJpeg(img2, path2+".jpeg", 50) robotgo.SaveJpeg(img2, path2+".jpeg", 50)
x, y, w, h := robotgo.GetDisplayBounds(i)
img3, err := robotgo.CaptureImg(x, y, w, h)
fmt.Println("Capture error: ", err)
robotgo.Save(img3, path2+"_1.png")
} }
} }
@ -94,7 +86,7 @@ func screen() {
fmt.Println("ScaleF: ", s1) fmt.Println("ScaleF: ", s1)
} }
sx, sy = robotgo.GetScaleSize() sx, sy = robotgo.GetScaleSize()
fmt.Println("get screen scale size: ", sx, sy) fmt.Println("get screen sclae size: ", sx, sy)
color() color()
} }

View File

@ -28,7 +28,7 @@ func alert() {
func get() { func get() {
// get the current process id // get the current process id
pid := robotgo.GetPid() pid := robotgo.GetPID()
fmt.Println("pid----", pid) fmt.Println("pid----", pid)
// get current Window Active // get current Window Active
@ -54,17 +54,9 @@ func findIds() {
return return
} }
if len(fpid) > 0 {
robotgo.KeyTap("a", fpid[0])
robotgo.TypeStr("Hi galaxy!", fpid[0])
robotgo.KeyToggle("a", fpid[0], "cmd")
robotgo.KeyToggle("a", fpid[0], "cmd", "up")
}
fmt.Println("pids...", fpid) fmt.Println("pids...", fpid)
if len(fpid) > 0 { if len(fpid) > 0 {
err = robotgo.ActivePid(fpid[0]) err = robotgo.ActivePID(fpid[0])
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
@ -87,7 +79,7 @@ func findIds() {
} }
func active() { func active() {
robotgo.ActivePid(100) robotgo.ActivePID(100)
// robotgo.Sleep(2) // robotgo.Sleep(2)
robotgo.ActiveName("code") robotgo.ActiveName("code")
robotgo.Sleep(1) robotgo.Sleep(1)

49
go.mod
View File

@ -1,38 +1,33 @@
module github.com/go-vgo/robotgo module github.com/go-vgo/robotgo
go 1.23.0 go 1.17
toolchain go1.23.6
require ( require (
github.com/otiai10/gosseract/v2 v2.4.1 github.com/lxn/win v0.0.0-20210218163916-a377121e959e
github.com/otiai10/gosseract v2.2.1+incompatible
// github.com/robotn/gohook v0.31.3 // github.com/robotn/gohook v0.31.3
github.com/robotn/xgb v0.10.0 github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934
github.com/robotn/xgbutil v0.10.0 github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770
github.com/tailscale/win v0.0.0-20250213223159-5992cb43ca35 github.com/vcaesar/gops v0.22.0
github.com/vcaesar/gops v0.41.0 github.com/vcaesar/imgo v0.30.1
github.com/vcaesar/imgo v0.41.0 github.com/vcaesar/keycode v0.10.0
github.com/vcaesar/keycode v0.10.1 github.com/vcaesar/tt v0.20.0
github.com/vcaesar/tt v0.20.1 golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect
) )
require ( require (
github.com/dblohm7/wingoes v0.0.0-20240820181039-f2b84150679e // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/ebitengine/purego v0.8.3 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/gen2brain/shm v0.1.1 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect github.com/otiai10/mint v1.3.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/jezek/xgb v1.1.1 // indirect github.com/shirou/gopsutil/v3 v3.21.12 // indirect
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect github.com/tklauser/go-sysconf v0.3.9 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/tklauser/numcpus v0.3.0 // indirect
github.com/shirou/gopsutil/v4 v4.25.4 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
github.com/tklauser/go-sysconf v0.3.15 // indirect golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
github.com/tklauser/numcpus v0.10.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
github.com/vcaesar/screenshot v0.11.1
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
golang.org/x/image v0.27.0 // indirect
golang.org/x/sys v0.33.0 // indirect
) )
// replace golang.org/x/sys => github.com/golang/sys v0.0.0-20190109145017-48ac38b7c8cb // replace golang.org/x/sys => github.com/golang/sys v0.0.0-20190109145017-48ac38b7c8cb

123
go.sum
View File

@ -1,71 +1,72 @@
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ= 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/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dblohm7/wingoes v0.0.0-20240820181039-f2b84150679e h1:L+XrFvD0vBIBm+Wf9sFN6aU395t7JROoai0qXZraA4U= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/dblohm7/wingoes v0.0.0-20240820181039-f2b84150679e/go.mod h1:SUxUaAK/0UG5lYyZR1L1nC4AaYYvSSYTWQSH3FPcxKU=
github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
github.com/ebitengine/purego v0.8.3/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.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= github.com/otiai10/gosseract v2.2.1+incompatible h1:Ry5ltVdpdp4LAa2bMjsSJH34XHVOV7XMi41HtzL8X2I=
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc= github.com/otiai10/gosseract v2.2.1+incompatible/go.mod h1:XrzWItCzCpFRZ35n3YtVTgq5bLAhFIkascoRo8G32QE=
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/otiai10/mint v1.3.0 h1:Ady6MKVezQwHBkGzLFbrsywyp09Ah7rkmfjV3Bcr5uc=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934 h1:2lhSR8N3T6I30q096DT7/5AKEIcf1vvnnWAmS0wfnNY=
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ= 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/xgbutil v0.0.0-20190912154524-c861d6f87770 h1:2uX8QRLkkxn2EpAQ6I3KhA79BkdRZfvugJUzJadiJwk=
github.com/robotn/xgb v0.10.0/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ= github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770/go.mod h1:svkDXUDQjUiWzLrA0OZgHc4lbOts3C+uRfP6/yjwYnU=
github.com/robotn/xgbutil v0.10.0 h1:gvf7mGQqCWQ68aHRtCxgdewRk+/KAJui6l3MJQQRCKw= github.com/shirou/gopsutil/v3 v3.21.12 h1:VoGxEW2hpmz0Vt3wUvHIl9fquzYLNpVpgNNB7pGJimA=
github.com/robotn/xgbutil v0.10.0/go.mod h1:svkDXUDQjUiWzLrA0OZgHc4lbOts3C+uRfP6/yjwYnU= github.com/shirou/gopsutil/v3 v3.21.12/go.mod h1:BToYZVTlSVlfazpDDYFnsVZLaoRG+g8ufT6fPQLdJzA=
github.com/shirou/gopsutil/v4 v4.25.4 h1:cdtFO363VEOOFrUCjZRh4XVJkb548lyF0q0uTeMqYPw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/shirou/gopsutil/v4 v4.25.4/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
github.com/tailscale/win v0.0.0-20250213223159-5992cb43ca35 h1:wAZbkTZkqDzWsqxPh2qkBd3KvFU7tcxV0BP0Rnhkxog= github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
github.com/tailscale/win v0.0.0-20250213223159-5992cb43ca35/go.mod h1:aMd4yDHLjbOuYP6fMxj1d9ACDQlSWwYztcpybGHCQc8= github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA= github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
github.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk= github.com/vcaesar/gops v0.22.0 h1:aWHWxY3fvUuaJGph+LegYUSEU/874WJT7MInd8OUmP0=
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/vcaesar/gops v0.22.0/go.mod h1:GFNGo9xpCfjcfd/Hovi9RSrpd4FdaQt8V92TzpU22w4=
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= github.com/vcaesar/imgo v0.30.1 h1:B7QMm2mZY+SGoEvvJwNi+eAv21ptvk2YT1IbP2OzyLE=
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/vcaesar/imgo v0.30.1/go.mod h1:n4EluJIN/0UYYGPHBCY/BWlIjdRUdY5U6obtP2lrgdM=
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/vcaesar/keycode v0.10.0 h1:Qx5QE8ZXHyRyjoA2QOxBp25OKMKB+zxMVqm0FWGV0d4=
github.com/vcaesar/gops v0.41.0 h1:FG748Jyw3FOuZnbzSgB+CQSx2e5LbLCPWV2JU1brFdc= github.com/vcaesar/keycode v0.10.0/go.mod h1:JNlY7xbKsh+LAGfY2j4M3znVrGEm5W1R8s/Uv6BJcfQ=
github.com/vcaesar/gops v0.41.0/go.mod h1:/3048L7Rj7QjQKTSB+kKc7hDm63YhTWy5QJ10TCP37A= github.com/vcaesar/tt v0.20.0 h1:9t2Ycb9RNHcP0WgQgIaRKJBB+FrRdejuaL6uWIHuoBA=
github.com/vcaesar/imgo v0.41.0 h1:kNLYGrThXhB9Dd6IwFmfPnxq9P6yat2g7dpPjr7OWO8= github.com/vcaesar/tt v0.20.0/go.mod h1:GHPxQYhn+7OgKakRusH7KJ0M5MhywoeLb8Fcffs/Gtg=
github.com/vcaesar/imgo v0.41.0/go.mod h1:/LGOge8etlzaVu/7l+UfhJxR6QqaoX5yeuzGIMfWb4I= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/vcaesar/keycode v0.10.1 h1:0DesGmMAPWpYTCYddOFiCMKCDKgNnwiQa2QXindVUHw= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/vcaesar/keycode v0.10.1/go.mod h1:JNlY7xbKsh+LAGfY2j4M3znVrGEm5W1R8s/Uv6BJcfQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
github.com/vcaesar/screenshot v0.11.1 h1:GgPuN89XC4Yh38dLx4quPlSo3YiWWhwIria/j3LtrqU= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
github.com/vcaesar/screenshot v0.11.1/go.mod h1:gJNwHBiP1v1v7i8TQ4yV1XJtcyn2I/OJL7OziVQkwjs= golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4= golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
github.com/vcaesar/tt v0.20.1/go.mod h1:cH2+AwGAJm19Wa6xvEa+0r+sXDJBT0QgNQey6mwqLeU= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/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.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

6
img.go
View File

@ -55,7 +55,7 @@ func SaveJpeg(img image.Image, path string, quality ...int) error {
// ToByteImg convert image.Image to []byte // ToByteImg convert image.Image to []byte
func ToByteImg(img image.Image, fm ...string) []byte { func ToByteImg(img image.Image, fm ...string) []byte {
return imgo.ToByte(img, fm...) return imgo.ToByteImg(img, fm...)
} }
// ToStringImg convert image.Image to string // ToStringImg convert image.Image to string
@ -122,7 +122,7 @@ func ImgToBitmap(m image.Image) (bit Bitmap) {
// ToUint8p convert the []uint8 to uint8 pointer // ToUint8p convert the []uint8 to uint8 pointer
func ToUint8p(dst []uint8) *uint8 { func ToUint8p(dst []uint8) *uint8 {
src := make([]uint8, len(dst)+10) src := make([]uint8, len(dst)+10)
for i := 0; i <= len(dst)-4; i += 4 { for i := 0; i < len(dst)-4; i += 4 {
src[i+3] = dst[i+3] src[i+3] = dst[i+3]
src[i] = dst[i+2] src[i] = dst[i+2]
src[i+1] = dst[i+1] src[i+1] = dst[i+1]
@ -151,7 +151,7 @@ func val(p *uint8, n int) uint8 {
} }
func copyToVUint8A(dst []uint8, src *uint8) { func copyToVUint8A(dst []uint8, src *uint8) {
for i := 0; i <= len(dst)-4; i += 4 { for i := 0; i < len(dst)-4; i += 4 {
dst[i] = val(src, i+2) dst[i] = val(src, i+2)
dst[i+1] = val(src, i+1) dst[i+1] = val(src, i+1)
dst[i+2] = val(src, i) dst[i+2] = val(src, i)

228
key.go
View File

@ -12,7 +12,7 @@ package robotgo
/* /*
// #include "key/keycode.h" // #include "key/keycode.h"
#include "key/keypress_c.h" #include "key/goKey.h"
*/ */
import "C" import "C"
@ -23,13 +23,12 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"unicode"
"unsafe" "unsafe"
"github.com/go-vgo/robotgo/clipboard" "github.com/go-vgo/robotgo/clipboard"
"github.com/vcaesar/tt"
) )
// Defining a bunch of constants.
const ( const (
// KeyA define key "a" // KeyA define key "a"
KeyA = "a" KeyA = "a"
@ -59,33 +58,6 @@ const (
KeyY = "y" KeyY = "y"
KeyZ = "z" KeyZ = "z"
// //
CapA = "A"
CapB = "B"
CapC = "C"
CapD = "D"
CapE = "E"
CapF = "F"
CapG = "G"
CapH = "H"
CapI = "I"
CapJ = "J"
CapK = "K"
CapL = "L"
CapM = "M"
CapN = "N"
CapO = "O"
CapP = "P"
CapQ = "Q"
CapR = "R"
CapS = "S"
CapT = "T"
CapU = "U"
CapV = "V"
CapW = "W"
CapX = "X"
CapY = "Y"
CapZ = "Z"
//
Key0 = "0" Key0 = "0"
Key1 = "1" Key1 = "1"
Key2 = "2" Key2 = "2"
@ -201,7 +173,7 @@ const (
LightsKbdDown = "lights_kbd_down" LightsKbdDown = "lights_kbd_down"
) )
// keyNames define a map of key names to MMKeyCode // keyNames define MMKeyCode map
var keyNames = map[string]C.MMKeyCode{ var keyNames = map[string]C.MMKeyCode{
"backspace": C.K_BACKSPACE, "backspace": C.K_BACKSPACE,
"delete": C.K_DELETE, "delete": C.K_DELETE,
@ -321,20 +293,10 @@ var keyNames = map[string]C.MMKeyCode{
// { NULL: C.K_NOT_A_KEY } // { NULL: C.K_NOT_A_KEY }
} }
// CmdCtrl If the operating system is macOS, return the key string "cmd", func tapKeyCode(code C.MMKeyCode, flags C.MMKeyFlags) {
// otherwise return the key string "ctrl C.toggleKeyCode(code, true, flags)
func CmdCtrl() string { MilliSleep(5)
if runtime.GOOS == "darwin" { C.toggleKeyCode(code, false, flags)
return "cmd"
}
return "ctrl"
}
// It sends a key press and release to the active application
func tapKeyCode(code C.MMKeyCode, flags C.MMKeyFlags, pid C.uintptr) {
C.toggleKeyCode(code, true, flags, pid)
MilliSleep(3)
C.toggleKeyCode(code, false, flags, pid)
} }
var keyErr = errors.New("Invalid key flag specified.") var keyErr = errors.New("Invalid key flag specified.")
@ -404,51 +366,35 @@ func getFlagsFromValue(value []string) (flags C.MMKeyFlags) {
return return
} }
func keyTaps(k string, keyArr []string, pid int) error { func keyTaps(k string, keyArr []string) error {
flags := getFlagsFromValue(keyArr) flags := getFlagsFromValue(keyArr)
key, err := checkKeyCodes(k) key, err := checkKeyCodes(k)
if err != nil { if err != nil {
return err return err
} }
tapKeyCode(key, flags, C.uintptr(pid)) tapKeyCode(key, flags)
MilliSleep(KeySleep) MilliSleep(KeySleep)
return nil return nil
} }
func getKeyDown(keyArr []string) (bool, []string) { func keyToggles(k string, keyArr []string) error {
if len(keyArr) <= 0 {
keyArr = append(keyArr, "down")
}
down := true down := true
if keyArr[0] == "up" { if keyArr[0] == "up" {
down = false down = false
} }
if keyArr[0] == "up" || keyArr[0] == "down" {
keyArr = keyArr[1:]
}
return down, keyArr
}
func keyTogglesB(k string, down bool, keyArr []string, pid int) error {
flags := getFlagsFromValue(keyArr) flags := getFlagsFromValue(keyArr)
key, err := checkKeyCodes(k) key, err := checkKeyCodes(k)
if err != nil { if err != nil {
return err return err
} }
C.toggleKeyCode(key, C.bool(down), flags, C.uintptr(pid)) C.toggleKeyCode(key, C.bool(down), flags)
MilliSleep(KeySleep) MilliSleep(KeySleep)
return nil return nil
} }
func keyToggles(k string, keyArr []string, pid int) error {
down, keyArr1 := getKeyDown(keyArr)
return keyTogglesB(k, down, keyArr1, pid)
}
/* /*
__ ___ ___________ ____ .______ ______ ___ .______ _______ __ ___ ___________ ____ .______ ______ ___ .______ _______
| |/ / | ____\ \ / / | _ \ / __ \ / \ | _ \ | \ | |/ / | ____\ \ / / | _ \ / __ \ / \ | _ \ | \
@ -459,7 +405,7 @@ func keyToggles(k string, keyArr []string, pid int) error {
*/ */
// ToInterfaces convert []string to []interface{} // ToInterfaces []string to []interface{}
func ToInterfaces(fields []string) []interface{} { func ToInterfaces(fields []string) []interface{} {
res := make([]interface{}, 0, len(fields)) res := make([]interface{}, 0, len(fields))
for _, s := range fields { for _, s := range fields {
@ -468,7 +414,7 @@ func ToInterfaces(fields []string) []interface{} {
return res return res
} }
// ToStrings convert []interface{} to []string // ToStrings []interface{} to []string
func ToStrings(fields []interface{}) []string { func ToStrings(fields []interface{}) []string {
res := make([]string, 0, len(fields)) res := make([]string, 0, len(fields))
for _, s := range fields { for _, s := range fields {
@ -477,7 +423,6 @@ func ToStrings(fields []interface{}) []string {
return res return res
} }
// toErr it converts a C string to a Go error
func toErr(str *C.char) error { func toErr(str *C.char) error {
gstr := C.GoString(str) gstr := C.GoString(str)
if gstr == "" { if gstr == "" {
@ -486,30 +431,12 @@ func toErr(str *C.char) error {
return errors.New(gstr) return errors.New(gstr)
} }
func appendShift(key string, len1 int, args ...interface{}) (string, []interface{}) { // KeyTap tap the keyboard code;
if len(key) > 0 && unicode.IsUpper([]rune(key)[0]) {
args = append(args, "shift")
}
key = strings.ToLower(key)
if _, ok := Special[key]; ok {
key = Special[key]
if len(args) <= len1 {
args = append(args, "shift")
}
}
return key, args
}
// KeyTap taps the keyboard code;
// //
// See keys supported: // See keys:
// // https://github.com/go-vgo/robotgo/blob/master/docs/keys.md
// https://github.com/go-vgo/robotgo/blob/master/docs/keys.md#keys
// //
// Examples: // Examples:
//
// robotgo.KeySleep = 100 // 100 millisecond // robotgo.KeySleep = 100 // 100 millisecond
// robotgo.KeyTap("a") // robotgo.KeyTap("a")
// robotgo.KeyTap("i", "alt", "command") // robotgo.KeyTap("i", "alt", "command")
@ -517,59 +444,57 @@ func appendShift(key string, len1 int, args ...interface{}) (string, []interface
// arr := []string{"alt", "command"} // arr := []string{"alt", "command"}
// robotgo.KeyTap("i", arr) // robotgo.KeyTap("i", arr)
// //
// robotgo.KeyTap("k", pid int) func KeyTap(tapKey string, args ...interface{}) error {
func KeyTap(key string, args ...interface{}) error {
var keyArr []string var keyArr []string
key, args = appendShift(key, 0, args...)
pid := 0 tapKey = strings.ToLower(tapKey)
if _, ok := Special[tapKey]; ok {
tapKey = Special[tapKey]
if len(args) <= 0 {
args = append(args, "shift")
}
}
if len(args) > 0 { if len(args) > 0 {
if reflect.TypeOf(args[0]) == reflect.TypeOf(keyArr) { if reflect.TypeOf(args[0]) == reflect.TypeOf(keyArr) {
keyArr = args[0].([]string) keyArr = args[0].([]string)
} else {
if reflect.TypeOf(args[0]) == reflect.TypeOf(pid) {
pid = args[0].(int)
keyArr = ToStrings(args[1:])
} else { } else {
keyArr = ToStrings(args) keyArr = ToStrings(args)
} }
} }
return keyTaps(tapKey, keyArr)
} }
return keyTaps(key, keyArr, pid) // KeyToggle toggle the keyboard, if there not have args default is "down"
}
func getToggleArgs(args ...interface{}) (pid int, keyArr []string) {
if len(args) > 0 && reflect.TypeOf(args[0]) == reflect.TypeOf(pid) {
pid = args[0].(int)
keyArr = ToStrings(args[1:])
} else {
keyArr = ToStrings(args)
}
return
}
// KeyToggle toggles the keyboard, if there not have args default is "down"
// //
// See keys: // See keys:
// // https://github.com/go-vgo/robotgo/blob/master/docs/keys.md
// https://github.com/go-vgo/robotgo/blob/master/docs/keys.md#keys
// //
// Examples: // Examples:
//
// robotgo.KeyToggle("a") // robotgo.KeyToggle("a")
// robotgo.KeyToggle("a", "up") // robotgo.KeyToggle("a", "up")
// //
// robotgo.KeyToggle("a", "up", "alt", "cmd") // robotgo.KeyToggle("a", "up", "alt", "cmd")
// robotgo.KeyToggle("k", pid int) //
func KeyToggle(key string, args ...interface{}) error { func KeyToggle(key string, args ...string) error {
key, args = appendShift(key, 1, args...) if len(args) <= 0 {
pid, keyArr := getToggleArgs(args...) args = append(args, "down")
return keyToggles(key, keyArr, pid) }
key = strings.ToLower(key)
if _, ok := Special[key]; ok {
key = Special[key]
if len(args) <= 1 {
args = append(args, "shift")
}
}
return keyToggles(key, args)
} }
// KeyPress press key string // KeyPress press key string
func KeyPress(key string, args ...interface{}) error { func KeyPress(key string, args ...string) error {
err := KeyDown(key, args...) err := KeyDown(key, args...)
if err != nil { if err != nil {
return err return err
@ -580,13 +505,13 @@ func KeyPress(key string, args ...interface{}) error {
} }
// KeyDown press down a key // KeyDown press down a key
func KeyDown(key string, args ...interface{}) error { func KeyDown(key string, args ...string) error {
return KeyToggle(key, args...) return KeyToggle(key, args...)
} }
// KeyUp press up a key // KeyUp press up a key
func KeyUp(key string, args ...interface{}) error { func KeyUp(key string, args ...string) error {
arr := []interface{}{"up"} arr := []string{"up"}
arr = append(arr, args...) arr = append(arr, args...)
return KeyToggle(key, arr...) return KeyToggle(key, arr...)
} }
@ -614,20 +539,10 @@ func CharCodeAt(s string, n int) rune {
return 0 return 0
} }
// UnicodeType tap the uint32 unicode // UnicodeType tap uint32 unicode
func UnicodeType(str uint32, args ...int) { func UnicodeType(str uint32) {
cstr := C.uint(str) cstr := C.uint(str)
pid := 0 C.unicodeType(cstr)
if len(args) > 0 {
pid = args[0]
}
isPid := 0
if len(args) > 1 {
isPid = args[1]
}
C.unicodeType(cstr, C.uintptr(pid), C.int8_t(isPid))
} }
// ToUC trans string to unicode []string // ToUC trans string to unicode []string
@ -658,26 +573,21 @@ func inputUTF(str string) {
C.free(unsafe.Pointer(cstr)) C.free(unsafe.Pointer(cstr))
} }
// TypeStr send a string (supported UTF-8) // TypeStr send a string, support UTF-8
// //
// robotgo.TypeStr(string: "The string to send", int: pid, "milli_sleep time", "x11 option") // robotgo.TypeStr(string: The string to send, int: milli_sleep time, x11 option)
// //
// Examples: // Examples:
// robotgo.TypeStr("abc@123, hi, こんにちは")
// //
// robotgo.TypeStr("abc@123, Hi galaxy, こんにちは")
// robotgo.TypeStr("To be or not to be, this is questions.", pid int)
func TypeStr(str string, args ...int) { func TypeStr(str string, args ...int) {
var tm, tm1 = 0, 7 var tm, tm1 = 0, 7
if len(args) > 1 {
tm = args[1]
}
if len(args) > 2 {
tm1 = args[2]
}
pid := 0
if len(args) > 0 { if len(args) > 0 {
pid = args[0] tm = args[0]
}
if len(args) > 1 {
tm1 = args[1]
} }
if runtime.GOOS == "linux" { if runtime.GOOS == "linux" {
@ -686,7 +596,7 @@ func TypeStr(str string, args ...int) {
ru := []rune(strUc[i]) ru := []rune(strUc[i])
if len(ru) <= 1 { if len(ru) <= 1 {
ustr := uint32(CharCodeAt(strUc[i], 0)) ustr := uint32(CharCodeAt(strUc[i], 0))
UnicodeType(ustr, pid) UnicodeType(ustr)
} else { } else {
inputUTF(strUc[i]) inputUTF(strUc[i])
MilliSleep(tm1) MilliSleep(tm1)
@ -699,7 +609,7 @@ func TypeStr(str string, args ...int) {
for i := 0; i < len([]rune(str)); i++ { for i := 0; i < len([]rune(str)); i++ {
ustr := uint32(CharCodeAt(str, i)) ustr := uint32(CharCodeAt(str, i))
UnicodeType(ustr, pid) UnicodeType(ustr)
// if len(args) > 0 { // if len(args) > 0 {
MilliSleep(tm) MilliSleep(tm)
// } // }
@ -707,7 +617,7 @@ func TypeStr(str string, args ...int) {
MilliSleep(KeySleep) MilliSleep(KeySleep)
} }
// PasteStr paste a string (support UTF-8), // PasteStr paste a string, support UTF-8,
// write the string to clipboard and tap `cmd + v` // write the string to clipboard and tap `cmd + v`
func PasteStr(str string) error { func PasteStr(str string) error {
err := clipboard.WriteAll(str) err := clipboard.WriteAll(str)
@ -722,15 +632,23 @@ func PasteStr(str string) error {
return KeyTap("v", "control") return KeyTap("v", "control")
} }
// TypeStrDelay type string with delayed // TypeStrDelay type string delayed
// And you can use robotgo.KeySleep = 100 to delayed not this function
func TypeStrDelay(str string, delay int) { func TypeStrDelay(str string, delay int) {
TypeStr(str) TypeStr(str)
MilliSleep(delay) MilliSleep(delay)
} }
// SetDelay sets the key and mouse delay // Deprecated: use the TypeStr(),
// robotgo.SetDelay(100) option the robotgo.KeySleep and robotgo.MouseSleep = d //
// TypeStringDelayed type string delayed, Wno-deprecated
//
// This function will be removed in version v1.0.0
func TypeStringDelayed(str string, delay int) {
tt.Drop("TypeStringDelayed", "TypeStrDelay")
TypeStrDelay(str, delay)
}
// SetDelay set the key and mouse delay
func SetDelay(d ...int) { func SetDelay(d ...int) {
v := 10 v := 10
if len(d) > 0 { if len(d) > 0 {

6
key/goKey.h Normal file
View File

@ -0,0 +1,6 @@
// Copyright 2016 The go-vgo Project Developers.
#include <stdlib.h>
#include "../base/types.h"
#include "keypress_c.h"
#include "keycode_c.h"

View File

@ -179,7 +179,7 @@ enum _MMKeyCode {
K_SHIFT = XK_Shift_L, K_SHIFT = XK_Shift_L,
K_LSHIFT = XK_Shift_L, K_LSHIFT = XK_Shift_L,
K_RSHIFT = XK_Shift_R, K_RSHIFT = XK_Shift_R,
K_CAPSLOCK = XK_Caps_Lock, K_CAPSLOCK = XK_Shift_Lock,
K_SPACE = XK_space, K_SPACE = XK_space,
K_INSERT = XK_Insert, K_INSERT = XK_Insert,
K_PRINTSCREEN = XK_Print, K_PRINTSCREEN = XK_Print,

View File

@ -79,19 +79,13 @@ MMKeyCode keyCodeForChar(const char c) {
if (code == NoSymbol) { if (code == NoSymbol) {
return K_NOT_A_KEY; return K_NOT_A_KEY;
} }
// x11 key bug
if (c == 60) {
code = 44;
}
return code; return code;
#endif #endif
} }
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
CFStringRef createStringForKey(CGKeyCode keyCode){ CFStringRef createStringForKey(CGKeyCode keyCode){
// TISInputSourceRef currentKeyboard = TISCopyCurrentASCIICapableKeyboardInputSource(); TISInputSourceRef currentKeyboard = TISCopyCurrentASCIICapableKeyboardInputSource();
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardLayoutInputSource();
CFDataRef layoutData = (CFDataRef) TISGetInputSourceProperty( CFDataRef layoutData = (CFDataRef) TISGetInputSourceProperty(
currentKeyboard, kTISPropertyUnicodeKeyLayoutData); currentKeyboard, kTISPropertyUnicodeKeyLayoutData);

View File

@ -2,10 +2,7 @@
#ifndef KEYPRESS_H #ifndef KEYPRESS_H
#define KEYPRESS_H #define KEYPRESS_H
#include <stdlib.h>
#include "../base/os.h" #include "../base/os.h"
#include "../base/types.h"
#include "keycode.h" #include "keycode.h"
#include <stdbool.h> #include <stdbool.h>
@ -40,7 +37,7 @@
#if defined(IS_WINDOWS) #if defined(IS_WINDOWS)
/* Send win32 key event for given key. */ /* Send win32 key event for given key. */
void win32KeyEvent(int key, MMKeyFlags flags, uintptr pid, int8_t isPid); void win32KeyEvent(int key, MMKeyFlags flags);
#endif #endif
#endif /* KEYPRESS_H */ #endif /* KEYPRESS_H */

View File

@ -1,17 +1,6 @@
// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT #include "keypress.h"
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/robotgo/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#include "../base/deadbeef_rand_c.h" #include "../base/deadbeef_rand_c.h"
#include "../base/microsleep.h" #include "../base/microsleep.h"
#include "keypress.h"
#include "keycode_c.h"
#include <ctype.h> /* For isupper() */ #include <ctype.h> /* For isupper() */
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
@ -25,23 +14,11 @@
/* Convenience wrappers around ugly APIs. */ /* Convenience wrappers around ugly APIs. */
#if defined(IS_WINDOWS) #if defined(IS_WINDOWS)
HWND GetHwndByPid(DWORD dwProcessId); void WIN32_KEY_EVENT_WAIT(MMKeyCode key, DWORD flags) {
win32KeyEvent(key, flags);
HWND getHwnd(uintptr pid, int8_t isPid) {
HWND hwnd = (HWND) pid;
if (isPid == 0) {
hwnd = GetHwndByPid(pid);
}
return hwnd;
}
void WIN32_KEY_EVENT_WAIT(MMKeyCode key, DWORD flags, uintptr pid) {
win32KeyEvent(key, flags, pid, 0);
Sleep(DEADBEEF_RANDRANGE(0, 1)); Sleep(DEADBEEF_RANDRANGE(0, 1));
} }
#elif defined(USE_X11) #elif defined(USE_X11)
Display *XGetMainDisplay(void);
void X_KEY_EVENT(Display *display, MMKeyCode key, bool is_press) { void X_KEY_EVENT(Display *display, MMKeyCode key, bool is_press) {
XTestFakeKeyEvent(display, XKeysymToKeycode(display, key), is_press, CurrentTime); XTestFakeKeyEvent(display, XKeysymToKeycode(display, key), is_press, CurrentTime);
XSync(display, false); XSync(display, false);
@ -54,17 +31,6 @@
#endif #endif
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
int SendTo(uintptr pid, CGEventRef event) {
if (pid != 0) {
CGEventPostToPid(pid, event);
} else {
CGEventPost(kCGHIDEventTap, event);
}
CFRelease(event);
return 0;
}
static io_connect_t _getAuxiliaryKeyDriver(void) { static io_connect_t _getAuxiliaryKeyDriver(void) {
static mach_port_t sEventDrvrRef = 0; static mach_port_t sEventDrvrRef = 0;
mach_port_t masterPort, service, iter; mach_port_t masterPort, service, iter;
@ -87,9 +53,10 @@
} }
return sEventDrvrRef; return sEventDrvrRef;
} }
#elif defined(IS_WINDOWS) #endif
void win32KeyEvent(int key, MMKeyFlags flags, uintptr pid, int8_t isPid) { #if defined(IS_WINDOWS)
void win32KeyEvent(int key, MMKeyFlags flags) {
int scan = MapVirtualKey(key & 0xff, MAPVK_VK_TO_VSC); int scan = MapVirtualKey(key & 0xff, MAPVK_VK_TO_VSC);
/* Set the scan code for extended keys */ /* Set the scan code for extended keys */
@ -132,16 +99,6 @@
} }
} }
// todo: test this
if (pid != 0) {
HWND hwnd = getHwnd(pid, isPid);
int down = (flags == 0 ? WM_KEYDOWN : WM_KEYUP);
// SendMessage(hwnd, down, key, 0);
PostMessageW(hwnd, down, key, 0);
return;
}
/* Set the scan code for keyup */ /* Set the scan code for keyup */
// if ( flags & KEYEVENTF_KEYUP ) { // if ( flags & KEYEVENTF_KEYUP ) {
// scan |= 0x80; // scan |= 0x80;
@ -160,7 +117,7 @@
} }
#endif #endif
void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags, uintptr pid) { void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags) {
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
/* The media keys all have 1000 added to them to help us detect them. */ /* The media keys all have 1000 added to them to help us detect them. */
if (code >= 1000) { if (code >= 1000) {
@ -179,28 +136,25 @@ void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags, uintptr pi
NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE); NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE);
assert(KERN_SUCCESS == kr); assert(KERN_SUCCESS == kr);
} else { } else {
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)code, down);
CGEventRef keyEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)code, down);
assert(keyEvent != NULL); assert(keyEvent != NULL);
CGEventSetType(keyEvent, down ? kCGEventKeyDown : kCGEventKeyUp); CGEventSetType(keyEvent, down ? kCGEventKeyDown : kCGEventKeyUp);
if (flags != 0) { // CGEventSetFlags(keyEvent, flags);
CGEventSetFlags(keyEvent, (CGEventFlags) flags); CGEventSetFlags(keyEvent, (int) flags);
} CGEventPost(kCGSessionEventTap, keyEvent);
CFRelease(keyEvent);
SendTo(pid, keyEvent);
CFRelease(source);
} }
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
const DWORD dwFlags = down ? 0 : KEYEVENTF_KEYUP; const DWORD dwFlags = down ? 0 : KEYEVENTF_KEYUP;
/* Parse modifier keys. */ /* Parse modifier keys. */
if (flags & MOD_META) { WIN32_KEY_EVENT_WAIT(K_META, dwFlags, pid); } if (flags & MOD_META) { WIN32_KEY_EVENT_WAIT(K_META, dwFlags); }
if (flags & MOD_ALT) { WIN32_KEY_EVENT_WAIT(K_ALT, dwFlags, pid); } if (flags & MOD_ALT) { WIN32_KEY_EVENT_WAIT(K_ALT, dwFlags); }
if (flags & MOD_CONTROL) { WIN32_KEY_EVENT_WAIT(K_CONTROL, dwFlags, pid); } if (flags & MOD_CONTROL) { WIN32_KEY_EVENT_WAIT(K_CONTROL, dwFlags); }
if (flags & MOD_SHIFT) { WIN32_KEY_EVENT_WAIT(K_SHIFT, dwFlags, pid); } if (flags & MOD_SHIFT) { WIN32_KEY_EVENT_WAIT(K_SHIFT, dwFlags); }
win32KeyEvent(code, dwFlags, pid, 0); win32KeyEvent(code, dwFlags);
#elif defined(USE_X11) #elif defined(USE_X11)
Display *display = XGetMainDisplay(); Display *display = XGetMainDisplay();
const Bool is_press = down ? True : False; /* Just to be safe. */ const Bool is_press = down ? True : False; /* Just to be safe. */
@ -238,9 +192,14 @@ void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags, uintptr pi
} }
#endif #endif
void toggleKey(char c, const bool down, MMKeyFlags flags, uintptr pid) { void toggleKey(char c, const bool down, MMKeyFlags flags){
MMKeyCode keyCode = keyCodeForChar(c); MMKeyCode keyCode = keyCodeForChar(c);
//Prevent unused variable warning for Mac and Linux.
#if defined(IS_WINDOWS)
int modifiers;
#endif
#if defined(USE_X11) #if defined(USE_X11)
if (toUpper(c) && !(flags & MOD_SHIFT)) { if (toUpper(c) && !(flags & MOD_SHIFT)) {
flags |= MOD_SHIFT; /* Not sure if this is safe for all layouts. */ flags |= MOD_SHIFT; /* Not sure if this is safe for all layouts. */
@ -252,15 +211,14 @@ void toggleKey(char c, const bool down, MMKeyFlags flags, uintptr pid) {
#endif #endif
#if defined(IS_WINDOWS) #if defined(IS_WINDOWS)
int modifiers = keyCode >> 8; // Pull out modifers. modifiers = keyCode >> 8; // Pull out modifers.
if ((modifiers & 1) != 0) { flags |= MOD_SHIFT; } // Uptdate flags from keycode modifiers. if ((modifiers & 1) != 0) { flags |= MOD_SHIFT; } // Uptdate flags from keycode modifiers.
if ((modifiers & 2) != 0) { flags |= MOD_CONTROL; } if ((modifiers & 2) != 0) { flags |= MOD_CONTROL; }
if ((modifiers & 4) != 0) { flags |= MOD_ALT; } if ((modifiers & 4) != 0) { flags |= MOD_ALT; }
keyCode = keyCode & 0xff; // Mask out modifiers. keyCode = keyCode & 0xff; // Mask out modifiers.
#endif #endif
toggleKeyCode(keyCode, down, flags, pid); toggleKeyCode(keyCode, down, flags);
} }
// void tapKey(char c, MMKeyFlags flags){ // void tapKey(char c, MMKeyFlags flags){
@ -270,13 +228,12 @@ void toggleKey(char c, const bool down, MMKeyFlags flags, uintptr pid) {
// } // }
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
void toggleUnicode(UniChar ch, const bool down, uintptr pid) { void toggleUnicode(UniChar ch, const bool down) {
/* This function relies on the convenient CGEventKeyboardSetUnicodeString(), /* This function relies on the convenient CGEventKeyboardSetUnicodeString(),
convert characters to a keycode, but does not support adding modifier flags. convert characters to a keycode, but does not support adding modifier flags.
It is only used in typeString(). It is only used in typeString().
-- if you need modifier keys, use the above functions instead. */ -- if you need modifier keys, use the above functions instead. */
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, 0, down);
CGEventRef keyEvent = CGEventCreateKeyboardEvent(source, 0, down);
if (keyEvent == NULL) { if (keyEvent == NULL) {
fputs("Could not create keyboard event.\n", stderr); fputs("Could not create keyboard event.\n", stderr);
return; return;
@ -284,52 +241,14 @@ void toggleKey(char c, const bool down, MMKeyFlags flags, uintptr pid) {
CGEventKeyboardSetUnicodeString(keyEvent, 1, &ch); CGEventKeyboardSetUnicodeString(keyEvent, 1, &ch);
SendTo(pid, keyEvent); CGEventPost(kCGSessionEventTap, keyEvent);
CFRelease(source); CFRelease(keyEvent);
} }
#else
#define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE, 0)
#endif #endif
// unicode type
void unicodeType(const unsigned value, uintptr pid, int8_t isPid) {
#if defined(IS_MACOSX)
UniChar ch = (UniChar)value; // Convert to unsigned char
toggleUnicode(ch, true, pid);
microsleep(5.0);
toggleUnicode(ch, false, pid);
#elif defined(IS_WINDOWS)
if (pid != 0) {
HWND hwnd = getHwnd(pid, isPid);
// SendMessage(hwnd, down, value, 0);
PostMessageW(hwnd, WM_CHAR, value, 0);
return;
}
INPUT input[2];
memset(input, 0, sizeof(input));
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = 0;
input[0].ki.wScan = value;
input[0].ki.dwFlags = 0x4; // KEYEVENTF_UNICODE;
input[1].type = INPUT_KEYBOARD;
input[1].ki.wVk = 0;
input[1].ki.wScan = value;
input[1].ki.dwFlags = KEYEVENTF_KEYUP | 0x4; // KEYEVENTF_UNICODE;
SendInput(2, input, sizeof(INPUT));
#elif defined(USE_X11)
toggleUniKey(value, true);
microsleep(5.0);
toggleUniKey(value, false);
#endif
}
#if defined(USE_X11) #if defined(USE_X11)
#define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE)
int input_utf(const char *utf) { int input_utf(const char *utf) {
Display *dpy = XOpenDisplay(NULL); Display *dpy = XOpenDisplay(NULL);
KeySym sym = XStringToKeysym(utf); KeySym sym = XStringToKeysym(utf);
@ -352,8 +271,39 @@ void unicodeType(const unsigned value, uintptr pid, int8_t isPid) {
XCloseDisplay(dpy); XCloseDisplay(dpy);
return 0; return 0;
} }
#else #endif
#if !defined(USE_X11)
int input_utf(const char *utf){ int input_utf(const char *utf){
return 0; return 0;
} }
#endif #endif
// unicode type
void unicodeType(const unsigned value){
#if defined(IS_MACOSX)
UniChar ch = (UniChar)value; // Convert to unsigned char
toggleUnicode(ch, true);
microsleep(5.0);
toggleUnicode(ch, false);
#elif defined(IS_WINDOWS)
INPUT input[2];
memset(input, 0, sizeof(input));
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = 0;
input[0].ki.wScan = value;
input[0].ki.dwFlags = 0x4; // KEYEVENTF_UNICODE;
input[1].type = INPUT_KEYBOARD;
input[1].ki.wVk = 0;
input[1].ki.wScan = value;
input[1].ki.dwFlags = KEYEVENTF_KEYUP | 0x4; // KEYEVENTF_UNICODE;
SendInput(2, input, sizeof(INPUT));
#elif defined(USE_X11)
toggleUniKey(value, true);
microsleep(5.0);
toggleUniKey(value, false);
#endif
}

View File

@ -83,43 +83,57 @@
/* Move the mouse to a specific point. */ /* Move the mouse to a specific point. */
void moveMouse(MMPointInt32 point){ void moveMouse(MMPointInt32 point){
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); CGEventRef move = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved,
CGEventRef move = CGEventCreateMouseEvent(source, kCGEventMouseMoved,
CGPointFromMMPointInt32(point), kCGMouseButtonLeft); CGPointFromMMPointInt32(point), kCGMouseButtonLeft);
calculateDeltas(&move, point); calculateDeltas(&move, point);
CGEventPost(kCGHIDEventTap, move); CGEventPost(kCGSessionEventTap, move);
CFRelease(move); CFRelease(move);
CFRelease(source);
#elif defined(USE_X11) #elif defined(USE_X11)
Display *display = XGetMainDisplay(); Display *display = XGetMainDisplay();
XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, point.x, point.y); XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, point.x, point.y);
XSync(display, false); XSync(display, false);
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
SetCursorPos(point.x, point.y); // Mouse motion is now done using SendInput with MOUSEINPUT.
// We use Absolute mouse positioning
#define MOUSE_COORD_TO_ABS(coord, width_or_height) ( \
((65536 * coord) / width_or_height) + (coord < 0 ? -1 : 1))
MMRectInt32 rect = getScreenRect(-1);
int32_t x = MOUSE_COORD_TO_ABS(point.x - rect.origin.x, rect.size.w);
int32_t y = MOUSE_COORD_TO_ABS(point.y - rect.origin.y, rect.size.h);
INPUT mouseInput;
mouseInput.type = INPUT_MOUSE;
mouseInput.mi.dx = x;
mouseInput.mi.dy = y;
mouseInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK;
mouseInput.mi.time = 0; // System will provide the timestamp
mouseInput.mi.dwExtraInfo = 0;
mouseInput.mi.mouseData = 0;
SendInput(1, &mouseInput, sizeof(mouseInput));
#endif #endif
} }
void dragMouse(MMPointInt32 point, const MMMouseButton button){ void dragMouse(MMPointInt32 point, const MMMouseButton button){
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
const CGEventType dragType = MMMouseDragToCGEventType(button); const CGEventType dragType = MMMouseDragToCGEventType(button);
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); CGEventRef drag = CGEventCreateMouseEvent(NULL, dragType,
CGEventRef drag = CGEventCreateMouseEvent(source, dragType,
CGPointFromMMPointInt32(point), (CGMouseButton)button); CGPointFromMMPointInt32(point), (CGMouseButton)button);
calculateDeltas(&drag, point); calculateDeltas(&drag, point);
CGEventPost(kCGHIDEventTap, drag); CGEventPost(kCGSessionEventTap, drag);
CFRelease(drag); CFRelease(drag);
CFRelease(source);
#else #else
moveMouse(point); moveMouse(point);
#endif #endif
} }
MMPointInt32 location() { MMPointInt32 getMousePos() {
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
CGEventRef event = CGEventCreate(NULL); CGEventRef event = CGEventCreate(NULL);
CGPoint point = CGEventGetLocation(event); CGPoint point = CGEventGetLocation(event);
@ -147,14 +161,12 @@ MMPointInt32 location() {
/* Press down a button, or release it. */ /* Press down a button, or release it. */
void toggleMouse(bool down, MMMouseButton button) { void toggleMouse(bool down, MMMouseButton button) {
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
const CGPoint currentPos = CGPointFromMMPointInt32(location()); const CGPoint currentPos = CGPointFromMMPointInt32(getMousePos());
const CGEventType mouseType = MMMouseToCGEventType(down, button); const CGEventType mouseType = MMMouseToCGEventType(down, button);
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); CGEventRef event = CGEventCreateMouseEvent(NULL, mouseType, currentPos, (CGMouseButton)button);
CGEventRef event = CGEventCreateMouseEvent(source, mouseType, currentPos, (CGMouseButton)button);
CGEventPost(kCGHIDEventTap, event); CGEventPost(kCGSessionEventTap, event);
CFRelease(event); CFRelease(event);
CFRelease(source);
#elif defined(USE_X11) #elif defined(USE_X11)
Display *display = XGetMainDisplay(); Display *display = XGetMainDisplay();
XTestFakeButtonEvent(display, button, down ? True : False, CurrentTime); XTestFakeButtonEvent(display, button, down ? True : False, CurrentTime);
@ -180,16 +192,15 @@ void clickMouse(MMMouseButton button){
toggleMouse(false, button); toggleMouse(false, button);
} }
/* Special function for sending double clicks, needed for MacOS. */ /* Special function for sending double clicks, needed for Mac OS X. */
void doubleClick(MMMouseButton button){ void doubleClick(MMMouseButton button){
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
/* Double click for Mac. */ /* Double click for Mac. */
const CGPoint currentPos = CGPointFromMMPointInt32(location()); const CGPoint currentPos = CGPointFromMMPointInt32(getMousePos());
const CGEventType mouseTypeDown = MMMouseToCGEventType(true, button); const CGEventType mouseTypeDown = MMMouseToCGEventType(true, button);
const CGEventType mouseTypeUP = MMMouseToCGEventType(false, button); const CGEventType mouseTypeUP = MMMouseToCGEventType(false, button);
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); CGEventRef event = CGEventCreateMouseEvent(NULL, mouseTypeDown, currentPos, kCGMouseButtonLeft);
CGEventRef event = CGEventCreateMouseEvent(source, mouseTypeDown, currentPos, kCGMouseButtonLeft);
/* Set event to double click. */ /* Set event to double click. */
CGEventSetIntegerValueField(event, kCGMouseEventClickState, 2); CGEventSetIntegerValueField(event, kCGMouseEventClickState, 2);
@ -199,7 +210,6 @@ void doubleClick(MMMouseButton button){
CGEventPost(kCGHIDEventTap, event); CGEventPost(kCGHIDEventTap, event);
CFRelease(event); CFRelease(event);
CFRelease(source);
#else #else
/* Double click for everything else. */ /* Double click for everything else. */
clickMouse(button); clickMouse(button);
@ -216,20 +226,25 @@ void scrollMouseXY(int x, int y) {
INPUT mouseScrollInputV; INPUT mouseScrollInputV;
#endif #endif
#if defined(IS_MACOSX) /* Direction should only be considered based on the scrollDirection. This Should not interfere. */
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); /* Set up the OS specific solution */
CGEventRef event = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitPixel, 2, y, x); #if defined(__APPLE__)
CGEventRef event;
event = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 2, y, x);
CGEventPost(kCGHIDEventTap, event); CGEventPost(kCGHIDEventTap, event);
CFRelease(event); CFRelease(event);
CFRelease(source);
#elif defined(USE_X11) #elif defined(USE_X11)
int ydir = 4; /* Button 4 is up, 5 is down. */ int ydir = 4; /* Button 4 is up, 5 is down. */
int xdir = 6; int xdir = 6;
Display *display = XGetMainDisplay(); Display *display = XGetMainDisplay();
if (y < 0) { ydir = 5; } if (y < 0) {
if (x < 0) { xdir = 7; } ydir = 5;
}
if (x < 0) {
xdir = 7;
}
int xi; int yi; int xi; int yi;
for (xi = 0; xi < abs(x); xi++) { for (xi = 0; xi < abs(x); xi++) {
@ -283,8 +298,8 @@ static double crude_hypot(double x, double y){
} }
bool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed){ bool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed){
MMPointInt32 pos = location(); MMPointInt32 pos = getMousePos();
// MMSizeInt32 screenSize = getMainDisplaySize(); MMSizeInt32 screenSize = getMainDisplaySize();
double velo_x = 0.0, velo_y = 0.0; double velo_x = 0.0, velo_y = 0.0;
double distance; double distance;
@ -304,9 +319,9 @@ bool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed)
pos.y += floor(velo_y + 0.5); pos.y += floor(velo_y + 0.5);
/* Make sure we are in the screen boundaries! (Strange things will happen if we are not.) */ /* Make sure we are in the screen boundaries! (Strange things will happen if we are not.) */
// if (pos.x >= screenSize.w || pos.y >= screenSize.h) { if (pos.x >= screenSize.w || pos.y >= screenSize.h) {
// return false; return false;
// } }
moveMouse(pos); moveMouse(pos);
/* Wait 1 - 3 milliseconds. */ /* Wait 1 - 3 milliseconds. */

14
ps.go
View File

@ -14,17 +14,17 @@ import ps "github.com/vcaesar/gops"
// Nps process struct // Nps process struct
type Nps struct { type Nps struct {
Pid int Pid int32
Name string Name string
} }
// Pids get the all process id // Pids get the all process id
func Pids() ([]int, error) { func Pids() ([]int32, error) {
return ps.Pids() return ps.Pids()
} }
// PidExists determine whether the process exists // PidExists determine whether the process exists
func PidExists(pid int) (bool, error) { func PidExists(pid int32) (bool, error) {
return ps.PidExists(pid) return ps.PidExists(pid)
} }
@ -45,7 +45,7 @@ func Process() ([]Nps, error) {
} }
// FindName find the process name by the process id // FindName find the process name by the process id
func FindName(pid int) (string, error) { func FindName(pid int32) (string, error) {
return ps.FindName(pid) return ps.FindName(pid)
} }
@ -57,12 +57,12 @@ func FindNames() ([]string, error) {
// FindIds finds the all processes named with a subset // FindIds finds the all processes named with a subset
// of "name" (case insensitive), // of "name" (case insensitive),
// return matched IDs. // return matched IDs.
func FindIds(name string) ([]int, error) { func FindIds(name string) ([]int32, error) {
return ps.FindIds(name) return ps.FindIds(name)
} }
// FindPath find the process path by the process pid // FindPath find the process path by the process pid
func FindPath(pid int) (string, error) { func FindPath(pid int32) (string, error) {
return ps.FindPath(pid) return ps.FindPath(pid)
} }
@ -72,6 +72,6 @@ func Run(path string) ([]byte, error) {
} }
// Kill kill the process by PID // Kill kill the process by PID
func Kill(pid int) error { func Kill(pid int32) error {
return ps.Kill(pid) return ps.Kill(pid)
} }

View File

@ -33,9 +33,6 @@ func TestGetScreenSize(t *testing.T) {
rect := robotgo.GetScreenRect() rect := robotgo.GetScreenRect()
fmt.Println("Get screen rect: ", rect) fmt.Println("Get screen rect: ", rect)
x, y = robotgo.Location()
fmt.Println("Get location: ", x, y)
} }
func TestGetSysScale(t *testing.T) { func TestGetSysScale(t *testing.T) {
@ -43,13 +40,5 @@ func TestGetSysScale(t *testing.T) {
log.Println("SysScale: ", s) log.Println("SysScale: ", s)
f := robotgo.ScaleF() f := robotgo.ScaleF()
log.Println("scale: ", f) log.Println("sclae: ", f)
}
func TestGetTitle(t *testing.T) {
// just exercise the function, it used to crash with a segfault + "Maximum
// number of clients reached"
for i := 0; i < 128; i++ {
robotgo.GetTitle()
}
} }

View File

@ -9,34 +9,28 @@
// except according to those terms. // except according to those terms.
/* /*
Package robotgo Go native cross-platform system automation. Package robotgo Go native cross-platform system automation.
Please make sure Golang, GCC is installed correctly before installing RobotGo; Please make sure Golang, GCC is installed correctly before installing RobotGo;
See Requirements: See Requirements:
https://github.com/go-vgo/robotgo#requirements https://github.com/go-vgo/robotgo#requirements
Installation: Installation:
With Go module support (Go 1.11+), just import: With Go module support (Go 1.11+), just import:
import "github.com/go-vgo/robotgo" import "github.com/go-vgo/robotgo"
Otherwise, to install the robotgo package, run the command: Otherwise, to install the robotgo package, run the command:
go get -u github.com/go-vgo/robotgo go get -u github.com/go-vgo/robotgo
*/ */
package robotgo package robotgo
/* /*
#cgo darwin CFLAGS: -x objective-c -Wno-deprecated-declarations #cgo darwin CFLAGS: -x objective-c -Wno-deprecated-declarations
#cgo darwin LDFLAGS: -framework Cocoa -framework CoreFoundation -framework IOKit #cgo darwin LDFLAGS: -framework Cocoa -framework OpenGL -framework IOKit
#cgo darwin LDFLAGS: -framework Carbon -framework OpenGL #cgo darwin LDFLAGS: -framework Carbon -framework CoreFoundation
//
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 140400
#cgo darwin LDFLAGS: -framework ScreenCaptureKit
#endif
#cgo linux CFLAGS: -I/usr/src #cgo linux CFLAGS: -I/usr/src
#cgo linux LDFLAGS: -L/usr/src -lm -lX11 -lXtst #cgo linux LDFLAGS: -L/usr/src -lm -lX11 -lXtst
@ -50,7 +44,6 @@ package robotgo
import "C" import "C"
import ( import (
"errors"
"image" "image"
"runtime" "runtime"
"time" "time"
@ -73,15 +66,10 @@ var (
// MouseSleep set the mouse default millisecond sleep time // MouseSleep set the mouse default millisecond sleep time
MouseSleep = 0 MouseSleep = 0
// KeySleep set the key default millisecond sleep time // KeySleep set the key default millisecond sleep time
KeySleep = 10 KeySleep = 0
// DisplayID set the screen display id // DisplayID set the screen display id
DisplayID = -1 DisplayID = -1
// NotPid used the hwnd not pid in windows
NotPid bool
// Scale option the os screen scale
Scale bool
) )
type ( type (
@ -91,15 +79,9 @@ type (
CHex C.MMRGBHex CHex C.MMRGBHex
// CBitmap define CBitmap as C.MMBitmapRef type // CBitmap define CBitmap as C.MMBitmapRef type
CBitmap C.MMBitmapRef CBitmap C.MMBitmapRef
// Handle define window Handle as C.MData type
Handle C.MData
) )
// Bitmap define the go Bitmap struct // Bitmap is Bitmap struct
//
// The common type conversion of bitmap:
//
// https://github.com/go-vgo/robotgo/blob/master/docs/keys.md#type-conversion
type Bitmap struct { type Bitmap struct {
ImgBuf *uint8 ImgBuf *uint8
Width, Height int Width, Height int
@ -227,9 +209,9 @@ func GetPixelColor(x, y int, displayId ...int) string {
return PadHex(GetPxColor(x, y, displayId...)) return PadHex(GetPxColor(x, y, displayId...))
} }
// GetLocationColor get the location pos's color // GetMouseColor get the mouse pos's color
func GetLocationColor(displayId ...int) string { func GetMouseColor(displayId ...int) string {
x, y := Location() x, y := GetMousePos()
return GetPixelColor(x, y, displayId...) return GetPixelColor(x, y, displayId...)
} }
@ -254,11 +236,6 @@ func getNumDisplays() int {
return int(C.get_num_displays()) return int(C.get_num_displays())
} }
// GetHWNDByPid get the hwnd by pid
func GetHWNDByPid(pid int) int {
return int(C.get_hwnd_by_pid(C.uintptr(pid)))
}
// SysScale get the sys scale // SysScale get the sys scale
func SysScale(displayId ...int) float64 { func SysScale(displayId ...int) float64 {
display := displayIdx(displayId...) display := displayIdx(displayId...)
@ -266,7 +243,7 @@ func SysScale(displayId ...int) float64 {
return float64(s) return float64(s)
} }
// Scaled get the screen scaled return scale size // Scaled get the screen scaled size
func Scaled(x int, displayId ...int) int { func Scaled(x int, displayId ...int) int {
f := ScaleF(displayId...) f := ScaleF(displayId...)
return Scaled0(x, f) return Scaled0(x, f)
@ -277,11 +254,6 @@ func Scaled0(x int, f float64) int {
return int(float64(x) * f) return int(float64(x) * f)
} }
// Scaled1 return int(x / f)
func Scaled1(x int, f float64) int {
return int(float64(x) / f)
}
// GetScreenSize get the screen size // GetScreenSize get the screen size
func GetScreenSize() (int, int) { func GetScreenSize() (int, int) {
size := C.getMainDisplaySize() size := C.getMainDisplaySize()
@ -300,8 +272,7 @@ func GetScreenRect(displayId ...int) Rect {
int(rect.size.w), int(rect.size.h) int(rect.size.w), int(rect.size.h)
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
// f := ScaleF(displayId...) f := ScaleF(displayId...)
f := ScaleF()
x, y, w, h = Scaled0(x, f), Scaled0(y, f), Scaled0(w, f), Scaled0(h, f) x, y, w, h = Scaled0(x, f), Scaled0(y, f), Scaled0(w, f), Scaled0(h, f)
} }
return Rect{ return Rect{
@ -340,21 +311,13 @@ func CaptureScreen(args ...int) CBitmap {
} else { } else {
// Get the main screen rect. // Get the main screen rect.
rect := GetScreenRect(displayId) rect := GetScreenRect(displayId)
if runtime.GOOS == "windows" { // x = C.int32_t(rect.X)
x = C.int32_t(rect.X) // y = C.int32_t(rect.Y)
y = C.int32_t(rect.Y)
}
w = C.int32_t(rect.W) w = C.int32_t(rect.W)
h = C.int32_t(rect.H) h = C.int32_t(rect.H)
} }
isPid := 0 bit := C.capture_screen(x, y, w, h, C.int32_t(displayId))
if NotPid || len(args) > 5 {
isPid = 1
}
bit := C.capture_screen(x, y, w, h, C.int32_t(displayId), C.int8_t(isPid))
return CBitmap(bit) return CBitmap(bit)
} }
@ -366,15 +329,12 @@ func CaptureGo(args ...int) Bitmap {
return ToBitmap(bit) return ToBitmap(bit)
} }
// CaptureImg capture the screen and return image.Image, error // CaptureImg capture the screen and return image.Image
func CaptureImg(args ...int) (image.Image, error) { func CaptureImg(args ...int) image.Image {
bit := CaptureScreen(args...) bit := CaptureScreen(args...)
if bit == nil {
return nil, errors.New("Capture image not found.")
}
defer FreeBitmap(bit) defer FreeBitmap(bit)
return ToImage(bit), nil return ToImage(bit)
} }
// FreeBitmap free and dealloc the C bitmap // FreeBitmap free and dealloc the C bitmap
@ -463,11 +423,6 @@ func GetXDisplayName() string {
return gname return gname
} }
// CloseMainDisplay close the main X11 display
func CloseMainDisplay() {
C.close_main_display()
}
// Deprecated: use the ScaledF(), // Deprecated: use the ScaledF(),
// //
// ScaleX get the primary display horizontal DPI scale factor, drop // ScaleX get the primary display horizontal DPI scale factor, drop
@ -475,6 +430,45 @@ func ScaleX() int {
return int(C.scaleX()) return int(C.scaleX())
} }
// Deprecated: use the ScaledF(),
//
// Scale get the screen scale (only windows old), drop
func Scale() int {
dpi := map[int]int{
0: 100,
// DPI Scaling Level
96: 100,
120: 125,
144: 150,
168: 175,
192: 200,
216: 225,
// Custom DPI
240: 250,
288: 300,
384: 400,
480: 500,
}
x := ScaleX()
return dpi[x]
}
// Deprecated: use the ScaledF(),
//
// Scale0 return ScaleX() / 0.96, drop
func Scale0() int {
return int(float64(ScaleX()) / 0.96)
}
// Deprecated: use the ScaledF(),
//
// Mul mul the scale, drop
func Mul(x int) int {
s := Scale()
return x * s / 100
}
/* /*
.___ ___. ______ __ __ _______. _______ .___ ___. ______ __ __ _______. _______
| \/ | / __ \ | | | | / || ____| | \/ | / __ \ | | | | / || ____|
@ -504,24 +498,23 @@ func CheckMouse(btn string) C.MMMouseButton {
return C.LEFT_BUTTON return C.LEFT_BUTTON
} }
// MoveScale calculate the os scale factor x, y // Deprecated: use the Move(),
func MoveScale(x, y int, displayId ...int) (int, int) { //
if Scale || runtime.GOOS == "windows" { // MoveMouse move the mouse
f := ScaleF() func MoveMouse(x, y int) {
x, y = Scaled1(x, f), Scaled1(y, f) Move(x, y)
}
return x, y
} }
// Move move the mouse to (x, y) // Move move the mouse to (x, y)
// //
// Examples: // Examples:
//
// robotgo.MouseSleep = 100 // 100 millisecond // robotgo.MouseSleep = 100 // 100 millisecond
// robotgo.Move(10, 10) // robotgo.Move(10, 10)
func Move(x, y int, displayId ...int) { func Move(x, y int) {
x, y = MoveScale(x, y, displayId...) // if runtime.GOOS == "windows" {
// f := ScaleF()
// x, y = Scaled0(x, f), Scaled0(y, f)
// }
cx := C.int32_t(x) cx := C.int32_t(x)
cy := C.int32_t(y) cy := C.int32_t(y)
@ -530,13 +523,23 @@ func Move(x, y int, displayId ...int) {
MilliSleep(MouseSleep) MilliSleep(MouseSleep)
} }
// Deprecated: use the DragSmooth(),
//
// DragMouse drag the mouse to (x, y),
// It's same with the DragSmooth() now
func DragMouse(x, y int, args ...interface{}) {
Toggle("left")
MilliSleep(50)
// Drag(x, y, args...)
MoveSmooth(x, y, args...)
Toggle("left", "up")
}
// Deprecated: use the DragSmooth(), // Deprecated: use the DragSmooth(),
// //
// Drag drag the mouse to (x, y), // Drag drag the mouse to (x, y),
// It's not valid now, use the DragSmooth() // It's not valid now, use the DragSmooth()
func Drag(x, y int, args ...string) { func Drag(x, y int, args ...string) {
x, y = MoveScale(x, y)
var button C.MMMouseButton = C.LEFT_BUTTON var button C.MMMouseButton = C.LEFT_BUTTON
cx := C.int32_t(x) cx := C.int32_t(x)
cy := C.int32_t(y) cy := C.int32_t(y)
@ -552,7 +555,6 @@ func Drag(x, y int, args ...string) {
// DragSmooth drag the mouse like smooth to (x, y) // DragSmooth drag the mouse like smooth to (x, y)
// //
// Examples: // Examples:
//
// robotgo.DragSmooth(10, 10) // robotgo.DragSmooth(10, 10)
func DragSmooth(x, y int, args ...interface{}) { func DragSmooth(x, y int, args ...interface{}) {
Toggle("left") Toggle("left")
@ -561,13 +563,20 @@ func DragSmooth(x, y int, args ...interface{}) {
Toggle("left", "up") Toggle("left", "up")
} }
// Deprecated: use the MoveSmooth(),
//
// MoveMouseSmooth move the mouse smooth,
// moves mouse to x, y human like, with the mouse button up.
func MoveMouseSmooth(x, y int, args ...interface{}) bool {
return MoveSmooth(x, y, args...)
}
// MoveSmooth move the mouse smooth, // MoveSmooth move the mouse smooth,
// moves mouse to x, y human like, with the mouse button up. // moves mouse to x, y human like, with the mouse button up.
// //
// robotgo.MoveSmooth(x, y int, low, high float64, mouseDelay int) // robotgo.MoveSmooth(x, y int, low, high float64, mouseDelay int)
// //
// Examples: // Examples:
//
// robotgo.MoveSmooth(10, 10) // robotgo.MoveSmooth(10, 10)
// robotgo.MoveSmooth(10, 10, 1.0, 2.0) // robotgo.MoveSmooth(10, 10, 1.0, 2.0)
func MoveSmooth(x, y int, args ...interface{}) bool { func MoveSmooth(x, y int, args ...interface{}) bool {
@ -575,7 +584,6 @@ func MoveSmooth(x, y int, args ...interface{}) bool {
// f := ScaleF() // f := ScaleF()
// x, y = Scaled0(x, f), Scaled0(y, f) // x, y = Scaled0(x, f), Scaled0(y, f)
// } // }
x, y = MoveScale(x, y)
cx := C.int32_t(x) cx := C.int32_t(x)
cy := C.int32_t(y) cy := C.int32_t(y)
@ -606,7 +614,7 @@ func MoveSmooth(x, y int, args ...interface{}) bool {
// MoveArgs get the mouse relative args // MoveArgs get the mouse relative args
func MoveArgs(x, y int) (int, int) { func MoveArgs(x, y int) (int, int) {
mx, my := Location() mx, my := GetMousePos()
mx = mx + x mx = mx + x
my = my + y my = my + y
@ -624,18 +632,22 @@ func MoveSmoothRelative(x, y int, args ...interface{}) {
MoveSmooth(mx, my, args...) MoveSmooth(mx, my, args...)
} }
// Location get the mouse location position return x, y // GetMousePos get the mouse's position return x, y
func Location() (int, int) { func GetMousePos() (int, int) {
pos := C.location() pos := C.getMousePos()
x := int(pos.x) x := int(pos.x)
y := int(pos.y) y := int(pos.y)
if Scale || runtime.GOOS == "windows" { return x, y
f := ScaleF()
x, y = Scaled0(x, f), Scaled0(y, f)
} }
return x, y // Deprecated: use the Click(),
//
// MouseClick click the mouse
//
// robotgo.MouseClick(button string, double bool)
func MouseClick(args ...interface{}) {
Click(args...)
} }
// Click click the mouse button // Click click the mouse button
@ -643,7 +655,6 @@ func Location() (int, int) {
// robotgo.Click(button string, double bool) // robotgo.Click(button string, double bool)
// //
// Examples: // Examples:
//
// robotgo.Click() // default is left button // robotgo.Click() // default is left button
// robotgo.Click("right") // robotgo.Click("right")
// robotgo.Click("wheelLeft") // robotgo.Click("wheelLeft")
@ -675,7 +686,6 @@ func Click(args ...interface{}) {
// robotgo.MoveClick(x, y int, button string, double bool) // robotgo.MoveClick(x, y int, button string, double bool)
// //
// Examples: // Examples:
//
// robotgo.MouseSleep = 100 // robotgo.MouseSleep = 100
// robotgo.MoveClick(10, 10) // robotgo.MoveClick(10, 10)
func MoveClick(x, y int, args ...interface{}) { func MoveClick(x, y int, args ...interface{}) {
@ -694,39 +704,35 @@ func MovesClick(x, y int, args ...interface{}) {
} }
// Toggle toggle the mouse, support button: // Toggle toggle the mouse, support button:
//
// "left", "center", "right", // "left", "center", "right",
// "wheelDown", "wheelUp", "wheelLeft", "wheelRight" // "wheelDown", "wheelUp", "wheelLeft", "wheelRight"
// //
// Examples: // Examples:
//
// robotgo.Toggle("left") // default is down // robotgo.Toggle("left") // default is down
// robotgo.Toggle("left", "up") // robotgo.Toggle("left", "up")
func Toggle(key ...interface{}) error { func Toggle(key ...string) error {
var button C.MMMouseButton = C.LEFT_BUTTON var button C.MMMouseButton = C.LEFT_BUTTON
if len(key) > 0 { if len(key) > 0 {
button = CheckMouse(key[0].(string)) button = CheckMouse(key[0])
} }
down := true down := true
if len(key) > 1 && key[1].(string) == "up" { if len(key) > 1 && key[1] == "up" {
down = false down = false
} }
C.toggleMouse(C.bool(down), button) C.toggleMouse(C.bool(down), button)
if len(key) > 2 {
MilliSleep(MouseSleep) MilliSleep(MouseSleep)
}
return nil return nil
} }
// MouseDown send mouse down event // MouseDown send mouse down event
func MouseDown(key ...interface{}) error { func MouseDown(key ...string) error {
return Toggle(key...) return Toggle(key...)
} }
// MouseUp send mouse up event // MouseUp send mouse up event
func MouseUp(key ...interface{}) error { func MouseUp(key ...string) error {
if len(key) <= 0 { if len(key) <= 0 {
key = append(key, "left") key = append(key, "left")
} }
@ -738,7 +744,6 @@ func MouseUp(key ...interface{}) error {
// robotgo.Scroll(x, y, msDelay int) // robotgo.Scroll(x, y, msDelay int)
// //
// Examples: // Examples:
//
// robotgo.Scroll(10, 10) // robotgo.Scroll(10, 10)
func Scroll(x, y int, args ...int) { func Scroll(x, y int, args ...int) {
var msDelay = 10 var msDelay = 10
@ -753,17 +758,16 @@ func Scroll(x, y int, args ...int) {
MilliSleep(MouseSleep + msDelay) MilliSleep(MouseSleep + msDelay)
} }
// ScrollDir scroll the mouse with direction to (x, "up") // ScrollMouse scroll the mouse to (x, "up")
// supported: "up", "down", "left", "right" // supported: "up", "down", "left", "right"
// //
// Examples: // Examples:
// // robotgo.ScrollMouse(10, "down")
// robotgo.ScrollDir(10, "down") // robotgo.ScrollMouse(10, "up")
// robotgo.ScrollDir(10, "up") func ScrollMouse(x int, direction ...string) {
func ScrollDir(x int, direction ...interface{}) {
d := "down" d := "down"
if len(direction) > 0 { if len(direction) > 0 {
d = direction[0].(string) d = direction[0]
} }
if d == "down" { if d == "down" {
@ -788,7 +792,6 @@ func ScrollDir(x int, direction ...interface{}) {
// robotgo.ScrollSmooth(toy, num, sleep, tox) // robotgo.ScrollSmooth(toy, num, sleep, tox)
// //
// Examples: // Examples:
//
// robotgo.ScrollSmooth(-10) // robotgo.ScrollSmooth(-10)
// robotgo.ScrollSmooth(-10, 6, 200, -10) // robotgo.ScrollSmooth(-10, 6, 200, -10)
func ScrollSmooth(to int, args ...int) { func ScrollSmooth(to int, args ...int) {
@ -820,7 +823,6 @@ func ScrollSmooth(to int, args ...int) {
// ScrollRelative scroll mouse with relative // ScrollRelative scroll mouse with relative
// //
// Examples: // Examples:
//
// robotgo.ScrollRelative(10, 10) // robotgo.ScrollRelative(10, 10)
func ScrollRelative(x, y int, args ...int) { func ScrollRelative(x, y int, args ...int) {
mx, my := MoveArgs(x, y) mx, my := MoveArgs(x, y)
@ -881,77 +883,67 @@ func IsValid() bool {
} }
// SetActive set the window active // SetActive set the window active
func SetActive(win Handle) { func SetActive(win C.MData) {
SetActiveC(C.MData(win))
}
// SetActiveC set the window active
func SetActiveC(win C.MData) {
C.set_active(win) C.set_active(win)
} }
// GetActive get the active window // GetActive get the active window
func GetActive() Handle { func GetActive() C.MData {
return Handle(GetActiveC())
}
// GetActiveC get the active window
func GetActiveC() C.MData {
mdata := C.get_active() mdata := C.get_active()
// fmt.Println("active----", mdata) // fmt.Println("active----", mdata)
return mdata return mdata
} }
// MinWindow set the window min // MinWindow set the window min
func MinWindow(pid int, args ...interface{}) { func MinWindow(pid int32, args ...interface{}) {
var ( var (
state = true state = true
isPid int hwnd int
) )
if len(args) > 0 { if len(args) > 0 {
state = args[0].(bool) state = args[0].(bool)
} }
if len(args) > 1 || NotPid { if len(args) > 1 {
isPid = 1 hwnd = args[1].(int)
} }
C.min_window(C.uintptr(pid), C.bool(state), C.int8_t(isPid)) C.min_window(C.uintptr(pid), C.bool(state), C.uintptr(hwnd))
} }
// MaxWindow set the window max // MaxWindow set the window max
func MaxWindow(pid int, args ...interface{}) { func MaxWindow(pid int32, args ...interface{}) {
var ( var (
state = true state = true
isPid int hwnd int
) )
if len(args) > 0 { if len(args) > 0 {
state = args[0].(bool) state = args[0].(bool)
} }
if len(args) > 1 || NotPid { if len(args) > 1 {
isPid = 1 hwnd = args[1].(int)
} }
C.max_window(C.uintptr(pid), C.bool(state), C.int8_t(isPid)) C.max_window(C.uintptr(pid), C.bool(state), C.uintptr(hwnd))
} }
// CloseWindow close the window // CloseWindow close the window
func CloseWindow(args ...int) { func CloseWindow(args ...int32) {
if len(args) <= 0 { if len(args) <= 0 {
C.close_main_window() C.close_main_window()
return return
} }
var pid, isPid int var hwnd, isHwnd int32
if len(args) > 0 { if len(args) > 0 {
pid = args[0] hwnd = args[0]
} }
if len(args) > 1 || NotPid { if len(args) > 1 {
isPid = 1 isHwnd = args[1]
} }
C.close_window_by_PId(C.uintptr(pid), C.int8_t(isPid)) C.close_window_by_PId(C.uintptr(hwnd), C.uintptr(isHwnd))
} }
// SetHandle set the window handle // SetHandle set the window handle
@ -961,44 +953,23 @@ func SetHandle(hwnd int) {
} }
// SetHandlePid set the window handle by pid // SetHandlePid set the window handle by pid
func SetHandlePid(pid int, args ...int) { func SetHandlePid(pid int32, args ...int32) {
var isPid int var isHwnd int32
if len(args) > 0 || NotPid {
isPid = 1
}
C.set_handle_pid_mData(C.uintptr(pid), C.int8_t(isPid))
}
// GetHandById get handle mdata by id
func GetHandById(id int, args ...int) Handle {
isPid := 1
if len(args) > 0 { if len(args) > 0 {
isPid = args[0] isHwnd = args[0]
}
return GetHandByPid(id, isPid)
} }
// GetHandByPid get handle mdata by pid C.set_handle_pid_mData(C.uintptr(pid), C.uintptr(isHwnd))
func GetHandByPid(pid int, args ...int) Handle {
return Handle(GetHandByPidC(pid, args...))
} }
// Deprecated: use the GetHandByPid(),
//
// GetHandPid get handle mdata by pid // GetHandPid get handle mdata by pid
func GetHandPid(pid int, args ...int) Handle { func GetHandPid(pid int32, args ...int32) C.MData {
return GetHandByPid(pid, args...) var isHwnd int32
if len(args) > 0 {
isHwnd = args[0]
} }
// GetHandByPidC get handle mdata by pid return C.set_handle_pid(C.uintptr(pid), C.uintptr(isHwnd))
func GetHandByPidC(pid int, args ...int) C.MData {
var isPid int
if len(args) > 0 || NotPid {
isPid = 1
}
return C.set_handle_pid(C.uintptr(pid), C.int8_t(isPid))
} }
// GetHandle get the window handle // GetHandle get the window handle
@ -1011,7 +982,7 @@ func GetHandle() int {
// Deprecated: use the GetHandle(), // Deprecated: use the GetHandle(),
// //
// # GetBHandle get the window handle, Wno-deprecated // GetBHandle get the window handle, Wno-deprecated
// //
// This function will be removed in version v1.0.0 // This function will be removed in version v1.0.0
func GetBHandle() int { func GetBHandle() int {
@ -1022,8 +993,8 @@ func GetBHandle() int {
return ghwnd return ghwnd
} }
func cgetTitle(pid, isPid int) string { func cgetTitle(hwnd, isHwnd int32) string {
title := C.get_title_by_pid(C.uintptr(pid), C.int8_t(isPid)) title := C.get_title_by_pid(C.uintptr(hwnd), C.uintptr(isHwnd))
gtitle := C.GoString(title) gtitle := C.GoString(title)
return gtitle return gtitle
@ -1032,12 +1003,11 @@ func cgetTitle(pid, isPid int) string {
// GetTitle get the window title return string // GetTitle get the window title return string
// //
// Examples: // Examples:
//
// fmt.Println(robotgo.GetTitle()) // fmt.Println(robotgo.GetTitle())
// //
// ids, _ := robotgo.FindIds() // ids, _ := robotgo.FindIds()
// robotgo.GetTitle(ids[0]) // robotgo.GetTitle(ids[0])
func GetTitle(args ...int) string { func GetTitle(args ...int32) string {
if len(args) <= 0 { if len(args) <= 0 {
title := C.get_main_title() title := C.get_main_title()
gtitle := C.GoString(title) gtitle := C.GoString(title)
@ -1051,21 +1021,21 @@ func GetTitle(args ...int) string {
return internalGetTitle(args[0]) return internalGetTitle(args[0])
} }
// GetPid get the process id return int32 // GetPID get the process id return int32
func GetPid() int { func GetPID() int32 {
pid := C.get_PID() pid := C.get_PID()
return int(pid) return int32(pid)
} }
// internalGetBounds get the window bounds // internalGetBounds get the window bounds
func internalGetBounds(pid, isPid int) (int, int, int, int) { func internalGetBounds(pid int32, hwnd int) (int, int, int, int) {
bounds := C.get_bounds(C.uintptr(pid), C.int8_t(isPid)) bounds := C.get_bounds(C.uintptr(pid), C.uintptr(hwnd))
return int(bounds.X), int(bounds.Y), int(bounds.W), int(bounds.H) return int(bounds.X), int(bounds.Y), int(bounds.W), int(bounds.H)
} }
// internalGetClient get the window client bounds // internalGetClient get the window client bounds
func internalGetClient(pid, isPid int) (int, int, int, int) { func internalGetClient(pid int32, hwnd int) (int, int, int, int) {
bounds := C.get_client(C.uintptr(pid), C.int8_t(isPid)) bounds := C.get_client(C.uintptr(pid), C.uintptr(hwnd))
return int(bounds.X), int(bounds.Y), int(bounds.W), int(bounds.H) return int(bounds.X), int(bounds.Y), int(bounds.W), int(bounds.H)
} }
@ -1075,30 +1045,29 @@ func Is64Bit() bool {
return bool(b) return bool(b)
} }
func internalActive(pid, isPid int) { func internalActive(pid int32, hwnd int) {
C.active_PID(C.uintptr(pid), C.int8_t(isPid)) C.active_PID(C.uintptr(pid), C.uintptr(hwnd))
} }
// ActivePid active the window by Pid, // ActivePID active the window by PID,
// If args[0] > 0 on the Windows platform via a window handle to active // If args[0] > 0 on the Windows platform via a window handle to active
// func ActivePid(pid int32, args ...int) { // func ActivePID(pid int32, args ...int) {
// var isPid int // var hwnd int
// if len(args) > 0 { // if len(args) > 0 {
// isPid = args[0] // hwnd = args[0]
// } // }
// C.active_PID(C.uintptr(pid), C.uintptr(isPid)) // C.active_PID(C.uintptr(pid), C.uintptr(hwnd))
// } // }
// ActiveName active the window by name // ActiveName active the window by name
// //
// Examples: // Examples:
//
// robotgo.ActiveName("chrome") // robotgo.ActiveName("chrome")
func ActiveName(name string) error { func ActiveName(name string) error {
pids, err := FindIds(name) pids, err := FindIds(name)
if err == nil && len(pids) > 0 { if err == nil && len(pids) > 0 {
return ActivePid(pids[0]) return ActivePID(pids[0])
} }
return err return err

View File

@ -1,95 +0,0 @@
package robotgo
import "github.com/vcaesar/tt"
// Deprecated: use the Move(),
//
// MoveMouse move the mouse
func MoveMouse(x, y int) {
Move(x, y)
}
// Deprecated: use the DragSmooth(),
//
// DragMouse drag the mouse to (x, y),
// It's same with the DragSmooth() now
func DragMouse(x, y int, args ...interface{}) {
Toggle("left")
MilliSleep(50)
// Drag(x, y, args...)
MoveSmooth(x, y, args...)
Toggle("left", "up")
}
// Deprecated: use the MoveSmooth(),
//
// MoveMouseSmooth move the mouse smooth,
// moves mouse to x, y human like, with the mouse button up.
func MoveMouseSmooth(x, y int, args ...interface{}) bool {
return MoveSmooth(x, y, args...)
}
// Deprecated: use the function Location()
//
// GetMousePos get the mouse's position return x, y
func GetMousePos() (int, int) {
return Location()
}
// Deprecated: use the Click(),
//
// # MouseClick click the mouse
//
// robotgo.MouseClick(button string, double bool)
func MouseClick(args ...interface{}) {
Click(args...)
}
// Deprecated: use the TypeStr(),
//
// # TypeStringDelayed type string delayed, Wno-deprecated
//
// This function will be removed in version v1.0.0
func TypeStringDelayed(str string, delay int) {
tt.Drop("TypeStringDelayed", "TypeStrDelay")
TypeStrDelay(str, delay)
}
// Deprecated: use the ScaledF(),
//
// Scale1 get the screen scale (only windows old), drop
func Scale1() int {
dpi := map[int]int{
0: 100,
// DPI Scaling Level
96: 100,
120: 125,
144: 150,
168: 175,
192: 200,
216: 225,
// Custom DPI
240: 250,
288: 300,
384: 400,
480: 500,
}
x := ScaleX()
return dpi[x]
}
// Deprecated: use the ScaledF(),
//
// Scale0 return ScaleX() / 0.96, drop
func Scale0() int {
return int(float64(ScaleX()) / 0.96)
}
// Deprecated: use the ScaledF(),
//
// Mul mul the scale, drop
func Mul(x int) int {
s := Scale1()
return x * s / 100
}

View File

@ -18,7 +18,7 @@ package robotgo
*/ */
import "C" import "C"
// GetMainId get the main display id // GetMianId get the main display id
func GetMainId() int { func GetMainId() int {
return int(C.CGMainDisplayID()) return int(C.CGMainDisplayID())
} }

View File

@ -14,51 +14,50 @@
package robotgo package robotgo
// GetBounds get the window bounds // GetBounds get the window bounds
func GetBounds(pid int, args ...int) (int, int, int, int) { func GetBounds(pid int32, args ...int) (int, int, int, int) {
var isPid int var hwnd int
if len(args) > 0 || NotPid { if len(args) > 0 {
isPid = 1 hwnd = args[0]
} }
return internalGetBounds(pid, isPid) return internalGetBounds(pid, hwnd)
} }
// GetClient get the window client bounds // GetClient get the window client bounds
func GetClient(pid int, args ...int) (int, int, int, int) { func GetClient(pid int32, args ...int) (int, int, int, int) {
var isPid int var hwnd int
if len(args) > 0 || NotPid { if len(args) > 0 {
isPid = 1 hwnd = args[0]
} }
return internalGetClient(pid, isPid) return internalGetClient(pid, hwnd)
} }
// internalGetTitle get the window title // internalGetTitle get the window title
func internalGetTitle(pid int, args ...int) string { func internalGetTitle(pid int32, args ...int32) string {
var isPid int var isHwnd int32
if len(args) > 0 || NotPid { if len(args) > 0 {
isPid = 1 isHwnd = args[0]
} }
gtitle := cgetTitle(pid, isPid) gtitle := cgetTitle(pid, isHwnd)
return gtitle return gtitle
} }
// ActivePid active the window by PID, // ActivePID active the window by PID,
// //
// If args[0] > 0 on the Windows platform via a window handle to active // If args[0] > 0 on the Windows platform via a window handle to active
// //
// Examples: // Examples:
//
// ids, _ := robotgo.FindIds() // ids, _ := robotgo.FindIds()
// robotgo.ActivePid(ids[0]) // robotgo.ActivePID(ids[0])
func ActivePid(pid int, args ...int) error { func ActivePID(pid int32, args ...int) error {
var isPid int var hwnd int
if len(args) > 0 || NotPid { if len(args) > 0 {
isPid = 1 hwnd = args[0]
} }
internalActive(pid, isPid) internalActive(pid, hwnd)
return nil return nil
} }
@ -72,7 +71,6 @@ func DisplaysNum() int {
// If cancel button is not given, only the default button is displayed // If cancel button is not given, only the default button is displayed
// //
// Examples: // Examples:
//
// robotgo.Alert("hi", "window", "ok", "cancel") // robotgo.Alert("hi", "window", "ok", "cancel")
func Alert(title, msg string, args ...string) bool { func Alert(title, msg string, args ...string) bool {
return showAlert(title, msg, args...) return showAlert(title, msg, args...)

View File

@ -14,7 +14,7 @@
package robotgo package robotgo
import ( import (
"github.com/otiai10/gosseract/v2" "github.com/otiai10/gosseract"
) )
// GetText get the image text by tesseract ocr // GetText get the image text by tesseract ocr

View File

@ -42,7 +42,7 @@ func TestSize(t *testing.T) {
func TestMoveMouse(t *testing.T) { func TestMoveMouse(t *testing.T) {
Move(20, 20) Move(20, 20)
MilliSleep(50) MilliSleep(50)
x, y := Location() x, y := GetMousePos()
tt.Equal(t, 20, x) tt.Equal(t, 20, x)
tt.Equal(t, 20, y) tt.Equal(t, 20, y)
@ -51,7 +51,7 @@ func TestMoveMouse(t *testing.T) {
func TestMoveMouseSmooth(t *testing.T) { func TestMoveMouseSmooth(t *testing.T) {
b := MoveSmooth(100, 100) b := MoveSmooth(100, 100)
MilliSleep(50) MilliSleep(50)
x, y := Location() x, y := GetMousePos()
tt.True(t, b) tt.True(t, b)
tt.Equal(t, 100, x) tt.Equal(t, 100, x)
@ -61,15 +61,15 @@ func TestMoveMouseSmooth(t *testing.T) {
func TestDragMouse(t *testing.T) { func TestDragMouse(t *testing.T) {
DragSmooth(500, 500) DragSmooth(500, 500)
MilliSleep(50) MilliSleep(50)
x, y := Location() x, y := GetMousePos()
tt.Equal(t, 500, x) tt.Equal(t, 500, x)
tt.Equal(t, 500, y) tt.Equal(t, 500, y)
} }
func TestScrollMouse(t *testing.T) { func TestScrollMouse(t *testing.T) {
ScrollDir(120, "up") ScrollMouse(120, "up")
ScrollDir(100, "right") ScrollMouse(100, "right")
Scroll(0, 120) Scroll(0, 120)
MilliSleep(100) MilliSleep(100)
@ -85,7 +85,7 @@ func TestMoveRelative(t *testing.T) {
MoveRelative(10, -10) MoveRelative(10, -10)
MilliSleep(50) MilliSleep(50)
x, y := Location() x, y := GetMousePos()
tt.Equal(t, 210, x) tt.Equal(t, 210, x)
tt.Equal(t, 190, y) tt.Equal(t, 190, y)
} }
@ -97,7 +97,7 @@ func TestMoveSmoothRelative(t *testing.T) {
MoveSmoothRelative(10, -10) MoveSmoothRelative(10, -10)
MilliSleep(50) MilliSleep(50)
x, y := Location() x, y := GetMousePos()
tt.Equal(t, 210, x) tt.Equal(t, 210, x)
tt.Equal(t, 190, y) tt.Equal(t, 190, y)
} }
@ -179,8 +179,7 @@ func TestImage(t *testing.T) {
err := SavePng(img, "robot_test.png") err := SavePng(img, "robot_test.png")
tt.Nil(t, err) tt.Nil(t, err)
img1, err := CaptureImg(10, 10, 20, 20) img1 := CaptureImg(10, 10, 20, 20)
tt.Nil(t, err)
e := Save(img1, "robot_img.jpeg", 50) e := Save(img1, "robot_img.jpeg", 50)
tt.Nil(t, e) tt.Nil(t, e)
@ -195,7 +194,7 @@ func TestImage(t *testing.T) {
func TestPs(t *testing.T) { func TestPs(t *testing.T) {
id, err := Pids() id, err := Pids()
tt.Not(t, "[]", id) tt.Not(t, "[]", id)
tt.IsType(t, "[]int", id) tt.IsType(t, "[]int32", id)
tt.Nil(t, err) tt.Nil(t, err)
ps, e := Process() ps, e := Process()
@ -218,14 +217,9 @@ func TestPs(t *testing.T) {
id, err = FindIds(n1[0]) id, err = FindIds(n1[0])
tt.Not(t, "[]", id) tt.Not(t, "[]", id)
tt.IsType(t, "[]int", id) tt.IsType(t, "[]int32", id)
tt.Nil(t, err) tt.Nil(t, err)
if len(id) > 0 {
e := KeyTap("v", id[0], "cmd")
tt.Nil(t, e)
}
// n, e = FindPath(id[0]) // n, e = FindPath(id[0])
// tt.NotEmpty(t, n) // tt.NotEmpty(t, n)
// tt.Nil(t, e) // tt.Nil(t, e)

View File

@ -17,8 +17,7 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
// "github.com/lxn/win" "github.com/lxn/win"
"github.com/tailscale/win"
) )
// FindWindow find window hwnd by name // FindWindow find window hwnd by name
@ -53,48 +52,30 @@ func SetFocus(hwnd win.HWND) win.HWND {
return win.SetFocus(hwnd) return win.SetFocus(hwnd)
} }
// SetForeg set the window into the foreground by hwnd // GetMian get the main display hwnd
func SetForeg(hwnd win.HWND) bool {
return win.SetForegroundWindow(hwnd)
}
// GetMain get the main display hwnd
func GetMain() win.HWND { func GetMain() win.HWND {
return win.GetActiveWindow() return win.GetActiveWindow()
} }
// GetMainId get the main display id // GetMianId get the main display id
func GetMainId() int { func GetMainId() int {
return int(GetMain()) return int(GetMain())
} }
// ScaleF get the system scale value // ScaleF get the system scale val
// if "displayId == -2" this function will get the desktop scale value
func ScaleF(displayId ...int) (f float64) { func ScaleF(displayId ...int) (f float64) {
if len(displayId) > 0 && displayId[0] != -1 { if len(displayId) > 0 && displayId[0] != -1 {
if displayId[0] >= 0 {
dpi := GetDPI(win.HWND(displayId[0])) dpi := GetDPI(win.HWND(displayId[0]))
f = float64(dpi) / 96.0 f = float64(dpi) / 96.0
}
if displayId[0] == -2 {
f = float64(GetDPI(GetDesktopWindow())) / 96.0
}
} else { } else {
f = float64(GetMainDPI()) / 96.0 f = float64(GetMainDPI()) / 96.0
} }
if f == 0.0 { if f == 0.0 {
f = 1.0 f = 1.0
} }
return f return f
} }
// GetDesktopWindow get the desktop window hwnd id
func GetDesktopWindow() win.HWND {
return win.GetDesktopWindow()
}
// GetMainDPI get the display dpi // GetMainDPI get the display dpi
func GetMainDPI() int { func GetMainDPI() int {
return int(GetDPI(GetHWND())) return int(GetDPI(GetHWND()))

View File

@ -15,6 +15,7 @@ package robotgo
import ( import (
"errors" "errors"
"fmt"
"log" "log"
"github.com/robotn/xgb" "github.com/robotn/xgb"
@ -27,81 +28,81 @@ import (
var xu *xgbutil.XUtil var xu *xgbutil.XUtil
// GetBounds get the window bounds // GetBounds get the window bounds
func GetBounds(pid int, args ...int) (int, int, int, int) { func GetBounds(pid int32, args ...int) (int, int, int, int) {
var isPid int var hwnd int
if len(args) > 0 || NotPid { if len(args) > 0 {
isPid = 1 hwnd = args[0]
return internalGetBounds(pid, isPid) return internalGetBounds(pid, hwnd)
} }
xid, err := GetXid(xu, pid) xid, err := GetXId(xu, pid)
if err != nil { if err != nil {
log.Println("Get Xid from Pid errors is: ", err) log.Println("Get Xid from Pid errors is: ", err)
return 0, 0, 0, 0 return 0, 0, 0, 0
} }
return internalGetBounds(int(xid), isPid) return internalGetBounds(int32(xid), hwnd)
} }
// GetClient get the window client bounds // GetClient get the window client bounds
func GetClient(pid int, args ...int) (int, int, int, int) { func GetClient(pid int32, args ...int) (int, int, int, int) {
var isPid int var hwnd int
if len(args) > 0 || NotPid { if len(args) > 0 {
isPid = 1 hwnd = args[0]
return internalGetClient(pid, isPid) return internalGetClient(pid, hwnd)
} }
xid, err := GetXid(xu, pid) xid, err := GetXId(xu, pid)
if err != nil { if err != nil {
log.Println("Get Xid from Pid errors is: ", err) log.Println("Get Xid from Pid errors is: ", err)
return 0, 0, 0, 0 return 0, 0, 0, 0
} }
return internalGetClient(int(xid), isPid) return internalGetClient(int32(xid), hwnd)
} }
// internalGetTitle get the window title // internalGetTitle get the window title
func internalGetTitle(pid int, args ...int) string { func internalGetTitle(pid int32, args ...int32) string {
var isPid int var hwnd int32
if len(args) > 0 || NotPid { if len(args) > 0 {
isPid = 1 hwnd = args[0]
return cgetTitle(pid, isPid) return cgetTitle(pid, hwnd)
} }
xid, err := GetXid(xu, pid) xid, err := GetXId(xu, pid)
if err != nil { if err != nil {
log.Println("Get Xid from Pid errors is: ", err) log.Println("Get Xid from Pid errors is: ", err)
return "" return ""
} }
return cgetTitle(int(xid), isPid) return cgetTitle(int32(xid), hwnd)
} }
// ActivePidC active the window by Pid, // ActivePIDC active the window by PID,
// If args[0] > 0 on the unix platform via a xid to active // If args[0] > 0 on the unix platform via a xid to active
func ActivePidC(pid int, args ...int) error { func ActivePIDC(pid int32, args ...int) error {
var isPid int var hwnd int
if len(args) > 0 || NotPid { if len(args) > 0 {
isPid = 1 hwnd = args[0]
internalActive(pid, isPid) internalActive(pid, hwnd)
return nil return nil
} }
xid, err := GetXid(xu, pid) xid, err := GetXId(xu, pid)
if err != nil { if err != nil {
log.Println("Get Xid from Pid errors is: ", err) log.Println("Get Xid from Pid errors is: ", err)
return err return err
} }
internalActive(int(xid), isPid) internalActive(int32(xid), hwnd)
return nil return nil
} }
// ActivePid active the window by Pid, // ActivePID active the window by PID,
// //
// If args[0] > 0 on the Windows platform via a window handle to active, // If args[0] > 0 on the Windows platform via a window handle to active,
// If args[0] > 0 on the unix platform via a xid to active // If args[0] > 0 on the unix platform via a xid to active
func ActivePid(pid int, args ...int) error { func ActivePID(pid int32, args ...int) error {
if xu == nil { if xu == nil {
var err error var err error
xu, err = xgbutil.NewConn() xu, err = xgbutil.NewConn()
@ -133,8 +134,8 @@ func ActivePid(pid int, args ...int) error {
return nil return nil
} }
// GetXid get the xid return window and error // GetXId get the xid return window and error
func GetXid(xu *xgbutil.XUtil, pid int) (xproto.Window, error) { func GetXId(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
if xu == nil { if xu == nil {
var err error var err error
xu, err = xgbutil.NewConn() xu, err = xgbutil.NewConn()
@ -148,8 +149,8 @@ func GetXid(xu *xgbutil.XUtil, pid int) (xproto.Window, error) {
return xid, err return xid, err
} }
// GetXidFromPid get the xid from pid // GetXidFromPid get the xide from pid
func GetXidFromPid(xu *xgbutil.XUtil, pid int) (xproto.Window, error) { func GetXidFromPid(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
windows, err := ewmh.ClientListGet(xu) windows, err := ewmh.ClientListGet(xu)
if err != nil { if err != nil {
return 0, err return 0, err
@ -190,7 +191,7 @@ func DisplaysNum() int {
return int(reply.Number) return int(reply.Number)
} }
// GetMainId get the main display id // GetMianId get the main display id
func GetMainId() int { func GetMainId() int {
conn, err := xgb.NewConn() conn, err := xgb.NewConn()
if err != nil { if err != nil {
@ -214,7 +215,6 @@ func GetMainId() int {
// If cancel button is not given, only the default button is displayed // If cancel button is not given, only the default button is displayed
// //
// Examples: // Examples:
//
// robotgo.Alert("hi", "window", "ok", "cancel") // robotgo.Alert("hi", "window", "ok", "cancel")
func Alert(title, msg string, args ...string) bool { func Alert(title, msg string, args ...string) bool {
defaultBtn, cancelBtn := alertArgs(args...) defaultBtn, cancelBtn := alertArgs(args...)
@ -224,11 +224,10 @@ func Alert(title, msg string, args ...string) bool {
c += cancelBtn + ":1" c += cancelBtn + ":1"
} }
c += ` -default ` + defaultBtn c += ` -default ` + defaultBtn
c += ` -geometry 400x200`
out, err := Run(c) out, err := Run(c)
if err != nil { if err != nil {
// fmt.Println("Alert: ", err, ". ", string(out)) fmt.Println("Alert: ", err, ". ", string(out))
return false return false
} }

View File

@ -1,63 +0,0 @@
// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/robotgo/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
package robotgo
import (
"image"
// "github.com/kbinani/screenshot"
"github.com/vcaesar/screenshot"
)
// GetDisplayBounds gets the display screen bounds
func GetDisplayBounds(i int) (x, y, w, h int) {
bs := screenshot.GetDisplayBounds(i)
return bs.Min.X, bs.Min.Y, bs.Dx(), bs.Dy()
}
// GetDisplayRect gets the display rect
func GetDisplayRect(i int) Rect {
x, y, w, h := GetDisplayBounds(i)
return Rect{
Point{X: x, Y: y},
Size{W: w, H: h}}
}
// Capture capture the screenshot, use the CaptureImg default
func Capture(args ...int) (*image.RGBA, error) {
displayId := 0
if DisplayID != -1 {
displayId = DisplayID
}
if len(args) > 4 {
displayId = args[4]
}
var x, y, w, h int
if len(args) > 3 {
x, y, w, h = args[0], args[1], args[2], args[3]
} else {
x, y, w, h = GetDisplayBounds(displayId)
}
return screenshot.Capture(x, y, w, h)
}
// SaveCapture capture screen and save the screenshot to image
func SaveCapture(path string, args ...int) error {
img, err := CaptureImg(args...)
if err != nil {
return err
}
return Save(img, path)
}

View File

@ -9,9 +9,10 @@
// except according to those terms. // except according to those terms.
#include "../base/types.h" #include "../base/types.h"
#include "../base/pubs.h"
#include "../base/rgb.h" #include "../base/rgb.h"
#include "../base/win32.h"
#include "screengrab_c.h" #include "screengrab_c.h"
#include "screen_c.h"
#include <stdio.h> #include <stdio.h>
void padHex(MMRGBHex color, char* hex) { void padHex(MMRGBHex color, char* hex) {
@ -50,7 +51,7 @@ MMRGBHex get_px_color(int32_t x, int32_t y, int32_t display_id) {
return color; return color;
} }
bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1), display_id, 0); bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1), display_id);
color = MMRGBHexAtPoint(bitmap, 0, 0); color = MMRGBHexAtPoint(bitmap, 0, 0);
destroyMMBitmap(bitmap); destroyMMBitmap(bitmap);
@ -78,14 +79,6 @@ char* get_XDisplay_name() {
#endif #endif
} }
void close_main_display() {
#if defined(USE_X11)
XCloseMainDisplay();
#else
//
#endif
}
uint32_t get_num_displays() { uint32_t get_num_displays() {
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
uint32_t count = 0; uint32_t count = 0;
@ -104,15 +97,6 @@ uint32_t get_num_displays() {
#endif #endif
} }
uintptr get_hwnd_by_pid(uintptr pid) {
#if defined(IS_WINDOWS)
HWND hwnd = GetHwndByPid(pid);
return (uintptr)hwnd;
#else
return 0;
#endif
}
void bitmap_dealloc(MMBitmapRef bitmap) { void bitmap_dealloc(MMBitmapRef bitmap) {
if (bitmap != NULL) { if (bitmap != NULL) {
destroyMMBitmap(bitmap); destroyMMBitmap(bitmap);
@ -121,8 +105,8 @@ void bitmap_dealloc(MMBitmapRef bitmap) {
} }
// capture_screen capture screen // capture_screen capture screen
MMBitmapRef capture_screen(int32_t x, int32_t y, int32_t w, int32_t h, int32_t display_id, int8_t isPid) { MMBitmapRef capture_screen(int32_t x, int32_t y, int32_t w, int32_t h, int32_t display_id) {
MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, w, h), display_id, isPid); MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, w, h), display_id);
return bitmap; return bitmap;
} }

View File

@ -4,70 +4,9 @@
#include <ApplicationServices/ApplicationServices.h> #include <ApplicationServices/ApplicationServices.h>
#elif defined(USE_X11) #elif defined(USE_X11)
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xresource.h>
// #include "../base/xdisplay_c.h" // #include "../base/xdisplay_c.h"
#endif #endif
intptr scaleX();
double sys_scale(int32_t display_id) {
#if defined(IS_MACOSX)
CGDirectDisplayID displayID = (CGDirectDisplayID) display_id;
if (displayID == -1) {
displayID = CGMainDisplayID();
}
CGDisplayModeRef modeRef = CGDisplayCopyDisplayMode(displayID);
double pixelWidth = CGDisplayModeGetPixelWidth(modeRef);
double targetWidth = CGDisplayModeGetWidth(modeRef);
return pixelWidth / targetWidth;
#elif defined(USE_X11)
Display *dpy = XOpenDisplay(NULL);
int scr = 0; /* Screen number */
double xres = ((((double) DisplayWidth(dpy, scr)) * 25.4) /
((double) DisplayWidthMM(dpy, scr)));
char *rms = XResourceManagerString(dpy);
if (rms) {
XrmDatabase db = XrmGetStringDatabase(rms);
if (db) {
XrmValue value;
char *type = NULL;
if (XrmGetResource(db, "Xft.dpi", "String", &type, &value)) {
if (value.addr) {
xres = atof(value.addr);
}
}
XrmDestroyDatabase(db);
}
}
XCloseDisplay (dpy);
return xres / 96.0;
#elif defined(IS_WINDOWS)
double s = scaleX() / 96.0;
return s;
#endif
}
intptr scaleX(){
#if defined(IS_MACOSX)
return 0;
#elif defined(USE_X11)
return 0;
#elif defined(IS_WINDOWS)
// Get desktop dc
HDC desktopDc = GetDC(NULL);
// Get native resolution
intptr horizontalDPI = GetDeviceCaps(desktopDc, LOGPIXELSX);
return horizontalDPI;
#endif
}
MMSizeInt32 getMainDisplaySize(void) { MMSizeInt32 getMainDisplaySize(void) {
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
CGDirectDisplayID displayID = CGMainDisplayID(); CGDirectDisplayID displayID = CGMainDisplayID();
@ -83,9 +22,15 @@ MMSizeInt32 getMainDisplaySize(void) {
(int32_t)DisplayWidth(display, screen), (int32_t)DisplayWidth(display, screen),
(int32_t)DisplayHeight(display, screen)); (int32_t)DisplayHeight(display, screen));
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
if (GetSystemMetrics(SM_CMONITORS) == 1) {
return MMSizeInt32Make( return MMSizeInt32Make(
(int32_t)GetSystemMetrics(SM_CXSCREEN), (int32_t)GetSystemMetrics(SM_CXSCREEN),
(int32_t)GetSystemMetrics(SM_CYSCREEN)); (int32_t)GetSystemMetrics(SM_CYSCREEN));
} else {
return MMSizeInt32Make(
(int32_t)GetSystemMetrics(SM_CXVIRTUALSCREEN),
(int32_t)GetSystemMetrics(SM_CYVIRTUALSCREEN));
}
#endif #endif
} }
@ -111,8 +56,7 @@ MMRectInt32 getScreenRect(int32_t display_id) {
(int32_t)DisplayWidth(display, screen), (int32_t)DisplayWidth(display, screen),
(int32_t)DisplayHeight(display, screen)); (int32_t)DisplayHeight(display, screen));
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
if (GetSystemMetrics(SM_CMONITORS) == 1 if (GetSystemMetrics(SM_CMONITORS) == 1) {
|| display_id == -1 || display_id == 0) {
return MMRectInt32Make( return MMRectInt32Make(
(int32_t)0, (int32_t)0,
(int32_t)0, (int32_t)0,

View File

@ -5,7 +5,6 @@
#include <OpenGL/OpenGL.h> #include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h> #include <OpenGL/gl.h>
#include <ApplicationServices/ApplicationServices.h> #include <ApplicationServices/ApplicationServices.h>
#include <ScreenCaptureKit/ScreenCaptureKit.h>
#elif defined(USE_X11) #elif defined(USE_X11)
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
@ -13,77 +12,20 @@
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
#include <string.h> #include <string.h>
#endif #endif
#include "screen_c.h"
#if defined(IS_MACOSX) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 140400 MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id) {
static CGImageRef capture15(CGDirectDisplayID id, CGRect diIntersectDisplayLocal, CGColorSpaceRef colorSpace) {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block CGImageRef image1 = nil;
[SCShareableContent getShareableContentWithCompletionHandler:^(SCShareableContent* content, NSError* error) {
@autoreleasepool {
if (error) {
dispatch_semaphore_signal(semaphore);
return;
}
SCDisplay* target = nil;
for (SCDisplay *display in content.displays) {
if (display.displayID == id) {
target = display;
break;
}
}
if (!target) {
dispatch_semaphore_signal(semaphore);
return;
}
SCContentFilter* filter = [[SCContentFilter alloc] initWithDisplay:target excludingWindows:@[]];
SCStreamConfiguration* config = [[SCStreamConfiguration alloc] init];
config.queueDepth = 5;
config.sourceRect = diIntersectDisplayLocal;
config.width = diIntersectDisplayLocal.size.width * sys_scale(id);
config.height = diIntersectDisplayLocal.size.height * sys_scale(id);
config.scalesToFit = false;
config.captureResolution = 1;
[SCScreenshotManager captureImageWithFilter:filter
configuration:config
completionHandler:^(CGImageRef img, NSError* error) {
if (!error) {
image1 = CGImageCreateCopyWithColorSpace(img, colorSpace);
}
dispatch_semaphore_signal(semaphore);
}];
}
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_release(semaphore);
return image1;
}
#endif
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id, int8_t isPid) {
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
MMBitmapRef bitmap = NULL; MMBitmapRef bitmap = NULL;
uint8_t *buffer = NULL; uint8_t *buffer = NULL;
size_t bufferSize = 0; size_t bufferSize = 0;
CGDirectDisplayID displayID = (CGDirectDisplayID) display_id; CGDirectDisplayID displayID = (CGDirectDisplayID) display_id;
if (displayID == -1 || displayID == 0) { if (displayID == -1) {
displayID = CGMainDisplayID(); displayID = CGMainDisplayID();
} }
MMPointInt32 o = rect.origin; MMSizeInt32 s = rect.size; CGImageRef image = CGDisplayCreateImageForRect(displayID,
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 140400 CGRectMake(rect.origin.x, rect.origin.y, rect.size.w, rect.size.h));
CGColorSpaceRef color = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
CGImageRef image = capture15(displayID, CGRectMake(o.x, o.y, s.w, s.h), color);
CGColorSpaceRelease(color);
#else
// This API is deprecated in macos 15, use ScreenCaptureKit's captureScreenshot
CGImageRef image = CGDisplayCreateImageForRect(displayID, CGRectMake(o.x, o.y, s.w, s.h));
#endif
if (!image) { return NULL; } if (!image) { return NULL; }
CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image)); CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image));
@ -110,15 +52,14 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id,
display = XGetMainDisplay(); display = XGetMainDisplay();
} }
MMPointInt32 o = rect.origin; MMSizeInt32 s = rect.size;
XImage *image = XGetImage(display, XDefaultRootWindow(display), XImage *image = XGetImage(display, XDefaultRootWindow(display),
(int)o.x, (int)o.y, (unsigned int)s.w, (unsigned int)s.h, (int)rect.origin.x, (int)rect.origin.y,
AllPlanes, ZPixmap); (unsigned int)rect.size.w, (unsigned int)rect.size.h, AllPlanes, ZPixmap);
XCloseDisplay(display); XCloseDisplay(display);
if (image == NULL) { return NULL; } if (image == NULL) { return NULL; }
bitmap = createMMBitmap_c((uint8_t *)image->data, bitmap = createMMBitmap_c((uint8_t *)image->data,
s.w, s.h, (size_t)image->bytes_per_line, rect.size.w, rect.size.h, (size_t)image->bytes_per_line,
(uint8_t)image->bits_per_pixel, (uint8_t)image->bits_per_pixel / 8); (uint8_t)image->bits_per_pixel, (uint8_t)image->bits_per_pixel / 8);
image->data = NULL; /* Steal ownership of bitmap data so we don't have to copy it. */ image->data = NULL; /* Steal ownership of bitmap data so we don't have to copy it. */
XDestroyImage(image); XDestroyImage(image);
@ -131,52 +72,44 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id,
HBITMAP dib; HBITMAP dib;
BITMAPINFO bi; BITMAPINFO bi;
int32_t x = rect.origin.x, y = rect.origin.y;
int32_t w = rect.size.w, h = rect.size.h;
/* Initialize bitmap info. */ /* Initialize bitmap info. */
bi.bmiHeader.biSize = sizeof(bi.bmiHeader); bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = (long) w; bi.bmiHeader.biWidth = (long)rect.size.w;
bi.bmiHeader.biHeight = -(long) h; /* Non-cartesian, please */ bi.bmiHeader.biHeight = -(long)rect.size.h; /* Non-cartesian, please */
bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB; bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biSizeImage = (DWORD)(4 * w * h); bi.bmiHeader.biSizeImage = (DWORD)(4 * rect.size.w * rect.size.h);
bi.bmiHeader.biXPelsPerMeter = 0; bi.bmiHeader.biXPelsPerMeter = 0;
bi.bmiHeader.biYPelsPerMeter = 0; bi.bmiHeader.biYPelsPerMeter = 0;
bi.bmiHeader.biClrUsed = 0; bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0; bi.bmiHeader.biClrImportant = 0;
HWND hwnd; if (display_id == -1) {
if (display_id == -1 || isPid == 0) { screen = GetDC(NULL); /* Get entire screen */
// screen = GetDC(NULL); /* Get entire screen */
hwnd = GetDesktopWindow();
} else { } else {
hwnd = (HWND) (uintptr) display_id; screen = GetDC((HWND) (uintptr) display_id);
} }
screen = GetDC(hwnd);
if (screen == NULL) { return NULL; } if (screen == NULL) { return NULL; }
// Todo: Use DXGI
screenMem = CreateCompatibleDC(screen);
/* Get screen data in display device context. */ /* Get screen data in display device context. */
dib = CreateDIBSection(screen, &bi, DIB_RGB_COLORS, &data, NULL, 0); dib = CreateDIBSection(screen, &bi, DIB_RGB_COLORS, &data, NULL, 0);
/* Copy the data into a bitmap struct. */ /* Copy the data into a bitmap struct. */
BOOL b = (screenMem == NULL) || BOOL smem = (screenMem = CreateCompatibleDC(screen)) == NULL;
SelectObject(screenMem, dib) == NULL || BOOL bitb = BitBlt(screenMem, (int)0, (int)0, (int)rect.size.w, (int)rect.size.h,
!BitBlt(screenMem, (int)0, (int)0, (int)w, (int)h, screen, x, y, SRCCOPY); screen, rect.origin.x, rect.origin.y, SRCCOPY);
if (b) { if (smem || SelectObject(screenMem, dib) == NULL || !bitb) {
/* Error copying data. */ /* Error copying data. */
ReleaseDC(hwnd, screen); ReleaseDC(NULL, screen);
DeleteObject(dib); DeleteObject(dib);
if (screenMem != NULL) { DeleteDC(screenMem); } if (screenMem != NULL) { DeleteDC(screenMem); }
return NULL; return NULL;
} }
bitmap = createMMBitmap_c(NULL, w, h, 4 * w, (uint8_t)bi.bmiHeader.biBitCount, 4); bitmap = createMMBitmap_c(NULL, rect.size.w, rect.size.h, 4 * rect.size.w,
(uint8_t)bi.bmiHeader.biBitCount, 4);
/* Copy the data to our pixel buffer. */ /* Copy the data to our pixel buffer. */
if (bitmap != NULL) { if (bitmap != NULL) {
@ -184,7 +117,7 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id,
memcpy(bitmap->imageBuffer, data, bitmap->bytewidth * bitmap->height); memcpy(bitmap->imageBuffer, data, bitmap->bytewidth * bitmap->height);
} }
ReleaseDC(hwnd, screen); ReleaseDC(NULL, screen);
DeleteObject(dib); DeleteObject(dib);
DeleteDC(screenMem); DeleteDC(screenMem);

View File

@ -1,38 +0,0 @@
<h1>Type and check the console</h1>
<script>
window.onclick = function(events) {
console.log({
event: "click",
altKey: events.altKey,
shiftKey: events.shiftKey
});
};
window.onkeydown = function(events) {
console.log({
event: "keydown",
key: events.key,
keyCode: events.keyCode,
keyChar: events.charCode
});
};
window.onkeyup = function(events) {
console.log({
event: "keyup",
key: events.key,
keyCode: events.keyCode,
keyChar: events.charCode
});
};
// move
window.onmousemove = function(events) {
console.log({
event: "move",
x: events.x,
y: events.y
});
}
</script>

View File

@ -1,2 +0,0 @@
// +bulid linux,next
package robotgo

View File

@ -18,7 +18,6 @@ int showAlert(const char *title, const char *msg,
CFStringRef defaultButtonTitle = CFStringCreateWithUTF8String(defaultButton); CFStringRef defaultButtonTitle = CFStringCreateWithUTF8String(defaultButton);
CFStringRef cancelButtonTitle = CFStringCreateWithUTF8String(cancelButton); CFStringRef cancelButtonTitle = CFStringCreateWithUTF8String(cancelButton);
CFOptionFlags responseFlags; CFOptionFlags responseFlags;
SInt32 err = CFUserNotificationDisplayAlert( SInt32 err = CFUserNotificationDisplayAlert(
0.0, kCFUserNotificationNoteAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, 0.0, kCFUserNotificationNoteAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage,
defaultButtonTitle, cancelButtonTitle, NULL, &responseFlags); defaultButtonTitle, cancelButtonTitle, NULL, &responseFlags);

View File

@ -12,7 +12,7 @@
#include "window.h" #include "window.h"
#include "win_sys.h" #include "win_sys.h"
void min_window(uintptr pid, bool state, int8_t isPid){ void min_window(uintptr pid, bool state, uintptr isHwnd){
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
// return 0; // return 0;
AXUIElementRef axID = AXUIElementCreateApplication(pid); AXUIElementRef axID = AXUIElementCreateApplication(pid);
@ -23,12 +23,16 @@ void min_window(uintptr pid, bool state, int8_t isPid){
XDismissErrors(); XDismissErrors();
// SetState((Window)pid, STATE_MINIMIZE, state); // SetState((Window)pid, STATE_MINIMIZE, state);
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
HWND hwnd = getHwnd(pid, isPid); if (isHwnd == 0) {
HWND hwnd = GetHwndByPId(pid);
win_min(hwnd, state); win_min(hwnd, state);
} else {
win_min((HWND)pid, state);
}
#endif #endif
} }
void max_window(uintptr pid, bool state, int8_t isPid){ void max_window(uintptr pid, bool state, uintptr isHwnd){
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
// return 0; // return 0;
#elif defined(USE_X11) #elif defined(USE_X11)
@ -36,8 +40,12 @@ void max_window(uintptr pid, bool state, int8_t isPid){
// SetState((Window)pid, STATE_MINIMIZE, false); // SetState((Window)pid, STATE_MINIMIZE, false);
// SetState((Window)pid, STATE_MAXIMIZE, state); // SetState((Window)pid, STATE_MAXIMIZE, state);
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
HWND hwnd = getHwnd(pid, isPid); if (isHwnd == 0) {
HWND hwnd = GetHwndByPId(pid);
win_max(hwnd, state); win_max(hwnd, state);
} else {
win_max((HWND)pid, state);
}
#endif #endif
} }
@ -55,15 +63,15 @@ uintptr get_handle(){
uintptr b_get_handle() { uintptr b_get_handle() {
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
return (uintptr)pub_mData.CgID; return (uintptr)mData.CgID;
#elif defined(USE_X11) #elif defined(USE_X11)
return (uintptr)pub_mData.XWin; return (uintptr)mData.XWin;
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
return (uintptr)pub_mData.HWnd; return (uintptr)mData.HWnd;
#endif #endif
} }
void active_PID(uintptr pid, int8_t isPid){ void active_PID(uintptr pid, uintptr isHwnd){
MData win = set_handle_pid(pid, isPid); MData win = set_handle_pid(pid, isHwnd);
set_active(win); set_active(win);
} }

View File

@ -28,7 +28,7 @@ struct _MData{
}; };
typedef struct _MData MData; typedef struct _MData MData;
MData pub_mData; MData mData;
struct _Bounds { struct _Bounds {
int32_t X; // Top left X coordinate int32_t X; // Top left X coordinate
@ -191,7 +191,6 @@ typedef struct _Bounds Bounds;
if (items != NULL) { if (items != NULL) {
*items = (uint32_t) nItems; *items = (uint32_t) nItems;
} }
XCloseDisplay(rDisplay);
return result; return result;
} }
} }
@ -268,8 +267,6 @@ typedef struct _Bounds Bounds;
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
HWND getHwnd(uintptr pid, int8_t isPid);
void win_min(HWND hwnd, bool state){ void win_min(HWND hwnd, bool state){
if (state) { if (state) {
ShowWindow(hwnd, SW_MINIMIZE); ShowWindow(hwnd, SW_MINIMIZE);

View File

@ -8,13 +8,72 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// #if defined(USE_X11) #if defined(USE_X11)
// #include <X11/Xresource.h> #include <X11/Xresource.h>
// #endif #endif
Bounds get_client(uintptr pid, int8_t isPid); Bounds get_client(uintptr pid, uintptr isHwnd);
intptr scaleX();
Bounds get_bounds(uintptr pid, int8_t isPid){ double sys_scale(int32_t display_id) {
#if defined(IS_MACOSX)
CGDirectDisplayID displayID = (CGDirectDisplayID) display_id;
if (displayID == -1) {
displayID = CGMainDisplayID();
}
CGDisplayModeRef modeRef = CGDisplayCopyDisplayMode(displayID);
double pixelWidth = CGDisplayModeGetPixelWidth(modeRef);
double targetWidth = CGDisplayModeGetWidth(modeRef);
return pixelWidth / targetWidth;
#elif defined(USE_X11)
Display *dpy = XOpenDisplay(NULL);
int scr = 0; /* Screen number */
double xres = ((((double) DisplayWidth(dpy, scr)) * 25.4) /
((double) DisplayWidthMM(dpy, scr)));
char *rms = XResourceManagerString(dpy);
if (rms) {
XrmDatabase db = XrmGetStringDatabase(rms);
if (db) {
XrmValue value;
char *type = NULL;
if (XrmGetResource(db, "Xft.dpi", "String", &type, &value)) {
if (value.addr) {
xres = atof(value.addr);
}
}
XrmDestroyDatabase(db);
}
}
XCloseDisplay (dpy);
return xres / 96.0;
#elif defined(IS_WINDOWS)
double s = scaleX() / 96.0;
return s;
#endif
}
intptr scaleX(){
#if defined(IS_MACOSX)
return 0;
#elif defined(USE_X11)
return 0;
#elif defined(IS_WINDOWS)
// Get desktop dc
HDC desktopDc = GetDC(NULL);
// Get native resolution
intptr horizontalDPI = GetDeviceCaps(desktopDc, LOGPIXELSX);
return horizontalDPI;
#endif
}
Bounds get_bounds(uintptr pid, uintptr isHwnd){
// Check if the window is valid // Check if the window is valid
Bounds bounds; Bounds bounds;
if (!is_valid()) { return bounds; } if (!is_valid()) { return bounds; }
@ -59,7 +118,7 @@ Bounds get_bounds(uintptr pid, int8_t isPid){
MData win; MData win;
win.XWin = (Window)pid; win.XWin = (Window)pid;
Bounds client = get_client(pid, isPid); Bounds client = get_client(pid, isHwnd);
Bounds frame = GetFrame(win); Bounds frame = GetFrame(win);
bounds.X = client.X - frame.X; bounds.X = client.X - frame.X;
@ -69,7 +128,12 @@ Bounds get_bounds(uintptr pid, int8_t isPid){
return bounds; return bounds;
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
HWND hwnd = getHwnd(pid, isPid); HWND hwnd;
if (isHwnd == 0) {
hwnd= GetHwndByPId(pid);
} else {
hwnd = (HWND)pid;
}
RECT rect = { 0 }; RECT rect = { 0 };
GetWindowRect(hwnd, &rect); GetWindowRect(hwnd, &rect);
@ -83,13 +147,13 @@ Bounds get_bounds(uintptr pid, int8_t isPid){
#endif #endif
} }
Bounds get_client(uintptr pid, int8_t isPid) { Bounds get_client(uintptr pid, uintptr isHwnd) {
// Check if the window is valid // Check if the window is valid
Bounds bounds; Bounds bounds;
if (!is_valid()) { return bounds; } if (!is_valid()) { return bounds; }
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
return get_bounds(pid, isPid); return get_bounds(pid, isHwnd);
#elif defined(USE_X11) #elif defined(USE_X11)
Display *rDisplay = XOpenDisplay(NULL); Display *rDisplay = XOpenDisplay(NULL);
@ -129,7 +193,12 @@ Bounds get_client(uintptr pid, int8_t isPid) {
return bounds; return bounds;
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
HWND hwnd = getHwnd(pid, isPid); HWND hwnd;
if (isHwnd == 0) {
hwnd = GetHwndByPId(pid);
} else {
hwnd = (HWND)pid;
}
RECT rect = { 0 }; RECT rect = { 0 };
GetClientRect(hwnd, &rect); GetClientRect(hwnd, &rect);

View File

@ -15,7 +15,7 @@ bool is_valid();
bool IsAxEnabled(bool options); bool IsAxEnabled(bool options);
MData get_active(void); MData get_active(void);
void initWindow(uintptr handle); void initWindow();
char* get_title_by_hand(MData m_data); char* get_title_by_hand(MData m_data);
void close_window_by_Id(MData m_data); void close_window_by_Id(MData m_data);
@ -24,8 +24,8 @@ uintptr initHandle = 0;
void initWindow(uintptr handle){ void initWindow(uintptr handle){
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
pub_mData.CgID = 0; mData.CgID = 0;
pub_mData.AxID = 0; mData.AxID = 0;
#elif defined(USE_X11) #elif defined(USE_X11)
Display *rDisplay = XOpenDisplay(NULL); Display *rDisplay = XOpenDisplay(NULL);
// If atoms loaded // If atoms loaded
@ -34,10 +34,10 @@ void initWindow(uintptr handle){
if (rDisplay != NULL) {LoadAtoms();} if (rDisplay != NULL) {LoadAtoms();}
} }
pub_mData.XWin = 0; mData.XWin = 0;
XCloseDisplay(rDisplay); XCloseDisplay(rDisplay);
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
pub_mData.HWnd = 0; mData.HWnd = 0;
#endif #endif
setHandle(handle); setHandle(handle);
} }
@ -50,7 +50,7 @@ bool Is64Bit() {
return false; return false;
} }
MData set_handle_pid(uintptr pid, int8_t isPid){ MData set_handle_pid(uintptr pid, uintptr isHwnd){
MData win; MData win;
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
// Handle to a AXUIElementRef // Handle to a AXUIElementRef
@ -59,41 +59,45 @@ MData set_handle_pid(uintptr pid, int8_t isPid){
win.XWin = (Window)pid; // Handle to an X11 window win.XWin = (Window)pid; // Handle to an X11 window
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
// win.HWnd = (HWND)pid; // Handle to a window HWND // win.HWnd = (HWND)pid; // Handle to a window HWND
win.HWnd = getHwnd(pid, isPid); if (isHwnd == 0) {
win.HWnd = GetHwndByPId(pid);
} else {
win.HWnd = (HWND)pid;
}
#endif #endif
return win; return win;
} }
void set_handle_pid_mData(uintptr pid, int8_t isPid){ void set_handle_pid_mData(uintptr pid, uintptr isHwnd){
MData win = set_handle_pid(pid, isPid); MData win = set_handle_pid(pid, isHwnd);
pub_mData = win; mData = win;
} }
bool is_valid() { bool is_valid() {
initWindow(initHandle); initWindow(initHandle);
if (!IsAxEnabled(true)) { if (!IsAxEnabled(true)) {
printf("%s\n", "Window: Accessibility API is disabled! " printf("%s\n", "Window: Accessibility API is disabled!\n"
"Failed to enable access for assistive devices. \n"); "Failed to enable access for assistive devices.");
} }
MData actdata = get_active(); MData actdata = get_active();
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
pub_mData.CgID = actdata.CgID; mData.CgID = actdata.CgID;
pub_mData.AxID = actdata.AxID; mData.AxID = actdata.AxID;
if (pub_mData.CgID == 0 || pub_mData.AxID == 0) { return false; } if (mData.CgID == 0 || mData.AxID == 0) { return false; }
CFTypeRef r = NULL; CFTypeRef r = NULL;
// Attempt to get the window role // Attempt to get the window role
if (AXUIElementCopyAttributeValue(pub_mData.AxID, kAXRoleAttribute, &r) == kAXErrorSuccess && r){ if (AXUIElementCopyAttributeValue(mData.AxID, kAXRoleAttribute, &r) == kAXErrorSuccess && r){
CFRelease(r); CFRelease(r);
return true; return true;
} }
return false; return false;
#elif defined(USE_X11) #elif defined(USE_X11)
pub_mData.XWin = actdata.XWin; mData.XWin = actdata.XWin;
if (pub_mData.XWin == 0) { return false; } if (mData.XWin == 0) { return false; }
Display *rDisplay = XOpenDisplay(NULL); Display *rDisplay = XOpenDisplay(NULL);
// Check for a valid X-Window display // Check for a valid X-Window display
@ -103,11 +107,8 @@ bool is_valid() {
XDismissErrors(); XDismissErrors();
// Get the window PID property // Get the window PID property
void* result = GetWindowProperty(pub_mData, WM_PID,NULL); void* result = GetWindowProperty(mData, WM_PID,NULL);
if (result == NULL) { if (result == NULL) { return false; }
XCloseDisplay(rDisplay);
return false;
}
// Free result and return true // Free result and return true
XFree(result); XFree(result);
@ -115,12 +116,12 @@ bool is_valid() {
return true; return true;
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
pub_mData.HWnd = actdata.HWnd; mData.HWnd = actdata.HWnd;
if (pub_mData.HWnd == 0) { if (mData.HWnd == 0) {
return false; return false;
} }
return IsWindow(pub_mData.HWnd) != 0; return IsWindow(mData.HWnd) != 0;
#endif #endif
} }
@ -175,13 +176,13 @@ bool IsAxEnabled(bool options){
bool setHandle(uintptr handle){ bool setHandle(uintptr handle){
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
// Release the AX element // Release the AX element
if (pub_mData.AxID != NULL) { if (mData.AxID != NULL) {
CFRelease(pub_mData.AxID); CFRelease(mData.AxID);
} }
// Reset both values // Reset both values
pub_mData.CgID = 0; mData.CgID = 0;
pub_mData.AxID = 0; mData.AxID = 0;
if (handle == 0) { if (handle == 0) {
// return 0; // return 0;
@ -192,8 +193,8 @@ bool setHandle(uintptr handle){
CGWindowID cgID = (CGWindowID)handle; CGWindowID cgID = (CGWindowID)handle;
AXUIElementRef axID = GetUIElement(cgID); AXUIElementRef axID = GetUIElement(cgID);
if (axID != NULL){ if (axID != NULL){
pub_mData.CgID = cgID; mData.CgID = cgID;
pub_mData.AxID = axID; mData.AxID = axID;
// return 0; // return 0;
return true; return true;
} }
@ -201,7 +202,7 @@ bool setHandle(uintptr handle){
// return 1; // return 1;
return false; return false;
#elif defined(USE_X11) #elif defined(USE_X11)
pub_mData.XWin = (Window)handle; mData.XWin = (Window)handle;
if (handle == 0) { if (handle == 0) {
return true; return true;
} }
@ -210,10 +211,10 @@ bool setHandle(uintptr handle){
return true; return true;
} }
pub_mData.XWin = 0; mData.XWin = 0;
return false; return false;
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
pub_mData.HWnd = (HWND)handle; mData.HWnd = (HWND)handle;
if (handle == 0) { if (handle == 0) {
return true; return true;
} }
@ -222,7 +223,7 @@ bool setHandle(uintptr handle){
return true; return true;
} }
pub_mData.HWnd = 0; mData.HWnd = 0;
return false; return false;
#endif #endif
} }
@ -237,7 +238,7 @@ bool IsTopMost(void){
// XDismissErrors (); // XDismissErrors ();
// return GetState (mData.XWin, STATE_TOPMOST); // return GetState (mData.XWin, STATE_TOPMOST);
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
return (GetWindowLongPtr(pub_mData.HWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; return (GetWindowLongPtr(mData.HWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
#endif #endif
} }
@ -247,7 +248,7 @@ bool IsMinimized(void){
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
CFBooleanRef data = NULL; CFBooleanRef data = NULL;
// Determine whether the window is minimized // Determine whether the window is minimized
if (AXUIElementCopyAttributeValue(pub_mData.AxID, kAXMinimizedAttribute, if (AXUIElementCopyAttributeValue(mData.AxID, kAXMinimizedAttribute,
(CFTypeRef*) &data) == kAXErrorSuccess && data != NULL) { (CFTypeRef*) &data) == kAXErrorSuccess && data != NULL) {
// Convert resulting data into a bool // Convert resulting data into a bool
bool result = CFBooleanGetValue(data); bool result = CFBooleanGetValue(data);
@ -261,7 +262,7 @@ bool IsMinimized(void){
// XDismissErrors(); // XDismissErrors();
// return GetState(mData.XWin, STATE_MINIMIZE); // return GetState(mData.XWin, STATE_MINIMIZE);
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
return (GetWindowLongPtr(pub_mData.HWnd, GWL_STYLE) & WS_MINIMIZE) != 0; return (GetWindowLongPtr(mData.HWnd, GWL_STYLE) & WS_MINIMIZE) != 0;
#endif #endif
} }
@ -276,7 +277,7 @@ bool IsMaximized(void){
// XDismissErrors(); // XDismissErrors();
// return GetState(mData.XWin, STATE_MAXIMIZE); // return GetState(mData.XWin, STATE_MAXIMIZE);
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
return (GetWindowLongPtr(pub_mData.HWnd, GWL_STYLE) & WS_MAXIMIZE) != 0; return (GetWindowLongPtr(mData.HWnd, GWL_STYLE) & WS_MAXIMIZE) != 0;
#endif #endif
} }
@ -367,11 +368,11 @@ MData get_active(void) {
if (focused == NULL) { return result; } // Verify if (focused == NULL) { return result; } // Verify
AXUIElementRef element; AXUIElementRef element;
CGWindowID win = 0;
// Retrieve the currently focused window // Retrieve the currently focused window
if (AXUIElementCopyAttributeValue(focused, kAXFocusedWindowAttribute, (CFTypeRef*) &element) if (AXUIElementCopyAttributeValue(focused, kAXFocusedWindowAttribute, (CFTypeRef*) &element)
== kAXErrorSuccess && element) { == kAXErrorSuccess && element) {
CGWindowID win = 0;
// Use undocumented API to get WID // Use undocumented API to get WID
if (_AXUIElementGetWindow(element, &win) == kAXErrorSuccess && win) { if (_AXUIElementGetWindow(element, &win) == kAXErrorSuccess && win) {
// Manually set internals // Manually set internals
@ -380,9 +381,6 @@ MData get_active(void) {
} else { } else {
CFRelease(element); CFRelease(element);
} }
} else {
result.CgID = win;
result.AxID = element;
} }
CFRelease(focused); CFRelease(focused);
@ -411,7 +409,6 @@ MData get_active(void) {
if (window != 0) { if (window != 0) {
// Set and return the foreground window // Set and return the foreground window
result.XWin = (Window)window; result.XWin = (Window)window;
XCloseDisplay(rDisplay);
return result; return result;
} }
} }
@ -453,9 +450,9 @@ void SetTopMost(bool state){
#elif defined(USE_X11) #elif defined(USE_X11)
// Ignore X errors // Ignore X errors
// XDismissErrors(); // XDismissErrors();
// SetState(pub_mData.XWin, STATE_TOPMOST, state); // SetState(mData.XWin, STATE_TOPMOST, state);
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
SetWindowPos(pub_mData.HWnd, state ? HWND_TOPMOST : HWND_NOTOPMOST, SetWindowPos(mData.HWnd, state ? HWND_TOPMOST : HWND_NOTOPMOST,
0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
#endif #endif
} }
@ -464,11 +461,11 @@ void close_main_window () {
// Check if the window is valid // Check if the window is valid
if (!is_valid()) { return; } if (!is_valid()) { return; }
close_window_by_Id(pub_mData); close_window_by_Id(mData);
} }
void close_window_by_PId(uintptr pid, int8_t isPid){ void close_window_by_PId(uintptr pid, uintptr isHwnd){
MData win = set_handle_pid(pid, isPid); MData win = set_handle_pid(pid, isHwnd);
close_window_by_Id(win); close_window_by_Id(win);
} }
@ -502,11 +499,11 @@ char* get_main_title(){
// Check if the window is valid // Check if the window is valid
if (!is_valid()) { return "is_valid failed."; } if (!is_valid()) { return "is_valid failed."; }
return get_title_by_hand(pub_mData); return get_title_by_hand(mData);
} }
char* get_title_by_pid(uintptr pid, int8_t isPid){ char* get_title_by_pid(uintptr pid, uintptr isHwnd){
MData win = set_handle_pid(pid, isPid); MData win = set_handle_pid(pid, isHwnd);
return get_title_by_hand(win); return get_title_by_hand(win);
} }
@ -591,7 +588,7 @@ int32_t get_PID(void) {
#if defined(IS_MACOSX) #if defined(IS_MACOSX)
pid_t pid = 0; pid_t pid = 0;
// Attempt to retrieve the window pid // Attempt to retrieve the window pid
if (AXUIElementGetPid(pub_mData.AxID, &pid)== kAXErrorSuccess) { if (AXUIElementGetPid(mData.AxID, &pid)== kAXErrorSuccess) {
return pid; return pid;
} }
return 0; return 0;
@ -600,7 +597,7 @@ int32_t get_PID(void) {
XDismissErrors(); XDismissErrors();
// Get the window PID // Get the window PID
long* result = (long*)GetWindowProperty(pub_mData, WM_PID,NULL); long* result = (long*)GetWindowProperty(mData, WM_PID,NULL);
// Check result and convert it // Check result and convert it
if (result == NULL) { return 0; } if (result == NULL) { return 0; }
@ -609,7 +606,7 @@ int32_t get_PID(void) {
return pid; return pid;
#elif defined(IS_WINDOWS) #elif defined(IS_WINDOWS)
DWORD id = 0; DWORD id = 0;
GetWindowThreadProcessId(pub_mData.HWnd, &id); GetWindowThreadProcessId(mData.HWnd, &id);
return id; return id;
#endif #endif
} }

View File

@ -1,2 +0,0 @@
// +bulid windows,next
package robotgo