mirror of
https://github.com/go-vgo/robotgo.git
synced 2025-06-01 14:43:55 +00:00
Compare commits
193 Commits
v1.0.0-bet
...
master
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a8c387a070 | ||
![]() |
3eef3b5879 | ||
![]() |
b731094f61 | ||
![]() |
8d4679db07 | ||
![]() |
02c668a946 | ||
![]() |
5c2864485d | ||
![]() |
f101b10497 | ||
![]() |
73c07dc991 | ||
![]() |
fc47bc8216 | ||
![]() |
912ddcbfe4 | ||
![]() |
57b5e5bca2 | ||
![]() |
8031f7f526 | ||
![]() |
36bc85ad19 | ||
![]() |
5fc2bd4c73 | ||
![]() |
47abfac5ee | ||
![]() |
df0731c4df | ||
![]() |
03432155c1 | ||
![]() |
6a1f060a8c | ||
![]() |
e924f25fe1 | ||
![]() |
d300eedf54 | ||
![]() |
c07f3f0171 | ||
![]() |
0b18fa5058 | ||
![]() |
471f7ba05f | ||
![]() |
a84a195c4c | ||
![]() |
c8df366f89 | ||
![]() |
70f811ce53 | ||
![]() |
ecc260ea31 | ||
![]() |
78d01703b8 | ||
![]() |
47cde13dab | ||
![]() |
8db59aac2d | ||
![]() |
217d6cf1f1 | ||
![]() |
75fd24ea0a | ||
![]() |
bed6776ca2 | ||
![]() |
1923d7bb48 | ||
![]() |
ead43d062e | ||
![]() |
3258566802 | ||
![]() |
0de26ecee4 | ||
![]() |
c48e3d072c | ||
![]() |
b1ad7db6be | ||
![]() |
0110b85d40 | ||
![]() |
3e5b10f720 | ||
![]() |
cb51e2aa10 | ||
![]() |
85f2702683 | ||
![]() |
5b9871b063 | ||
![]() |
b201ab9f80 | ||
![]() |
d3e364fa26 | ||
![]() |
1f437d12e4 | ||
![]() |
c5110d0ac8 | ||
![]() |
f98b4c52bd | ||
![]() |
f1db2ede4a | ||
![]() |
d90493e63e | ||
![]() |
63eb594ea5 | ||
![]() |
8a990ac042 | ||
![]() |
bf1758b424 | ||
![]() |
9424b71a73 | ||
![]() |
6c137427db | ||
![]() |
ffbf4f875b | ||
![]() |
05c54c6f25 | ||
![]() |
3171c5bdff | ||
![]() |
b718cf4a8c | ||
![]() |
bfc28d12fa | ||
![]() |
e9421b58b6 | ||
![]() |
4d780b9908 | ||
![]() |
39818d41fa | ||
![]() |
eacf74f488 | ||
![]() |
61b77ce3e1 | ||
![]() |
01e4fffcb8 | ||
![]() |
e2f5f54804 | ||
![]() |
f22f063926 | ||
![]() |
722feb7ba3 | ||
![]() |
dbf0d84f12 | ||
![]() |
b8a6b1778e | ||
![]() |
a780825c09 | ||
![]() |
de675b4dd2 | ||
![]() |
ef191f2dfd | ||
![]() |
44b2715de0 | ||
![]() |
90f41269da | ||
![]() |
8a5ca54915 | ||
![]() |
5b0ac98ef3 | ||
![]() |
c2b5c864d2 | ||
![]() |
0c4055bfee | ||
![]() |
af32110521 | ||
![]() |
5c3cbd6e17 | ||
![]() |
3182fb9d73 | ||
![]() |
6fa2f418fa | ||
![]() |
8e7a413ec6 | ||
![]() |
8ce3a5dff0 | ||
![]() |
8ea126d35b | ||
![]() |
c62f7fd81e | ||
![]() |
92fd032685 | ||
![]() |
ffcf6b26cd | ||
![]() |
451bb91209 | ||
![]() |
cbca6d08c7 | ||
![]() |
d249cdcd9e | ||
![]() |
4140463ed1 | ||
![]() |
186bceb9d0 | ||
![]() |
01212c5684 | ||
![]() |
07dd53a897 | ||
![]() |
9afa311121 | ||
![]() |
94be6c56c1 | ||
![]() |
e0583e83ec | ||
![]() |
6a2ffab625 | ||
![]() |
679aef0f70 | ||
![]() |
cc6f1934f9 | ||
![]() |
4bdacf4187 | ||
![]() |
c8d35acd24 | ||
![]() |
e4848b4608 | ||
![]() |
f47571eaae | ||
![]() |
dd149367b3 | ||
![]() |
da736a93ee | ||
![]() |
73a40e7861 | ||
![]() |
5e5c4ddbfa | ||
![]() |
23d3df9027 | ||
![]() |
bb76af18f0 | ||
![]() |
b13320884a | ||
![]() |
df1617d894 | ||
![]() |
b20007917d | ||
![]() |
f830c8ed13 | ||
![]() |
736fa1cc26 | ||
![]() |
9f8d308eaa | ||
![]() |
95be5f752f | ||
![]() |
4bc64ebf67 | ||
![]() |
bdae1a7759 | ||
![]() |
c9e1c3db67 | ||
![]() |
e8b3975205 | ||
![]() |
f4f4a3d319 | ||
![]() |
3052272818 | ||
![]() |
6313e52156 | ||
![]() |
f911550742 | ||
![]() |
2f936e1f49 | ||
![]() |
7aa5beb8f7 | ||
![]() |
4eea01b88d | ||
![]() |
7103f6b891 | ||
![]() |
bb90d71b5f | ||
![]() |
0ef48f1c4d | ||
![]() |
be6984fd34 | ||
![]() |
2f2ed595f6 | ||
![]() |
5079db2df7 | ||
![]() |
469cd4da5e | ||
![]() |
a8faa0e906 | ||
![]() |
0293ab5d0c | ||
![]() |
fc5dac6f8a | ||
![]() |
4bf054f47a | ||
![]() |
c3cda41c2d | ||
![]() |
e9b5a9251e | ||
![]() |
47ca6812fe | ||
![]() |
4ad733fe83 | ||
![]() |
f428ffb1fb | ||
![]() |
a1cb2ebef2 | ||
![]() |
31c248aedd | ||
![]() |
db2eda3e1f | ||
![]() |
ee25e577e5 | ||
![]() |
62c61cf52a | ||
![]() |
1934220f50 | ||
![]() |
673c9a68a3 | ||
![]() |
e08e05307e | ||
![]() |
e53c75ff95 | ||
![]() |
c5cdd0a33f | ||
![]() |
8ba7338861 | ||
![]() |
7df3bc3800 | ||
![]() |
8744c88f5f | ||
![]() |
e533734f0b | ||
![]() |
a2e387b448 | ||
![]() |
bfa6b232be | ||
![]() |
51ca08e484 | ||
![]() |
debc2719ee | ||
![]() |
985c590284 | ||
![]() |
94c4b98edd | ||
![]() |
895aed8f22 | ||
![]() |
6bf430b1cd | ||
![]() |
1d2ec44308 | ||
![]() |
60bf136aa1 | ||
![]() |
e7c518eb2a | ||
![]() |
e755317599 | ||
![]() |
efc7c90b9f | ||
![]() |
c493c4981d | ||
![]() |
f110d5bf9e | ||
![]() |
ade0381d15 | ||
![]() |
0dcc87c355 | ||
![]() |
3d7cce3a31 | ||
![]() |
60ddc20e02 | ||
![]() |
16e0808dbd | ||
![]() |
3278758575 | ||
![]() |
389f7c6802 | ||
![]() |
ffa27a50cc | ||
![]() |
e1c5590f30 | ||
![]() |
93a9f8194f | ||
![]() |
a917683d97 | ||
![]() |
34d0fbf4bc | ||
![]() |
3e97de3745 | ||
![]() |
2f79ebe879 | ||
![]() |
ab66b269b8 | ||
![]() |
a00655dbe4 |
@ -5,7 +5,7 @@ jobs:
|
||||
docker:
|
||||
# using custom image, see .circleci/images/primary/Dockerfile
|
||||
# - image: govgo/robotgoci:1.10.3
|
||||
- image: golang:1.17.6
|
||||
- image: golang:1.23.0
|
||||
working_directory: /gopath/src/github.com/go-vgo/robotgo
|
||||
steps:
|
||||
- checkout
|
||||
@ -20,7 +20,6 @@ jobs:
|
||||
- run: apt -y install xvfb
|
||||
#
|
||||
# override:
|
||||
# - run: go get -u github.com/go-vgo/robotgo
|
||||
- run: go get -v -t -d ./...
|
||||
- run: xvfb-run go test -v ./...
|
||||
#
|
||||
|
@ -1,5 +1,5 @@
|
||||
# FROM golang:1.10.1
|
||||
FROM golang:1.17.6-stretch AS build
|
||||
FROM golang:1.24.2-stretch AS build
|
||||
# FROM govgo/go:1.11.1
|
||||
|
||||
RUN apt update && apt install -y --no-install-recommends \
|
||||
|
2
.github/issue_template.md
vendored
2
.github/issue_template.md
vendored
@ -1,4 +1,4 @@
|
||||
1. Please **speak English**, this is the language everybody of us can speak and write.
|
||||
1. Please **speak English (English only)**, 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**.
|
||||
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 -->
|
||||
|
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@ -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)
|
||||
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.
|
||||
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.**
|
||||
|
||||
|
4
.github/workflows/go.yml
vendored
4
.github/workflows/go.yml
vendored
@ -10,10 +10,10 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Set up Go 1.17
|
||||
- name: Set up Go 1.24.0
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.17
|
||||
go-version: 1.24.0
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
|
@ -15,7 +15,9 @@ go:
|
||||
# - 1.14.x
|
||||
# - 1.15.x
|
||||
# - 1.16.x
|
||||
- 1.17.x
|
||||
# - 1.17.x
|
||||
# - 1.18.x
|
||||
- 1.19.x
|
||||
# - tip
|
||||
|
||||
addons:
|
||||
|
@ -24,7 +24,7 @@ This process gives everyone a chance to validate the design, helps prevent dupli
|
||||
|
||||
## 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 continous 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 continuous testing.
|
||||
|
||||
## Code review
|
||||
|
||||
|
166
README.md
166
README.md
@ -4,29 +4,33 @@
|
||||
<!--[](https://travis-ci.org/go-vgo/robotgo)
|
||||
[](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>-->
|
||||
|
||||
[](https://github.com/go-vgo/robotgo/commits/master)
|
||||
[](https://circleci.com/gh/go-vgo/robotgo)
|
||||
[](https://travis-ci.org/go-vgo/robotgo)
|
||||

|
||||
[](https://goreportcard.com/report/github.com/go-vgo/robotgo)
|
||||
[](https://godoc.org/github.com/go-vgo/robotgo)
|
||||
[](https://pkg.go.dev/github.com/go-vgo/robotgo?tab=doc)
|
||||
[](https://github.com/go-vgo/robotgo/releases/latest)
|
||||
[](https://gitter.im/go-vgo/robotgo?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
<!-- [](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> -->
|
||||
|
||||
> Golang Desktop Automation. Control the mouse, keyboard, bitmap and image, read the screen, process, Window Handle and global event listener.
|
||||
> Golang Desktop Automation. Control the mouse, keyboard, read the screen, process, Window Handle, image and bitmap and global event listener.
|
||||
|
||||
RobotGo supports Mac, Windows, and Linux(X11); and robotgo supports arm64 and x86-amd64.
|
||||
|
||||
## Contents
|
||||
|
||||
- [Docs](#docs)
|
||||
- [Binding](#binding)
|
||||
- [Requirements](#requirements)
|
||||
- [Installation](#installation)
|
||||
- [Update](#update)
|
||||
- [Examples](#examples)
|
||||
- [Cross-Compiling](#crosscompiling)
|
||||
- [Type Conversion and keys](https://github.com/go-vgo/robotgo/blob/master/docs/keys.md)
|
||||
- [Cross-Compiling](https://github.com/go-vgo/robotgo/blob/master/docs/install.md#crosscompiling)
|
||||
- [Authors](#authors)
|
||||
- [Plans](#plans)
|
||||
- [Donate](#donate)
|
||||
@ -34,10 +38,12 @@ RobotGo supports Mac, Windows, and Linux(X11); and robotgo supports arm64 and x8
|
||||
- [License](#license)
|
||||
|
||||
## Docs
|
||||
- [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)
|
||||
|
||||
- [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)
|
||||
|
||||
## Binding:
|
||||
|
||||
[ADB](https://github.com/vcaesar/adb), packaging android adb API.
|
||||
|
||||
[Robotn](https://github.com/vcaesar/robotn), binding JavaScript and other, support more language.
|
||||
@ -47,28 +53,40 @@ 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.
|
||||
|
||||
### ALL:
|
||||
|
||||
```
|
||||
Golang
|
||||
|
||||
GCC
|
||||
```
|
||||
|
||||
#### For Mac OS X:
|
||||
#### For MacOS:
|
||||
```
|
||||
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))
|
||||
|
||||
```
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
#### For Windows:
|
||||
|
||||
[MinGW-w64](https://sourceforge.net/projects/mingw-w64/files) (Use recommended)
|
||||
```
|
||||
winget install Golang.go
|
||||
```
|
||||
|
||||
```
|
||||
Or the other GCC (But you should compile the "libpng" with yourself when use the bitmap.)
|
||||
winget install MartinStorsjo.LLVM-MinGW.UCRT
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
@ -76,52 +94,55 @@ GCC
|
||||
|
||||
X11 with the XTest extension (the Xtst library)
|
||||
|
||||
"Clipboard": xsel xclip
|
||||
|
||||
"Bitmap":
|
||||
|
||||
libpng (Just used by bitmap)
|
||||
"Bitmap": libpng (Just used by the "bitmap".)
|
||||
|
||||
"Event":
|
||||
"Event-Gohook": xcb, xkb, libxkbcommon (Just used by the "hook".)
|
||||
|
||||
xcb, xkb, libxkbcommon
|
||||
|
||||
"Clipboard":
|
||||
|
||||
xsel xclip
|
||||
```
|
||||
|
||||
##### Ubuntu:
|
||||
|
||||
```yml
|
||||
# sudo apt install golang
|
||||
sudo snap install go --classic
|
||||
|
||||
# gcc
|
||||
sudo apt install gcc libc6-dev
|
||||
|
||||
# x11
|
||||
sudo apt install libx11-dev xorg-dev libxtst-dev
|
||||
|
||||
# Clipboard
|
||||
sudo apt install xsel xclip
|
||||
|
||||
#
|
||||
# Bitmap
|
||||
sudo apt install libpng++-dev
|
||||
|
||||
# Hook
|
||||
# GoHook
|
||||
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:
|
||||
|
||||
```yml
|
||||
sudo dnf install libXtst-devel
|
||||
|
||||
# Bitmap
|
||||
sudo dnf install libpng-devel
|
||||
|
||||
# Hook
|
||||
sudo dnf install libxkbcommon-devel libxkbcommon-x11-devel xorg-x11-xkb-utils-devel
|
||||
# x11
|
||||
sudo dnf install libXtst-devel
|
||||
|
||||
# Clipboard
|
||||
sudo dnf install xsel xclip
|
||||
|
||||
#
|
||||
# Bitmap
|
||||
sudo dnf install libpng-devel
|
||||
|
||||
# GoHook
|
||||
sudo dnf install libxkbcommon-devel libxkbcommon-x11-devel xorg-x11-xkb-utils-devel
|
||||
|
||||
```
|
||||
|
||||
## Installation:
|
||||
@ -141,6 +162,7 @@ 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).
|
||||
|
||||
## Update:
|
||||
|
||||
```
|
||||
go get -u github.com/go-vgo/robotgo
|
||||
```
|
||||
@ -148,7 +170,6 @@ 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).
|
||||
`go mod vendor` problem, [golang #26366](https://github.com/golang/go/issues/26366).
|
||||
|
||||
|
||||
## [Examples:](https://github.com/go-vgo/robotgo/blob/master/examples)
|
||||
|
||||
#### [Mouse](https://github.com/go-vgo/robotgo/blob/master/examples/mouse/main.go)
|
||||
@ -157,14 +178,21 @@ Note go1.10.x C file compilation cache problem, [golang #24355](https://github.c
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-vgo/robotgo"
|
||||
)
|
||||
|
||||
func main() {
|
||||
robotgo.MouseSleep = 100
|
||||
robotgo.MouseSleep = 300
|
||||
|
||||
robotgo.ScrollMouse(10, "up")
|
||||
robotgo.ScrollMouse(20, "right")
|
||||
robotgo.Move(100, 100)
|
||||
fmt.Println(robotgo.Location())
|
||||
robotgo.Move(100, -200) // multi screen supported
|
||||
robotgo.MoveSmooth(120, -150)
|
||||
fmt.Println(robotgo.Location())
|
||||
|
||||
robotgo.ScrollDir(10, "up")
|
||||
robotgo.ScrollDir(20, "right")
|
||||
|
||||
robotgo.Scroll(0, -10)
|
||||
robotgo.Scroll(100, 0)
|
||||
@ -199,10 +227,11 @@ import (
|
||||
|
||||
func main() {
|
||||
robotgo.TypeStr("Hello World")
|
||||
robotgo.TypeStr("だんしゃり", 1)
|
||||
robotgo.TypeStr("だんしゃり", 0, 1)
|
||||
// robotgo.TypeStr("テストする")
|
||||
|
||||
robotgo.TypeStr("Hi galaxy. こんにちは世界.")
|
||||
robotgo.TypeStr("Hi, Seattle space needle, Golden gate bridge, One world trade center.")
|
||||
robotgo.TypeStr("Hi galaxy, hi stars, hi MT.Rainier, hi sea. こんにちは世界.")
|
||||
robotgo.Sleep(1)
|
||||
|
||||
// ustr := uint32(robotgo.CharCodeAt("Test", 0))
|
||||
@ -235,13 +264,14 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-vgo/robotgo"
|
||||
"github.com/vcaesar/imgo"
|
||||
)
|
||||
|
||||
func main() {
|
||||
x, y := robotgo.GetMousePos()
|
||||
x, y := robotgo.Location()
|
||||
fmt.Println("pos: ", x, y)
|
||||
|
||||
color := robotgo.GetPixelColor(100, 200)
|
||||
@ -259,18 +289,23 @@ func main() {
|
||||
num := robotgo.DisplaysNum()
|
||||
for i := 0; i < num; i++ {
|
||||
robotgo.DisplayID = i
|
||||
img1 := robotgo.CaptureImg()
|
||||
img1, _ := robotgo.CaptureImg()
|
||||
path1 := "save_" + strconv.Itoa(i)
|
||||
robotgo.Save(img1, path1+".png")
|
||||
robotgo.SaveJpeg(img1, path1+".jpeg", 50)
|
||||
|
||||
img2 := robotgo.CaptureImg(10, 10, 20, 20)
|
||||
img2, _ := robotgo.CaptureImg(10, 10, 20, 20)
|
||||
robotgo.Save(img2, "test_"+strconv.Itoa(i)+".png")
|
||||
|
||||
x, y, w, h := robotgo.GetDisplayBounds(i)
|
||||
img3, err := robotgo.CaptureImg(x, y, w, h)
|
||||
fmt.Println("Capture error: ", err)
|
||||
robotgo.Save(img3, path1+"_1.png")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### [Bitmap](https://github.com/vcaesar/bitmap/blob/master/examples/main.go)
|
||||
#### [Bitmap](https://github.com/vcaesar/bitmap/blob/main/examples/main.go)
|
||||
|
||||
```Go
|
||||
package main
|
||||
@ -345,8 +380,8 @@ func opencv() {
|
||||
// bit1 := robotgo.CaptureScreen(10, 10, 30, 30)
|
||||
// img1 := robotgo.ToImage(bit1)
|
||||
// defer robotgo.FreeBitmapArr(bit0, bit1)
|
||||
img := robotgo.CaptureImg()
|
||||
img1 := robotgo.CaptureImg(10, 10, 30, 30)
|
||||
img, _ := robotgo.CaptureImg()
|
||||
img1, _ := robotgo.CaptureImg(10, 10, 30, 30)
|
||||
|
||||
fmt.Print("gcv find image: ")
|
||||
fmt.Println(gcv.FindImg(img1, img))
|
||||
@ -448,7 +483,13 @@ func main() {
|
||||
fmt.Println("pids... ", fpid)
|
||||
|
||||
if len(fpid) > 0 {
|
||||
robotgo.ActivePID(fpid[0])
|
||||
robotgo.TypeStr("Hi galaxy!", fpid[0])
|
||||
robotgo.KeyTap("a", fpid[0], "cmd")
|
||||
|
||||
robotgo.KeyToggle("a", fpid[0])
|
||||
robotgo.KeyToggle("a", fpid[0], "up")
|
||||
|
||||
robotgo.ActivePid(fpid[0])
|
||||
|
||||
robotgo.Kill(fpid[0])
|
||||
}
|
||||
@ -473,48 +514,19 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
## CrossCompiling
|
||||
|
||||
##### Windows64 to windows32
|
||||
```Go
|
||||
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)
|
||||
|
||||
- [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
|
||||
|
||||
- Refactor some C code to Go (such as x11, windows)
|
||||
- Better multiscreen support
|
||||
- Waylad supports
|
||||
- Wayland support
|
||||
- Update Window Handle
|
||||
- Try support Android and IOS
|
||||
- Try to support Android and IOS
|
||||
|
||||
## Contributors
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
# Robotgo
|
||||
|
||||
## !!! Warning: this page not updated !!!
|
||||
|
||||
[](https://github.com/go-vgo/robotgo/commits/master)
|
||||
[](https://circleci.com/gh/go-vgo/robotgo)
|
||||
[](https://travis-ci.org/go-vgo/robotgo)
|
||||
@ -67,7 +69,7 @@ xcode-select --install
|
||||
|
||||
```
|
||||
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 等其他系统):
|
||||
|
@ -34,7 +34,7 @@ environment:
|
||||
PATH: C:\msys64\mingw32\bin\;C:\Program Files (x86)\NSIS\;%PATH%
|
||||
# - COMPILER: MINGW_W64
|
||||
# ARCHITECTURE: x64
|
||||
GOVERSION: 1.17.6
|
||||
GOVERSION: 1.23.0
|
||||
# GOPATH: c:\gopath
|
||||
|
||||
# scripts that run after cloning repository
|
||||
|
@ -11,6 +11,7 @@ struct _MMBitmap {
|
||||
uint8_t *imageBuffer; /* Pixels stored in Quad I format; */
|
||||
int32_t width; /* Never 0, unless image is NULL. */
|
||||
int32_t height; /* Never 0, unless image is NULL. */
|
||||
|
||||
int32_t bytewidth; /* The aligned width (width + padding). */
|
||||
uint8_t bitsPerPixel; /* Should be either 24 or 32. */
|
||||
uint8_t bytesPerPixel; /* For convenience; should be bitsPerPixel / 8. */
|
||||
|
@ -22,12 +22,12 @@
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HWND GetHwndByPId(DWORD dwProcessId) {
|
||||
HWND GetHwndByPid(DWORD dwProcessId) {
|
||||
WNDINFO info = {0};
|
||||
info.hWnd = NULL;
|
||||
info.dwPid = dwProcessId;
|
||||
EnumWindows(EnumWindowsProc, (LPARAM)&info);
|
||||
// printf("%d\n", info.hWnd);
|
||||
|
||||
return info.hWnd;
|
||||
}
|
||||
#endif
|
@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
|
||||
Package clipboard read/write on clipboard
|
||||
*/
|
||||
package clipboard
|
||||
|
@ -1,14 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/go-vgo/robotgo/clipboard"
|
||||
)
|
||||
|
||||
func main() {
|
||||
out, err := ioutil.ReadAll(os.Stdin)
|
||||
out, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
2
doc.go
2
doc.go
@ -54,7 +54,7 @@ Keys are supported:
|
||||
"f23"
|
||||
"f24"
|
||||
|
||||
"cmd" is the "win" key for windows
|
||||
"cmd" this is the "win" key for windows
|
||||
"lcmd" left command
|
||||
"rcmd" right command
|
||||
// "command"
|
||||
|
33
docs/install.md
Normal file
33
docs/install.md
Normal file
@ -0,0 +1,33 @@
|
||||
## 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).
|
24
docs/keys.md
24
docs/keys.md
@ -1,3 +1,25 @@
|
||||
## 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
|
||||
|
||||
```Go
|
||||
@ -118,4 +140,4 @@
|
||||
"lights_kbd_toggle" Toggle keyboard backlight on/off No Windows support
|
||||
"lights_kbd_up" Turn up keyboard backlight brightness No Windows support
|
||||
"lights_kbd_down" Turn down keyboard backlight brightness No Windows support
|
||||
```
|
||||
```
|
||||
|
@ -68,7 +68,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
x, y := robotgo.GetMousePos()
|
||||
x, y := robotgo.Location()
|
||||
fmt.Println("pos:", x, y)
|
||||
color := robotgo.GetPixelColor(100, 200)
|
||||
fmt.Println("color----", color)
|
||||
|
@ -18,15 +18,16 @@ import (
|
||||
)
|
||||
|
||||
func typeStr() {
|
||||
// importing "Hello World"
|
||||
robotgo.TypeStr("Hello World!", 1)
|
||||
// typing "Hello World"
|
||||
robotgo.TypeStr("Hello World!", 0, 1)
|
||||
robotgo.KeySleep = 100
|
||||
robotgo.TypeStr("だんしゃり")
|
||||
|
||||
robotgo.TypeStr("Hi galaxy. こんにちは世界. 你好, 再见!")
|
||||
robotgo.TypeStr("Hi galaxy, hi stars, hi MT.Rainier, hi sea. こんにちは世界.")
|
||||
robotgo.TypeStr("So, hi, bye! 你好, 再见!")
|
||||
robotgo.Sleep(1)
|
||||
|
||||
robotgo.TypeStr("So, hi, bye!")
|
||||
robotgo.TypeStr("Hi, Seattle space needle, Golden gate bridge, One world trade center.")
|
||||
robotgo.MilliSleep(100)
|
||||
|
||||
ustr := uint32(robotgo.CharCodeAt("So, hi, bye!", 0))
|
||||
@ -73,6 +74,14 @@ func keyTap() {
|
||||
robotgo.KeyTap("a", "control")
|
||||
}
|
||||
|
||||
func special() {
|
||||
robotgo.TypeStr("{}")
|
||||
robotgo.KeyTap("[", "]")
|
||||
|
||||
robotgo.KeyToggle("(")
|
||||
robotgo.KeyToggle("(", "up")
|
||||
}
|
||||
|
||||
func keyToggle() {
|
||||
// robotgo.KeySleep = 150
|
||||
robotgo.KeyToggle(robotgo.KeyA)
|
||||
@ -112,6 +121,7 @@ func key() {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typeStr()
|
||||
special()
|
||||
|
||||
keyTap()
|
||||
keyToggle()
|
||||
|
@ -25,9 +25,7 @@ func move() {
|
||||
// move the mouse to 100, 200
|
||||
robotgo.Move(100, 200)
|
||||
|
||||
// robotgo.Drag(10, 10)
|
||||
// robotgo.Drag(20, 20, "right")
|
||||
//
|
||||
// drag mouse with smooth
|
||||
robotgo.DragSmooth(10, 10)
|
||||
robotgo.DragSmooth(100, 200, 1.0, 100.0)
|
||||
|
||||
@ -37,7 +35,7 @@ func move() {
|
||||
robotgo.MoveSmoothRelative(10, -100, 1.0, 30.0)
|
||||
|
||||
for i := 0; i < 1080; i += 1000 {
|
||||
fmt.Println(i)
|
||||
fmt.Println("i: ", i)
|
||||
// MoveMouse(800, i)
|
||||
robotgo.Move(800, i)
|
||||
}
|
||||
@ -57,7 +55,7 @@ func click() {
|
||||
|
||||
func get() {
|
||||
// gets the mouse coordinates
|
||||
x, y := robotgo.GetMousePos()
|
||||
x, y := robotgo.Location()
|
||||
fmt.Println("pos:", x, y)
|
||||
if x == 456 && y == 586 {
|
||||
fmt.Println("mouse...", "586")
|
||||
@ -68,12 +66,15 @@ func get() {
|
||||
|
||||
func toggleAndScroll() {
|
||||
// scrolls the mouse either up
|
||||
robotgo.ScrollMouse(10, "up")
|
||||
robotgo.ScrollMouse(10, "right")
|
||||
robotgo.ScrollDir(10, "up")
|
||||
robotgo.ScrollDir(10, "right")
|
||||
|
||||
robotgo.Scroll(100, 10)
|
||||
robotgo.Scroll(0, -10)
|
||||
|
||||
robotgo.Toggle("left")
|
||||
robotgo.Toggle("left", "up")
|
||||
|
||||
// toggles the right mouse button
|
||||
robotgo.Toggle("right")
|
||||
robotgo.Toggle("right", "up")
|
||||
|
@ -7,28 +7,43 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
//
|
||||
// syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call()
|
||||
|
||||
width, height := robotgo.GetScaleSize()
|
||||
fmt.Println("get scale screen size: ", width, height)
|
||||
|
||||
bitmap := robotgo.CaptureScreen(0, 0, width, height)
|
||||
// robotgo.SaveBitmap(bitmap, "test.png")
|
||||
defer robotgo.FreeBitmap(bitmap)
|
||||
// bitmap.Save(bitmap, "test.png")
|
||||
robotgo.Save(robotgo.ToImage(bitmap), "test.png")
|
||||
|
||||
sx := robotgo.ScaleX()
|
||||
s := robotgo.Scale()
|
||||
robotgo.Scale = true
|
||||
robotgo.Move(10, 10)
|
||||
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
|
||||
fmt.Println("scale: ", sx, s, " pos: ", robotx, roboty)
|
||||
|
||||
mx, my := robotgo.GetMousePos()
|
||||
mx, my := robotgo.Location()
|
||||
sx, sy := mx*s/100, my*s/100
|
||||
|
||||
rx, ry, rw, rh := sx, sy, robotx, roboty
|
||||
// bit1 := robotgo.CaptureScreen(10, 20, robotw, roboth)
|
||||
bit1 := robotgo.CaptureScreen(rx, ry, rw, rh)
|
||||
// robotgo.SaveBitmap(bit1, "test2.png")
|
||||
defer robotgo.FreeBitmap(bit1)
|
||||
// bitmap.Save(bit1, "test2.png")
|
||||
robotgo.Save(robotgo.ToImage(bit1), "test2.png")
|
||||
|
||||
clo := robotgo.GetPixelColor(robotx, roboty)
|
||||
|
@ -20,30 +20,38 @@ import (
|
||||
|
||||
func bitmap() {
|
||||
bit := robotgo.CaptureScreen()
|
||||
defer robotgo.FreeBitmap(bit)
|
||||
fmt.Println("abitMap...", bit)
|
||||
|
||||
gbit := robotgo.ToBitmap(bit)
|
||||
fmt.Println("bitmap...", gbit.Width)
|
||||
|
||||
gbitMap := robotgo.CaptureGo()
|
||||
fmt.Println("Go CaptureScreen...", gbitMap.Width)
|
||||
// fmt.Println("...", gbitmap.Width, gbitmap.BytesPerPixel)
|
||||
// robotgo.SaveCapture("saveCapture.png", 10, 20, 100, 100)
|
||||
robotgo.SaveCapture("saveCapture.png", 10, 20, 100, 100)
|
||||
|
||||
img := robotgo.CaptureImg()
|
||||
img, err := robotgo.CaptureImg()
|
||||
fmt.Println("error: ", err)
|
||||
robotgo.Save(img, "save.png")
|
||||
|
||||
num := robotgo.DisplaysNum()
|
||||
for i := 0; i < num; i++ {
|
||||
robotgo.DisplayID = i
|
||||
img1 := robotgo.CaptureImg()
|
||||
img1, _ := robotgo.CaptureImg()
|
||||
path1 := "save_" + strconv.Itoa(i)
|
||||
robotgo.Save(img1, path1+".png")
|
||||
robotgo.SaveJpeg(img1, path1+".jpeg", 50)
|
||||
|
||||
img2 := robotgo.CaptureImg(10, 10, 20, 20)
|
||||
img2, _ := robotgo.CaptureImg(10, 10, 20, 20)
|
||||
path2 := "test_" + strconv.Itoa(i)
|
||||
robotgo.Save(img2, path2+".png")
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,7 +94,7 @@ func screen() {
|
||||
fmt.Println("ScaleF: ", s1)
|
||||
}
|
||||
sx, sy = robotgo.GetScaleSize()
|
||||
fmt.Println("get screen sclae size: ", sx, sy)
|
||||
fmt.Println("get screen scale size: ", sx, sy)
|
||||
|
||||
color()
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ func alert() {
|
||||
|
||||
func get() {
|
||||
// get the current process id
|
||||
pid := robotgo.GetPID()
|
||||
pid := robotgo.GetPid()
|
||||
fmt.Println("pid----", pid)
|
||||
|
||||
// get current Window Active
|
||||
@ -54,9 +54,17 @@ func findIds() {
|
||||
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)
|
||||
if len(fpid) > 0 {
|
||||
err = robotgo.ActivePID(fpid[0])
|
||||
err = robotgo.ActivePid(fpid[0])
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
@ -79,7 +87,7 @@ func findIds() {
|
||||
}
|
||||
|
||||
func active() {
|
||||
robotgo.ActivePID(100)
|
||||
robotgo.ActivePid(100)
|
||||
// robotgo.Sleep(2)
|
||||
robotgo.ActiveName("code")
|
||||
robotgo.Sleep(1)
|
||||
|
49
go.mod
49
go.mod
@ -1,33 +1,38 @@
|
||||
module github.com/go-vgo/robotgo
|
||||
|
||||
go 1.17
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.23.6
|
||||
|
||||
require (
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e
|
||||
github.com/otiai10/gosseract v2.2.1+incompatible
|
||||
github.com/otiai10/gosseract/v2 v2.4.1
|
||||
// github.com/robotn/gohook v0.31.3
|
||||
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934
|
||||
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770
|
||||
github.com/vcaesar/gops v0.22.0
|
||||
github.com/vcaesar/imgo v0.30.1
|
||||
github.com/vcaesar/keycode v0.10.0
|
||||
github.com/vcaesar/tt v0.20.0
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect
|
||||
github.com/robotn/xgb v0.10.0
|
||||
github.com/robotn/xgbutil v0.10.0
|
||||
github.com/tailscale/win v0.0.0-20250213223159-5992cb43ca35
|
||||
github.com/vcaesar/gops v0.41.0
|
||||
github.com/vcaesar/imgo v0.41.0
|
||||
github.com/vcaesar/keycode v0.10.1
|
||||
github.com/vcaesar/tt v0.20.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/otiai10/mint v1.3.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.21.12 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.9 // indirect
|
||||
github.com/tklauser/numcpus v0.3.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
github.com/dblohm7/wingoes v0.0.0-20240820181039-f2b84150679e // indirect
|
||||
github.com/ebitengine/purego v0.8.3 // indirect
|
||||
github.com/gen2brain/shm v0.1.1 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/jezek/xgb v1.1.1 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.25.4 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
github.com/tklauser/numcpus v0.10.0 // 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
|
||||
|
123
go.sum
123
go.sum
@ -1,72 +1,71 @@
|
||||
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ=
|
||||
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0=
|
||||
github.com/davecgh/go-spew v1.1.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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/dblohm7/wingoes v0.0.0-20240820181039-f2b84150679e h1:L+XrFvD0vBIBm+Wf9sFN6aU395t7JROoai0qXZraA4U=
|
||||
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/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc=
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
github.com/otiai10/gosseract v2.2.1+incompatible h1:Ry5ltVdpdp4LAa2bMjsSJH34XHVOV7XMi41HtzL8X2I=
|
||||
github.com/otiai10/gosseract v2.2.1+incompatible/go.mod h1:XrzWItCzCpFRZ35n3YtVTgq5bLAhFIkascoRo8G32QE=
|
||||
github.com/otiai10/mint v1.3.0 h1:Ady6MKVezQwHBkGzLFbrsywyp09Ah7rkmfjV3Bcr5uc=
|
||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4=
|
||||
github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
|
||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc=
|
||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/otiai10/gosseract/v2 v2.4.1 h1:G8AyBpXEeSlcq8TI85LH/pM5SXk8Djy2GEXisgyblRw=
|
||||
github.com/otiai10/gosseract/v2 v2.4.1/go.mod h1:1gNWP4Hgr2o7yqWfs6r5bZxAatjOIdqWxJLWsTsembk=
|
||||
github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
|
||||
github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
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/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ=
|
||||
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770 h1:2uX8QRLkkxn2EpAQ6I3KhA79BkdRZfvugJUzJadiJwk=
|
||||
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770/go.mod h1:svkDXUDQjUiWzLrA0OZgHc4lbOts3C+uRfP6/yjwYnU=
|
||||
github.com/shirou/gopsutil/v3 v3.21.12 h1:VoGxEW2hpmz0Vt3wUvHIl9fquzYLNpVpgNNB7pGJimA=
|
||||
github.com/shirou/gopsutil/v3 v3.21.12/go.mod h1:BToYZVTlSVlfazpDDYFnsVZLaoRG+g8ufT6fPQLdJzA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
|
||||
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
|
||||
github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
|
||||
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
|
||||
github.com/vcaesar/gops v0.22.0 h1:aWHWxY3fvUuaJGph+LegYUSEU/874WJT7MInd8OUmP0=
|
||||
github.com/vcaesar/gops v0.22.0/go.mod h1:GFNGo9xpCfjcfd/Hovi9RSrpd4FdaQt8V92TzpU22w4=
|
||||
github.com/vcaesar/imgo v0.30.1 h1:B7QMm2mZY+SGoEvvJwNi+eAv21ptvk2YT1IbP2OzyLE=
|
||||
github.com/vcaesar/imgo v0.30.1/go.mod h1:n4EluJIN/0UYYGPHBCY/BWlIjdRUdY5U6obtP2lrgdM=
|
||||
github.com/vcaesar/keycode v0.10.0 h1:Qx5QE8ZXHyRyjoA2QOxBp25OKMKB+zxMVqm0FWGV0d4=
|
||||
github.com/vcaesar/keycode v0.10.0/go.mod h1:JNlY7xbKsh+LAGfY2j4M3znVrGEm5W1R8s/Uv6BJcfQ=
|
||||
github.com/vcaesar/tt v0.20.0 h1:9t2Ycb9RNHcP0WgQgIaRKJBB+FrRdejuaL6uWIHuoBA=
|
||||
github.com/vcaesar/tt v0.20.0/go.mod h1:GHPxQYhn+7OgKakRusH7KJ0M5MhywoeLb8Fcffs/Gtg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
github.com/robotn/xgb v0.10.0 h1:O3kFbIwtwZ3pgLbp1h5slCQ4OpY8BdwugJLrUe6GPIM=
|
||||
github.com/robotn/xgb v0.10.0/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ=
|
||||
github.com/robotn/xgbutil v0.10.0 h1:gvf7mGQqCWQ68aHRtCxgdewRk+/KAJui6l3MJQQRCKw=
|
||||
github.com/robotn/xgbutil v0.10.0/go.mod h1:svkDXUDQjUiWzLrA0OZgHc4lbOts3C+uRfP6/yjwYnU=
|
||||
github.com/shirou/gopsutil/v4 v4.25.4 h1:cdtFO363VEOOFrUCjZRh4XVJkb548lyF0q0uTeMqYPw=
|
||||
github.com/shirou/gopsutil/v4 v4.25.4/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tailscale/win v0.0.0-20250213223159-5992cb43ca35 h1:wAZbkTZkqDzWsqxPh2qkBd3KvFU7tcxV0BP0Rnhkxog=
|
||||
github.com/tailscale/win v0.0.0-20250213223159-5992cb43ca35/go.mod h1:aMd4yDHLjbOuYP6fMxj1d9ACDQlSWwYztcpybGHCQc8=
|
||||
github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA=
|
||||
github.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk=
|
||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
||||
github.com/vcaesar/gops v0.41.0 h1:FG748Jyw3FOuZnbzSgB+CQSx2e5LbLCPWV2JU1brFdc=
|
||||
github.com/vcaesar/gops v0.41.0/go.mod h1:/3048L7Rj7QjQKTSB+kKc7hDm63YhTWy5QJ10TCP37A=
|
||||
github.com/vcaesar/imgo v0.41.0 h1:kNLYGrThXhB9Dd6IwFmfPnxq9P6yat2g7dpPjr7OWO8=
|
||||
github.com/vcaesar/imgo v0.41.0/go.mod h1:/LGOge8etlzaVu/7l+UfhJxR6QqaoX5yeuzGIMfWb4I=
|
||||
github.com/vcaesar/keycode v0.10.1 h1:0DesGmMAPWpYTCYddOFiCMKCDKgNnwiQa2QXindVUHw=
|
||||
github.com/vcaesar/keycode v0.10.1/go.mod h1:JNlY7xbKsh+LAGfY2j4M3znVrGEm5W1R8s/Uv6BJcfQ=
|
||||
github.com/vcaesar/screenshot v0.11.1 h1:GgPuN89XC4Yh38dLx4quPlSo3YiWWhwIria/j3LtrqU=
|
||||
github.com/vcaesar/screenshot v0.11.1/go.mod h1:gJNwHBiP1v1v7i8TQ4yV1XJtcyn2I/OJL7OziVQkwjs=
|
||||
github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4=
|
||||
github.com/vcaesar/tt v0.20.1/go.mod h1:cH2+AwGAJm19Wa6xvEa+0r+sXDJBT0QgNQey6mwqLeU=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
|
||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
|
||||
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-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-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
6
img.go
6
img.go
@ -55,7 +55,7 @@ func SaveJpeg(img image.Image, path string, quality ...int) error {
|
||||
|
||||
// ToByteImg convert image.Image to []byte
|
||||
func ToByteImg(img image.Image, fm ...string) []byte {
|
||||
return imgo.ToByteImg(img, fm...)
|
||||
return imgo.ToByte(img, fm...)
|
||||
}
|
||||
|
||||
// ToStringImg convert image.Image to string
|
||||
@ -122,7 +122,7 @@ func ImgToBitmap(m image.Image) (bit Bitmap) {
|
||||
// ToUint8p convert the []uint8 to uint8 pointer
|
||||
func ToUint8p(dst []uint8) *uint8 {
|
||||
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] = dst[i+2]
|
||||
src[i+1] = dst[i+1]
|
||||
@ -151,7 +151,7 @@ func val(p *uint8, n int) 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+1] = val(src, i+1)
|
||||
dst[i+2] = val(src, i)
|
||||
|
195
key.go
195
key.go
@ -12,7 +12,7 @@ package robotgo
|
||||
|
||||
/*
|
||||
// #include "key/keycode.h"
|
||||
#include "key/goKey.h"
|
||||
#include "key/keypress_c.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
@ -23,12 +23,13 @@ import (
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unsafe"
|
||||
|
||||
"github.com/go-vgo/robotgo/clipboard"
|
||||
"github.com/vcaesar/tt"
|
||||
)
|
||||
|
||||
// Defining a bunch of constants.
|
||||
const (
|
||||
// KeyA define key "a"
|
||||
KeyA = "a"
|
||||
@ -58,6 +59,33 @@ const (
|
||||
KeyY = "y"
|
||||
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"
|
||||
Key1 = "1"
|
||||
Key2 = "2"
|
||||
@ -173,7 +201,7 @@ const (
|
||||
LightsKbdDown = "lights_kbd_down"
|
||||
)
|
||||
|
||||
// keyNames define MMKeyCode map
|
||||
// keyNames define a map of key names to MMKeyCode
|
||||
var keyNames = map[string]C.MMKeyCode{
|
||||
"backspace": C.K_BACKSPACE,
|
||||
"delete": C.K_DELETE,
|
||||
@ -293,10 +321,20 @@ var keyNames = map[string]C.MMKeyCode{
|
||||
// { NULL: C.K_NOT_A_KEY }
|
||||
}
|
||||
|
||||
func tapKeyCode(code C.MMKeyCode, flags C.MMKeyFlags) {
|
||||
C.toggleKeyCode(code, true, flags)
|
||||
MilliSleep(5)
|
||||
C.toggleKeyCode(code, false, flags)
|
||||
// CmdCtrl If the operating system is macOS, return the key string "cmd",
|
||||
// otherwise return the key string "ctrl
|
||||
func CmdCtrl() string {
|
||||
if runtime.GOOS == "darwin" {
|
||||
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.")
|
||||
@ -366,31 +404,39 @@ func getFlagsFromValue(value []string) (flags C.MMKeyFlags) {
|
||||
return
|
||||
}
|
||||
|
||||
func keyTaps(k string, keyArr []string) error {
|
||||
func keyTaps(k string, keyArr []string, pid int) error {
|
||||
flags := getFlagsFromValue(keyArr)
|
||||
key, err := checkKeyCodes(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tapKeyCode(key, flags)
|
||||
tapKeyCode(key, flags, C.uintptr(pid))
|
||||
MilliSleep(KeySleep)
|
||||
return nil
|
||||
}
|
||||
|
||||
func keyToggles(k string, keyArr []string) error {
|
||||
func keyToggles(k string, keyArr []string, pid int) error {
|
||||
if len(keyArr) <= 0 {
|
||||
keyArr = append(keyArr, "down")
|
||||
}
|
||||
|
||||
down := true
|
||||
if keyArr[0] == "up" {
|
||||
down = false
|
||||
}
|
||||
|
||||
if keyArr[0] == "up" || keyArr[0] == "down" {
|
||||
keyArr = keyArr[1:]
|
||||
}
|
||||
flags := getFlagsFromValue(keyArr)
|
||||
|
||||
key, err := checkKeyCodes(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
C.toggleKeyCode(key, C.bool(down), flags)
|
||||
C.toggleKeyCode(key, C.bool(down), flags, C.uintptr(pid))
|
||||
MilliSleep(KeySleep)
|
||||
return nil
|
||||
}
|
||||
@ -405,7 +451,7 @@ func keyToggles(k string, keyArr []string) error {
|
||||
|
||||
*/
|
||||
|
||||
// ToInterfaces []string to []interface{}
|
||||
// ToInterfaces convert []string to []interface{}
|
||||
func ToInterfaces(fields []string) []interface{} {
|
||||
res := make([]interface{}, 0, len(fields))
|
||||
for _, s := range fields {
|
||||
@ -414,7 +460,7 @@ func ToInterfaces(fields []string) []interface{} {
|
||||
return res
|
||||
}
|
||||
|
||||
// ToStrings []interface{} to []string
|
||||
// ToStrings convert []interface{} to []string
|
||||
func ToStrings(fields []interface{}) []string {
|
||||
res := make([]string, 0, len(fields))
|
||||
for _, s := range fields {
|
||||
@ -423,6 +469,7 @@ func ToStrings(fields []interface{}) []string {
|
||||
return res
|
||||
}
|
||||
|
||||
// toErr it converts a C string to a Go error
|
||||
func toErr(str *C.char) error {
|
||||
gstr := C.GoString(str)
|
||||
if gstr == "" {
|
||||
@ -431,12 +478,14 @@ func toErr(str *C.char) error {
|
||||
return errors.New(gstr)
|
||||
}
|
||||
|
||||
// KeyTap tap the keyboard code;
|
||||
// KeyTap taps the keyboard code;
|
||||
//
|
||||
// See keys:
|
||||
// https://github.com/go-vgo/robotgo/blob/master/docs/keys.md
|
||||
// See keys supported:
|
||||
//
|
||||
// https://github.com/go-vgo/robotgo/blob/master/docs/keys.md#keys
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// robotgo.KeySleep = 100 // 100 millisecond
|
||||
// robotgo.KeyTap("a")
|
||||
// robotgo.KeyTap("i", "alt", "command")
|
||||
@ -444,42 +493,56 @@ func toErr(str *C.char) error {
|
||||
// arr := []string{"alt", "command"}
|
||||
// robotgo.KeyTap("i", arr)
|
||||
//
|
||||
func KeyTap(tapKey string, args ...interface{}) error {
|
||||
// robotgo.KeyTap("k", pid int)
|
||||
func KeyTap(key string, args ...interface{}) error {
|
||||
var keyArr []string
|
||||
|
||||
tapKey = strings.ToLower(tapKey)
|
||||
if _, ok := Special[tapKey]; ok {
|
||||
tapKey = Special[tapKey]
|
||||
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) <= 0 {
|
||||
args = append(args, "shift")
|
||||
}
|
||||
}
|
||||
|
||||
pid := 0
|
||||
if len(args) > 0 {
|
||||
if reflect.TypeOf(args[0]) == reflect.TypeOf(keyArr) {
|
||||
keyArr = args[0].([]string)
|
||||
} else {
|
||||
keyArr = ToStrings(args)
|
||||
if reflect.TypeOf(args[0]) == reflect.TypeOf(pid) {
|
||||
pid = args[0].(int)
|
||||
keyArr = ToStrings(args[1:])
|
||||
} else {
|
||||
keyArr = ToStrings(args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keyTaps(tapKey, keyArr)
|
||||
return keyTaps(key, keyArr, pid)
|
||||
}
|
||||
|
||||
// KeyToggle toggle the keyboard, if there not have args default is "down"
|
||||
// KeyToggle toggles the keyboard, if there not have args default is "down"
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
// robotgo.KeyToggle("a")
|
||||
// robotgo.KeyToggle("a", "up")
|
||||
//
|
||||
// robotgo.KeyToggle("a", "up", "alt", "cmd")
|
||||
//
|
||||
func KeyToggle(key string, args ...string) error {
|
||||
if len(args) <= 0 {
|
||||
args = append(args, "down")
|
||||
// robotgo.KeyToggle("k", pid int)
|
||||
func KeyToggle(key string, args ...interface{}) error {
|
||||
|
||||
if len(key) > 0 && unicode.IsUpper([]rune(key)[0]) {
|
||||
args = append(args, "shift")
|
||||
}
|
||||
|
||||
key = strings.ToLower(key)
|
||||
@ -490,11 +553,20 @@ func KeyToggle(key string, args ...string) error {
|
||||
}
|
||||
}
|
||||
|
||||
return keyToggles(key, args)
|
||||
pid := 0
|
||||
var 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 keyToggles(key, keyArr, pid)
|
||||
}
|
||||
|
||||
// KeyPress press key string
|
||||
func KeyPress(key string, args ...string) error {
|
||||
func KeyPress(key string, args ...interface{}) error {
|
||||
err := KeyDown(key, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -505,13 +577,13 @@ func KeyPress(key string, args ...string) error {
|
||||
}
|
||||
|
||||
// KeyDown press down a key
|
||||
func KeyDown(key string, args ...string) error {
|
||||
func KeyDown(key string, args ...interface{}) error {
|
||||
return KeyToggle(key, args...)
|
||||
}
|
||||
|
||||
// KeyUp press up a key
|
||||
func KeyUp(key string, args ...string) error {
|
||||
arr := []string{"up"}
|
||||
func KeyUp(key string, args ...interface{}) error {
|
||||
arr := []interface{}{"up"}
|
||||
arr = append(arr, args...)
|
||||
return KeyToggle(key, arr...)
|
||||
}
|
||||
@ -539,10 +611,20 @@ func CharCodeAt(s string, n int) rune {
|
||||
return 0
|
||||
}
|
||||
|
||||
// UnicodeType tap uint32 unicode
|
||||
func UnicodeType(str uint32) {
|
||||
// UnicodeType tap the uint32 unicode
|
||||
func UnicodeType(str uint32, args ...int) {
|
||||
cstr := C.uint(str)
|
||||
C.unicodeType(cstr)
|
||||
pid := 0
|
||||
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
|
||||
@ -573,21 +655,26 @@ func inputUTF(str string) {
|
||||
C.free(unsafe.Pointer(cstr))
|
||||
}
|
||||
|
||||
// TypeStr send a string, support UTF-8
|
||||
// TypeStr send a string (supported UTF-8)
|
||||
//
|
||||
// robotgo.TypeStr(string: The string to send, int: milli_sleep time, x11 option)
|
||||
// robotgo.TypeStr(string: "The string to send", int: pid, "milli_sleep time", "x11 option")
|
||||
//
|
||||
// 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) {
|
||||
var tm, tm1 = 0, 7
|
||||
|
||||
if len(args) > 0 {
|
||||
tm = args[0]
|
||||
}
|
||||
if len(args) > 1 {
|
||||
tm1 = args[1]
|
||||
tm = args[1]
|
||||
}
|
||||
if len(args) > 2 {
|
||||
tm1 = args[2]
|
||||
}
|
||||
pid := 0
|
||||
if len(args) > 0 {
|
||||
pid = args[0]
|
||||
}
|
||||
|
||||
if runtime.GOOS == "linux" {
|
||||
@ -596,7 +683,7 @@ func TypeStr(str string, args ...int) {
|
||||
ru := []rune(strUc[i])
|
||||
if len(ru) <= 1 {
|
||||
ustr := uint32(CharCodeAt(strUc[i], 0))
|
||||
UnicodeType(ustr)
|
||||
UnicodeType(ustr, pid)
|
||||
} else {
|
||||
inputUTF(strUc[i])
|
||||
MilliSleep(tm1)
|
||||
@ -609,7 +696,7 @@ func TypeStr(str string, args ...int) {
|
||||
|
||||
for i := 0; i < len([]rune(str)); i++ {
|
||||
ustr := uint32(CharCodeAt(str, i))
|
||||
UnicodeType(ustr)
|
||||
UnicodeType(ustr, pid)
|
||||
// if len(args) > 0 {
|
||||
MilliSleep(tm)
|
||||
// }
|
||||
@ -617,7 +704,7 @@ func TypeStr(str string, args ...int) {
|
||||
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`
|
||||
func PasteStr(str string) error {
|
||||
err := clipboard.WriteAll(str)
|
||||
@ -632,23 +719,15 @@ func PasteStr(str string) error {
|
||||
return KeyTap("v", "control")
|
||||
}
|
||||
|
||||
// TypeStrDelay type string delayed
|
||||
// TypeStrDelay type string with delayed
|
||||
// And you can use robotgo.KeySleep = 100 to delayed not this function
|
||||
func TypeStrDelay(str string, delay int) {
|
||||
TypeStr(str)
|
||||
MilliSleep(delay)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// SetDelay set the key and mouse delay
|
||||
// SetDelay sets the key and mouse delay
|
||||
// robotgo.SetDelay(100) option the robotgo.KeySleep and robotgo.MouseSleep = d
|
||||
func SetDelay(d ...int) {
|
||||
v := 10
|
||||
if len(d) > 0 {
|
||||
|
@ -1,6 +0,0 @@
|
||||
// Copyright 2016 The go-vgo Project Developers.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "../base/types.h"
|
||||
#include "keypress_c.h"
|
||||
#include "keycode_c.h"
|
@ -179,7 +179,7 @@ enum _MMKeyCode {
|
||||
K_SHIFT = XK_Shift_L,
|
||||
K_LSHIFT = XK_Shift_L,
|
||||
K_RSHIFT = XK_Shift_R,
|
||||
K_CAPSLOCK = XK_Shift_Lock,
|
||||
K_CAPSLOCK = XK_Caps_Lock,
|
||||
K_SPACE = XK_space,
|
||||
K_INSERT = XK_Insert,
|
||||
K_PRINTSCREEN = XK_Print,
|
||||
|
@ -79,13 +79,19 @@ MMKeyCode keyCodeForChar(const char c) {
|
||||
if (code == NoSymbol) {
|
||||
return K_NOT_A_KEY;
|
||||
}
|
||||
|
||||
// x11 key bug
|
||||
if (c == 60) {
|
||||
code = 44;
|
||||
}
|
||||
return code;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(IS_MACOSX)
|
||||
CFStringRef createStringForKey(CGKeyCode keyCode){
|
||||
TISInputSourceRef currentKeyboard = TISCopyCurrentASCIICapableKeyboardInputSource();
|
||||
// TISInputSourceRef currentKeyboard = TISCopyCurrentASCIICapableKeyboardInputSource();
|
||||
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardLayoutInputSource();
|
||||
CFDataRef layoutData = (CFDataRef) TISGetInputSourceProperty(
|
||||
currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
|
||||
|
||||
|
@ -2,7 +2,10 @@
|
||||
#ifndef KEYPRESS_H
|
||||
#define KEYPRESS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "../base/os.h"
|
||||
#include "../base/types.h"
|
||||
|
||||
#include "keycode.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
@ -37,7 +40,7 @@
|
||||
|
||||
#if defined(IS_WINDOWS)
|
||||
/* Send win32 key event for given key. */
|
||||
void win32KeyEvent(int key, MMKeyFlags flags);
|
||||
void win32KeyEvent(int key, MMKeyFlags flags, uintptr pid, int8_t isPid);
|
||||
#endif
|
||||
|
||||
#endif /* KEYPRESS_H */
|
||||
|
354
key/keypress_c.h
354
key/keypress_c.h
@ -1,6 +1,17 @@
|
||||
#include "keypress.h"
|
||||
// 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.
|
||||
|
||||
#include "../base/deadbeef_rand_c.h"
|
||||
#include "../base/microsleep.h"
|
||||
#include "keypress.h"
|
||||
#include "keycode_c.h"
|
||||
|
||||
#include <ctype.h> /* For isupper() */
|
||||
#if defined(IS_MACOSX)
|
||||
@ -14,11 +25,23 @@
|
||||
|
||||
/* Convenience wrappers around ugly APIs. */
|
||||
#if defined(IS_WINDOWS)
|
||||
void WIN32_KEY_EVENT_WAIT(MMKeyCode key, DWORD flags) {
|
||||
win32KeyEvent(key, flags);
|
||||
HWND GetHwndByPid(DWORD dwProcessId);
|
||||
|
||||
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));
|
||||
}
|
||||
#elif defined(USE_X11)
|
||||
Display *XGetMainDisplay(void);
|
||||
|
||||
void X_KEY_EVENT(Display *display, MMKeyCode key, bool is_press) {
|
||||
XTestFakeKeyEvent(display, XKeysymToKeycode(display, key), is_press, CurrentTime);
|
||||
XSync(display, false);
|
||||
@ -31,93 +54,113 @@
|
||||
#endif
|
||||
|
||||
#if defined(IS_MACOSX)
|
||||
static io_connect_t _getAuxiliaryKeyDriver(void) {
|
||||
static mach_port_t sEventDrvrRef = 0;
|
||||
mach_port_t masterPort, service, iter;
|
||||
kern_return_t kr;
|
||||
|
||||
if (!sEventDrvrRef) {
|
||||
kr = IOMasterPort(bootstrap_port, &masterPort);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
kr = IOServiceGetMatchingServices(masterPort, IOServiceMatching(kIOHIDSystemClass), &iter);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
|
||||
service = IOIteratorNext(iter);
|
||||
assert(service);
|
||||
|
||||
kr = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &sEventDrvrRef);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
|
||||
IOObjectRelease(service);
|
||||
IOObjectRelease(iter);
|
||||
}
|
||||
return sEventDrvrRef;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IS_WINDOWS)
|
||||
void win32KeyEvent(int key, MMKeyFlags flags) {
|
||||
int scan = MapVirtualKey(key & 0xff, MAPVK_VK_TO_VSC);
|
||||
|
||||
/* Set the scan code for extended keys */
|
||||
switch (key){
|
||||
case VK_RCONTROL:
|
||||
case VK_SNAPSHOT: /* Print Screen */
|
||||
case VK_RMENU: /* Right Alt / Alt Gr */
|
||||
case VK_PAUSE: /* Pause / Break */
|
||||
case VK_HOME:
|
||||
case VK_UP:
|
||||
case VK_PRIOR: /* Page up */
|
||||
case VK_LEFT:
|
||||
case VK_RIGHT:
|
||||
case VK_END:
|
||||
case VK_DOWN:
|
||||
case VK_NEXT: /* 'Page Down' */
|
||||
case VK_INSERT:
|
||||
case VK_DELETE:
|
||||
case VK_LWIN:
|
||||
case VK_RWIN:
|
||||
case VK_APPS: /* Application */
|
||||
case VK_VOLUME_MUTE:
|
||||
case VK_VOLUME_DOWN:
|
||||
case VK_VOLUME_UP:
|
||||
case VK_MEDIA_NEXT_TRACK:
|
||||
case VK_MEDIA_PREV_TRACK:
|
||||
case VK_MEDIA_STOP:
|
||||
case VK_MEDIA_PLAY_PAUSE:
|
||||
case VK_BROWSER_BACK:
|
||||
case VK_BROWSER_FORWARD:
|
||||
case VK_BROWSER_REFRESH:
|
||||
case VK_BROWSER_STOP:
|
||||
case VK_BROWSER_SEARCH:
|
||||
case VK_BROWSER_FAVORITES:
|
||||
case VK_BROWSER_HOME:
|
||||
case VK_LAUNCH_MAIL:
|
||||
{
|
||||
flags |= KEYEVENTF_EXTENDEDKEY;
|
||||
break;
|
||||
int SendTo(uintptr pid, CGEventRef event) {
|
||||
if (pid != 0) {
|
||||
CGEventPostToPid(pid, event);
|
||||
} else {
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
}
|
||||
|
||||
CFRelease(event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set the scan code for keyup */
|
||||
// if ( flags & KEYEVENTF_KEYUP ) {
|
||||
// scan |= 0x80;
|
||||
// }
|
||||
// keybd_event(key, scan, flags, 0);
|
||||
|
||||
INPUT keyInput;
|
||||
static io_connect_t _getAuxiliaryKeyDriver(void) {
|
||||
static mach_port_t sEventDrvrRef = 0;
|
||||
mach_port_t masterPort, service, iter;
|
||||
kern_return_t kr;
|
||||
|
||||
keyInput.type = INPUT_KEYBOARD;
|
||||
keyInput.ki.wVk = key;
|
||||
keyInput.ki.wScan = scan;
|
||||
keyInput.ki.dwFlags = flags;
|
||||
keyInput.ki.time = 0;
|
||||
keyInput.ki.dwExtraInfo = 0;
|
||||
SendInput(1, &keyInput, sizeof(keyInput));
|
||||
}
|
||||
if (!sEventDrvrRef) {
|
||||
kr = IOMasterPort(bootstrap_port, &masterPort);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
kr = IOServiceGetMatchingServices(masterPort, IOServiceMatching(kIOHIDSystemClass), &iter);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
|
||||
service = IOIteratorNext(iter);
|
||||
assert(service);
|
||||
|
||||
kr = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &sEventDrvrRef);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
|
||||
IOObjectRelease(service);
|
||||
IOObjectRelease(iter);
|
||||
}
|
||||
return sEventDrvrRef;
|
||||
}
|
||||
#elif defined(IS_WINDOWS)
|
||||
|
||||
void win32KeyEvent(int key, MMKeyFlags flags, uintptr pid, int8_t isPid) {
|
||||
int scan = MapVirtualKey(key & 0xff, MAPVK_VK_TO_VSC);
|
||||
|
||||
/* Set the scan code for extended keys */
|
||||
switch (key){
|
||||
case VK_RCONTROL:
|
||||
case VK_SNAPSHOT: /* Print Screen */
|
||||
case VK_RMENU: /* Right Alt / Alt Gr */
|
||||
case VK_PAUSE: /* Pause / Break */
|
||||
case VK_HOME:
|
||||
case VK_UP:
|
||||
case VK_PRIOR: /* Page up */
|
||||
case VK_LEFT:
|
||||
case VK_RIGHT:
|
||||
case VK_END:
|
||||
case VK_DOWN:
|
||||
case VK_NEXT: /* 'Page Down' */
|
||||
case VK_INSERT:
|
||||
case VK_DELETE:
|
||||
case VK_LWIN:
|
||||
case VK_RWIN:
|
||||
case VK_APPS: /* Application */
|
||||
case VK_VOLUME_MUTE:
|
||||
case VK_VOLUME_DOWN:
|
||||
case VK_VOLUME_UP:
|
||||
case VK_MEDIA_NEXT_TRACK:
|
||||
case VK_MEDIA_PREV_TRACK:
|
||||
case VK_MEDIA_STOP:
|
||||
case VK_MEDIA_PLAY_PAUSE:
|
||||
case VK_BROWSER_BACK:
|
||||
case VK_BROWSER_FORWARD:
|
||||
case VK_BROWSER_REFRESH:
|
||||
case VK_BROWSER_STOP:
|
||||
case VK_BROWSER_SEARCH:
|
||||
case VK_BROWSER_FAVORITES:
|
||||
case VK_BROWSER_HOME:
|
||||
case VK_LAUNCH_MAIL:
|
||||
{
|
||||
flags |= KEYEVENTF_EXTENDEDKEY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 */
|
||||
// if ( flags & KEYEVENTF_KEYUP ) {
|
||||
// scan |= 0x80;
|
||||
// }
|
||||
// keybd_event(key, scan, flags, 0);
|
||||
|
||||
INPUT keyInput;
|
||||
|
||||
keyInput.type = INPUT_KEYBOARD;
|
||||
keyInput.ki.wVk = key;
|
||||
keyInput.ki.wScan = scan;
|
||||
keyInput.ki.dwFlags = flags;
|
||||
keyInput.ki.time = 0;
|
||||
keyInput.ki.dwExtraInfo = 0;
|
||||
SendInput(1, &keyInput, sizeof(keyInput));
|
||||
}
|
||||
#endif
|
||||
|
||||
void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags) {
|
||||
void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags, uintptr pid) {
|
||||
#if defined(IS_MACOSX)
|
||||
/* The media keys all have 1000 added to them to help us detect them. */
|
||||
if (code >= 1000) {
|
||||
@ -136,25 +179,28 @@ void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags) {
|
||||
NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
} else {
|
||||
CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)code, down);
|
||||
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
CGEventRef keyEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)code, down);
|
||||
assert(keyEvent != NULL);
|
||||
|
||||
CGEventSetType(keyEvent, down ? kCGEventKeyDown : kCGEventKeyUp);
|
||||
// CGEventSetFlags(keyEvent, flags);
|
||||
CGEventSetFlags(keyEvent, (int) flags);
|
||||
CGEventPost(kCGSessionEventTap, keyEvent);
|
||||
CFRelease(keyEvent);
|
||||
if (flags != 0) {
|
||||
CGEventSetFlags(keyEvent, (CGEventFlags) flags);
|
||||
}
|
||||
|
||||
SendTo(pid, keyEvent);
|
||||
CFRelease(source);
|
||||
}
|
||||
#elif defined(IS_WINDOWS)
|
||||
const DWORD dwFlags = down ? 0 : KEYEVENTF_KEYUP;
|
||||
|
||||
/* Parse modifier keys. */
|
||||
if (flags & MOD_META) { WIN32_KEY_EVENT_WAIT(K_META, dwFlags); }
|
||||
if (flags & MOD_ALT) { WIN32_KEY_EVENT_WAIT(K_ALT, dwFlags); }
|
||||
if (flags & MOD_CONTROL) { WIN32_KEY_EVENT_WAIT(K_CONTROL, dwFlags); }
|
||||
if (flags & MOD_SHIFT) { WIN32_KEY_EVENT_WAIT(K_SHIFT, dwFlags); }
|
||||
if (flags & MOD_META) { WIN32_KEY_EVENT_WAIT(K_META, dwFlags, pid); }
|
||||
if (flags & MOD_ALT) { WIN32_KEY_EVENT_WAIT(K_ALT, dwFlags, pid); }
|
||||
if (flags & MOD_CONTROL) { WIN32_KEY_EVENT_WAIT(K_CONTROL, dwFlags, pid); }
|
||||
if (flags & MOD_SHIFT) { WIN32_KEY_EVENT_WAIT(K_SHIFT, dwFlags, pid); }
|
||||
|
||||
win32KeyEvent(code, dwFlags);
|
||||
win32KeyEvent(code, dwFlags, pid, 0);
|
||||
#elif defined(USE_X11)
|
||||
Display *display = XGetMainDisplay();
|
||||
const Bool is_press = down ? True : False; /* Just to be safe. */
|
||||
@ -192,14 +238,9 @@ void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void toggleKey(char c, const bool down, MMKeyFlags flags){
|
||||
void toggleKey(char c, const bool down, MMKeyFlags flags, uintptr pid) {
|
||||
MMKeyCode keyCode = keyCodeForChar(c);
|
||||
|
||||
//Prevent unused variable warning for Mac and Linux.
|
||||
#if defined(IS_WINDOWS)
|
||||
int modifiers;
|
||||
#endif
|
||||
|
||||
#if defined(USE_X11)
|
||||
if (toUpper(c) && !(flags & MOD_SHIFT)) {
|
||||
flags |= MOD_SHIFT; /* Not sure if this is safe for all layouts. */
|
||||
@ -211,14 +252,15 @@ void toggleKey(char c, const bool down, MMKeyFlags flags){
|
||||
#endif
|
||||
|
||||
#if defined(IS_WINDOWS)
|
||||
modifiers = keyCode >> 8; // Pull out modifers.
|
||||
int modifiers = keyCode >> 8; // Pull out modifers.
|
||||
|
||||
if ((modifiers & 1) != 0) { flags |= MOD_SHIFT; } // Uptdate flags from keycode modifiers.
|
||||
if ((modifiers & 2) != 0) { flags |= MOD_CONTROL; }
|
||||
if ((modifiers & 4) != 0) { flags |= MOD_ALT; }
|
||||
keyCode = keyCode & 0xff; // Mask out modifiers.
|
||||
#endif
|
||||
|
||||
toggleKeyCode(keyCode, down, flags);
|
||||
toggleKeyCode(keyCode, down, flags, pid);
|
||||
}
|
||||
|
||||
// void tapKey(char c, MMKeyFlags flags){
|
||||
@ -228,27 +270,66 @@ void toggleKey(char c, const bool down, MMKeyFlags flags){
|
||||
// }
|
||||
|
||||
#if defined(IS_MACOSX)
|
||||
void toggleUnicode(UniChar ch, const bool down) {
|
||||
/* This function relies on the convenient CGEventKeyboardSetUnicodeString(),
|
||||
convert characters to a keycode, but does not support adding modifier flags.
|
||||
It is only used in typeString().
|
||||
-- if you need modifier keys, use the above functions instead. */
|
||||
CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, 0, down);
|
||||
if (keyEvent == NULL) {
|
||||
fputs("Could not create keyboard event.\n", stderr);
|
||||
return;
|
||||
void toggleUnicode(UniChar ch, const bool down, uintptr pid) {
|
||||
/* This function relies on the convenient CGEventKeyboardSetUnicodeString(),
|
||||
convert characters to a keycode, but does not support adding modifier flags.
|
||||
It is only used in typeString().
|
||||
-- if you need modifier keys, use the above functions instead. */
|
||||
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
CGEventRef keyEvent = CGEventCreateKeyboardEvent(source, 0, down);
|
||||
if (keyEvent == NULL) {
|
||||
fputs("Could not create keyboard event.\n", stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
CGEventKeyboardSetUnicodeString(keyEvent, 1, &ch);
|
||||
|
||||
SendTo(pid, keyEvent);
|
||||
CFRelease(source);
|
||||
}
|
||||
|
||||
CGEventKeyboardSetUnicodeString(keyEvent, 1, &ch);
|
||||
|
||||
CGEventPost(kCGSessionEventTap, keyEvent);
|
||||
CFRelease(keyEvent);
|
||||
}
|
||||
#else
|
||||
#define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE, 0)
|
||||
#endif
|
||||
|
||||
#if defined(USE_X11)
|
||||
#define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE)
|
||||
// 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)
|
||||
int input_utf(const char *utf) {
|
||||
Display *dpy = XOpenDisplay(NULL);
|
||||
KeySym sym = XStringToKeysym(utf);
|
||||
@ -271,39 +352,8 @@ void toggleUnicode(UniChar ch, const bool down) {
|
||||
XCloseDisplay(dpy);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#if !defined(USE_X11)
|
||||
#else
|
||||
int input_utf(const char *utf){
|
||||
return 0;
|
||||
}
|
||||
#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
|
||||
}
|
||||
#endif
|
173
mouse/mouse_c.h
173
mouse/mouse_c.h
@ -15,125 +15,111 @@
|
||||
|
||||
/* Some convenience macros for converting our enums to the system API types. */
|
||||
#if defined(IS_MACOSX)
|
||||
CGEventType MMMouseDownToCGEventType(MMMouseButton button) {
|
||||
if (button == LEFT_BUTTON) {
|
||||
return kCGEventLeftMouseDown;
|
||||
CGEventType MMMouseDownToCGEventType(MMMouseButton button) {
|
||||
if (button == LEFT_BUTTON) {
|
||||
return kCGEventLeftMouseDown;
|
||||
}
|
||||
if (button == RIGHT_BUTTON) {
|
||||
return kCGEventRightMouseDown;
|
||||
}
|
||||
return kCGEventOtherMouseDown;
|
||||
}
|
||||
if (button == RIGHT_BUTTON) {
|
||||
return kCGEventRightMouseDown;
|
||||
}
|
||||
return kCGEventOtherMouseDown;
|
||||
}
|
||||
|
||||
CGEventType MMMouseUpToCGEventType(MMMouseButton button) {
|
||||
if (button == LEFT_BUTTON) { return kCGEventLeftMouseUp; }
|
||||
if (button == RIGHT_BUTTON) { return kCGEventRightMouseUp; }
|
||||
return kCGEventOtherMouseUp;
|
||||
}
|
||||
CGEventType MMMouseUpToCGEventType(MMMouseButton button) {
|
||||
if (button == LEFT_BUTTON) { return kCGEventLeftMouseUp; }
|
||||
if (button == RIGHT_BUTTON) { return kCGEventRightMouseUp; }
|
||||
return kCGEventOtherMouseUp;
|
||||
}
|
||||
|
||||
CGEventType MMMouseDragToCGEventType(MMMouseButton button) {
|
||||
if (button == LEFT_BUTTON) { return kCGEventLeftMouseDragged; }
|
||||
if (button == RIGHT_BUTTON) { return kCGEventRightMouseDragged; }
|
||||
return kCGEventOtherMouseDragged;
|
||||
}
|
||||
CGEventType MMMouseDragToCGEventType(MMMouseButton button) {
|
||||
if (button == LEFT_BUTTON) { return kCGEventLeftMouseDragged; }
|
||||
if (button == RIGHT_BUTTON) { return kCGEventRightMouseDragged; }
|
||||
return kCGEventOtherMouseDragged;
|
||||
}
|
||||
|
||||
CGEventType MMMouseToCGEventType(bool down, MMMouseButton button) {
|
||||
if (down) { return MMMouseDownToCGEventType(button); }
|
||||
return MMMouseUpToCGEventType(button);
|
||||
}
|
||||
CGEventType MMMouseToCGEventType(bool down, MMMouseButton button) {
|
||||
if (down) { return MMMouseDownToCGEventType(button); }
|
||||
return MMMouseUpToCGEventType(button);
|
||||
}
|
||||
|
||||
#elif defined(IS_WINDOWS)
|
||||
|
||||
DWORD MMMouseUpToMEventF(MMMouseButton button) {
|
||||
if (button == LEFT_BUTTON) { return MOUSEEVENTF_LEFTUP; }
|
||||
if (button == RIGHT_BUTTON) { return MOUSEEVENTF_RIGHTUP; }
|
||||
return MOUSEEVENTF_MIDDLEUP;
|
||||
}
|
||||
DWORD MMMouseUpToMEventF(MMMouseButton button) {
|
||||
if (button == LEFT_BUTTON) { return MOUSEEVENTF_LEFTUP; }
|
||||
if (button == RIGHT_BUTTON) { return MOUSEEVENTF_RIGHTUP; }
|
||||
return MOUSEEVENTF_MIDDLEUP;
|
||||
}
|
||||
|
||||
DWORD MMMouseDownToMEventF(MMMouseButton button) {
|
||||
if (button == LEFT_BUTTON) { return MOUSEEVENTF_LEFTDOWN; }
|
||||
if (button == RIGHT_BUTTON) { return MOUSEEVENTF_RIGHTDOWN; }
|
||||
return MOUSEEVENTF_MIDDLEDOWN;
|
||||
}
|
||||
DWORD MMMouseDownToMEventF(MMMouseButton button) {
|
||||
if (button == LEFT_BUTTON) { return MOUSEEVENTF_LEFTDOWN; }
|
||||
if (button == RIGHT_BUTTON) { return MOUSEEVENTF_RIGHTDOWN; }
|
||||
return MOUSEEVENTF_MIDDLEDOWN;
|
||||
}
|
||||
|
||||
DWORD MMMouseToMEventF(bool down, MMMouseButton button) {
|
||||
if (down) { return MMMouseDownToMEventF(button); }
|
||||
return MMMouseUpToMEventF(button);
|
||||
}
|
||||
DWORD MMMouseToMEventF(bool down, MMMouseButton button) {
|
||||
if (down) { return MMMouseDownToMEventF(button); }
|
||||
return MMMouseUpToMEventF(button);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IS_MACOSX)
|
||||
/* Calculate the delta for a mouse move and add them to the event. */
|
||||
void calculateDeltas(CGEventRef *event, MMPointInt32 point){
|
||||
/* The next few lines are a workaround for games not detecting mouse moves. */
|
||||
CGEventRef get = CGEventCreate(NULL);
|
||||
CGPoint mouse = CGEventGetLocation(get);
|
||||
/* Calculate the delta for a mouse move and add them to the event. */
|
||||
void calculateDeltas(CGEventRef *event, MMPointInt32 point) {
|
||||
/* The next few lines are a workaround for games not detecting mouse moves. */
|
||||
CGEventRef get = CGEventCreate(NULL);
|
||||
CGPoint mouse = CGEventGetLocation(get);
|
||||
|
||||
// Calculate the deltas.
|
||||
int64_t deltaX = point.x - mouse.x;
|
||||
int64_t deltaY = point.y - mouse.y;
|
||||
// Calculate the deltas.
|
||||
int64_t deltaX = point.x - mouse.x;
|
||||
int64_t deltaY = point.y - mouse.y;
|
||||
|
||||
CGEventSetIntegerValueField(*event, kCGMouseEventDeltaX, deltaX);
|
||||
CGEventSetIntegerValueField(*event, kCGMouseEventDeltaY, deltaY);
|
||||
CGEventSetIntegerValueField(*event, kCGMouseEventDeltaX, deltaX);
|
||||
CGEventSetIntegerValueField(*event, kCGMouseEventDeltaY, deltaY);
|
||||
|
||||
CFRelease(get);
|
||||
}
|
||||
CFRelease(get);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Move the mouse to a specific point. */
|
||||
void moveMouse(MMPointInt32 point){
|
||||
#if defined(IS_MACOSX)
|
||||
CGEventRef move = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved,
|
||||
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
CGEventRef move = CGEventCreateMouseEvent(source, kCGEventMouseMoved,
|
||||
CGPointFromMMPointInt32(point), kCGMouseButtonLeft);
|
||||
|
||||
calculateDeltas(&move, point);
|
||||
|
||||
CGEventPost(kCGSessionEventTap, move);
|
||||
CGEventPost(kCGHIDEventTap, move);
|
||||
CFRelease(move);
|
||||
CFRelease(source);
|
||||
#elif defined(USE_X11)
|
||||
Display *display = XGetMainDisplay();
|
||||
XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, point.x, point.y);
|
||||
|
||||
XSync(display, false);
|
||||
#elif defined(IS_WINDOWS)
|
||||
// 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));
|
||||
SetCursorPos(point.x, point.y);
|
||||
#endif
|
||||
}
|
||||
|
||||
void dragMouse(MMPointInt32 point, const MMMouseButton button){
|
||||
#if defined(IS_MACOSX)
|
||||
const CGEventType dragType = MMMouseDragToCGEventType(button);
|
||||
CGEventRef drag = CGEventCreateMouseEvent(NULL, dragType,
|
||||
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
CGEventRef drag = CGEventCreateMouseEvent(source, dragType,
|
||||
CGPointFromMMPointInt32(point), (CGMouseButton)button);
|
||||
|
||||
calculateDeltas(&drag, point);
|
||||
|
||||
CGEventPost(kCGSessionEventTap, drag);
|
||||
CGEventPost(kCGHIDEventTap, drag);
|
||||
CFRelease(drag);
|
||||
CFRelease(source);
|
||||
#else
|
||||
moveMouse(point);
|
||||
#endif
|
||||
}
|
||||
|
||||
MMPointInt32 getMousePos() {
|
||||
MMPointInt32 location() {
|
||||
#if defined(IS_MACOSX)
|
||||
CGEventRef event = CGEventCreate(NULL);
|
||||
CGPoint point = CGEventGetLocation(event);
|
||||
@ -161,12 +147,14 @@ MMPointInt32 getMousePos() {
|
||||
/* Press down a button, or release it. */
|
||||
void toggleMouse(bool down, MMMouseButton button) {
|
||||
#if defined(IS_MACOSX)
|
||||
const CGPoint currentPos = CGPointFromMMPointInt32(getMousePos());
|
||||
const CGPoint currentPos = CGPointFromMMPointInt32(location());
|
||||
const CGEventType mouseType = MMMouseToCGEventType(down, button);
|
||||
CGEventRef event = CGEventCreateMouseEvent(NULL, mouseType, currentPos, (CGMouseButton)button);
|
||||
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
CGEventRef event = CGEventCreateMouseEvent(source, mouseType, currentPos, (CGMouseButton)button);
|
||||
|
||||
CGEventPost(kCGSessionEventTap, event);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CFRelease(event);
|
||||
CFRelease(source);
|
||||
#elif defined(USE_X11)
|
||||
Display *display = XGetMainDisplay();
|
||||
XTestFakeButtonEvent(display, button, down ? True : False, CurrentTime);
|
||||
@ -192,15 +180,16 @@ void clickMouse(MMMouseButton button){
|
||||
toggleMouse(false, button);
|
||||
}
|
||||
|
||||
/* Special function for sending double clicks, needed for Mac OS X. */
|
||||
/* Special function for sending double clicks, needed for MacOS. */
|
||||
void doubleClick(MMMouseButton button){
|
||||
#if defined(IS_MACOSX)
|
||||
/* Double click for Mac. */
|
||||
const CGPoint currentPos = CGPointFromMMPointInt32(getMousePos());
|
||||
const CGPoint currentPos = CGPointFromMMPointInt32(location());
|
||||
const CGEventType mouseTypeDown = MMMouseToCGEventType(true, button);
|
||||
const CGEventType mouseTypeUP = MMMouseToCGEventType(false, button);
|
||||
|
||||
CGEventRef event = CGEventCreateMouseEvent(NULL, mouseTypeDown, currentPos, kCGMouseButtonLeft);
|
||||
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
CGEventRef event = CGEventCreateMouseEvent(source, mouseTypeDown, currentPos, kCGMouseButtonLeft);
|
||||
|
||||
/* Set event to double click. */
|
||||
CGEventSetIntegerValueField(event, kCGMouseEventClickState, 2);
|
||||
@ -210,6 +199,7 @@ void doubleClick(MMMouseButton button){
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
|
||||
CFRelease(event);
|
||||
CFRelease(source);
|
||||
#else
|
||||
/* Double click for everything else. */
|
||||
clickMouse(button);
|
||||
@ -226,25 +216,20 @@ void scrollMouseXY(int x, int y) {
|
||||
INPUT mouseScrollInputV;
|
||||
#endif
|
||||
|
||||
/* Direction should only be considered based on the scrollDirection. This Should not interfere. */
|
||||
/* Set up the OS specific solution */
|
||||
#if defined(__APPLE__)
|
||||
CGEventRef event;
|
||||
event = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 2, y, x);
|
||||
#if defined(IS_MACOSX)
|
||||
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
CGEventRef event = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitPixel, 2, y, x);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
|
||||
CFRelease(event);
|
||||
CFRelease(source);
|
||||
#elif defined(USE_X11)
|
||||
int ydir = 4; /* Button 4 is up, 5 is down. */
|
||||
int xdir = 6;
|
||||
Display *display = XGetMainDisplay();
|
||||
|
||||
if (y < 0) {
|
||||
ydir = 5;
|
||||
}
|
||||
if (x < 0) {
|
||||
xdir = 7;
|
||||
}
|
||||
if (y < 0) { ydir = 5; }
|
||||
if (x < 0) { xdir = 7; }
|
||||
|
||||
int xi; int yi;
|
||||
for (xi = 0; xi < abs(x); xi++) {
|
||||
@ -298,8 +283,8 @@ static double crude_hypot(double x, double y){
|
||||
}
|
||||
|
||||
bool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed){
|
||||
MMPointInt32 pos = getMousePos();
|
||||
MMSizeInt32 screenSize = getMainDisplaySize();
|
||||
MMPointInt32 pos = location();
|
||||
// MMSizeInt32 screenSize = getMainDisplaySize();
|
||||
double velo_x = 0.0, velo_y = 0.0;
|
||||
double distance;
|
||||
|
||||
@ -319,9 +304,9 @@ bool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed)
|
||||
pos.y += floor(velo_y + 0.5);
|
||||
|
||||
/* 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) {
|
||||
return false;
|
||||
}
|
||||
// if (pos.x >= screenSize.w || pos.y >= screenSize.h) {
|
||||
// return false;
|
||||
// }
|
||||
moveMouse(pos);
|
||||
|
||||
/* Wait 1 - 3 milliseconds. */
|
||||
|
14
ps.go
14
ps.go
@ -14,17 +14,17 @@ import ps "github.com/vcaesar/gops"
|
||||
|
||||
// Nps process struct
|
||||
type Nps struct {
|
||||
Pid int32
|
||||
Pid int
|
||||
Name string
|
||||
}
|
||||
|
||||
// Pids get the all process id
|
||||
func Pids() ([]int32, error) {
|
||||
func Pids() ([]int, error) {
|
||||
return ps.Pids()
|
||||
}
|
||||
|
||||
// PidExists determine whether the process exists
|
||||
func PidExists(pid int32) (bool, error) {
|
||||
func PidExists(pid int) (bool, error) {
|
||||
return ps.PidExists(pid)
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ func Process() ([]Nps, error) {
|
||||
}
|
||||
|
||||
// FindName find the process name by the process id
|
||||
func FindName(pid int32) (string, error) {
|
||||
func FindName(pid int) (string, error) {
|
||||
return ps.FindName(pid)
|
||||
}
|
||||
|
||||
@ -57,12 +57,12 @@ func FindNames() ([]string, error) {
|
||||
// FindIds finds the all processes named with a subset
|
||||
// of "name" (case insensitive),
|
||||
// return matched IDs.
|
||||
func FindIds(name string) ([]int32, error) {
|
||||
func FindIds(name string) ([]int, error) {
|
||||
return ps.FindIds(name)
|
||||
}
|
||||
|
||||
// FindPath find the process path by the process pid
|
||||
func FindPath(pid int32) (string, error) {
|
||||
func FindPath(pid int) (string, error) {
|
||||
return ps.FindPath(pid)
|
||||
}
|
||||
|
||||
@ -72,6 +72,6 @@ func Run(path string) ([]byte, error) {
|
||||
}
|
||||
|
||||
// Kill kill the process by PID
|
||||
func Kill(pid int32) error {
|
||||
func Kill(pid int) error {
|
||||
return ps.Kill(pid)
|
||||
}
|
||||
|
@ -33,6 +33,9 @@ func TestGetScreenSize(t *testing.T) {
|
||||
|
||||
rect := robotgo.GetScreenRect()
|
||||
fmt.Println("Get screen rect: ", rect)
|
||||
|
||||
x, y = robotgo.Location()
|
||||
fmt.Println("Get location: ", x, y)
|
||||
}
|
||||
|
||||
func TestGetSysScale(t *testing.T) {
|
||||
@ -40,5 +43,13 @@ func TestGetSysScale(t *testing.T) {
|
||||
log.Println("SysScale: ", s)
|
||||
|
||||
f := robotgo.ScaleF()
|
||||
log.Println("sclae: ", f)
|
||||
log.Println("scale: ", 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()
|
||||
}
|
||||
}
|
||||
|
355
robotgo.go
355
robotgo.go
@ -9,28 +9,34 @@
|
||||
// except according to those terms.
|
||||
|
||||
/*
|
||||
|
||||
Package robotgo Go native cross-platform system automation.
|
||||
|
||||
Please make sure Golang, GCC is installed correctly before installing RobotGo;
|
||||
|
||||
See Requirements:
|
||||
|
||||
https://github.com/go-vgo/robotgo#requirements
|
||||
|
||||
Installation:
|
||||
|
||||
With Go module support (Go 1.11+), just import:
|
||||
|
||||
import "github.com/go-vgo/robotgo"
|
||||
|
||||
Otherwise, to install the robotgo package, run the command:
|
||||
|
||||
go get -u github.com/go-vgo/robotgo
|
||||
*/
|
||||
package robotgo
|
||||
|
||||
/*
|
||||
#cgo darwin CFLAGS: -x objective-c -Wno-deprecated-declarations
|
||||
#cgo darwin LDFLAGS: -framework Cocoa -framework OpenGL -framework IOKit
|
||||
#cgo darwin LDFLAGS: -framework Carbon -framework CoreFoundation
|
||||
#cgo darwin LDFLAGS: -framework Cocoa -framework CoreFoundation -framework IOKit
|
||||
#cgo darwin LDFLAGS: -framework Carbon -framework OpenGL
|
||||
//
|
||||
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 140400
|
||||
#cgo darwin LDFLAGS: -framework ScreenCaptureKit
|
||||
#endif
|
||||
|
||||
#cgo linux CFLAGS: -I/usr/src
|
||||
#cgo linux LDFLAGS: -L/usr/src -lm -lX11 -lXtst
|
||||
@ -44,6 +50,7 @@ package robotgo
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"runtime"
|
||||
"time"
|
||||
@ -66,10 +73,15 @@ var (
|
||||
// MouseSleep set the mouse default millisecond sleep time
|
||||
MouseSleep = 0
|
||||
// KeySleep set the key default millisecond sleep time
|
||||
KeySleep = 0
|
||||
KeySleep = 10
|
||||
|
||||
// DisplayID set the screen display id
|
||||
DisplayID = -1
|
||||
|
||||
// NotPid used the hwnd not pid in windows
|
||||
NotPid bool
|
||||
// Scale option the os screen scale
|
||||
Scale bool
|
||||
)
|
||||
|
||||
type (
|
||||
@ -79,9 +91,15 @@ type (
|
||||
CHex C.MMRGBHex
|
||||
// CBitmap define CBitmap as C.MMBitmapRef type
|
||||
CBitmap C.MMBitmapRef
|
||||
// Handle define window Handle as C.MData type
|
||||
Handle C.MData
|
||||
)
|
||||
|
||||
// Bitmap is Bitmap struct
|
||||
// Bitmap define the go Bitmap struct
|
||||
//
|
||||
// The common type conversion of bitmap:
|
||||
//
|
||||
// https://github.com/go-vgo/robotgo/blob/master/docs/keys.md#type-conversion
|
||||
type Bitmap struct {
|
||||
ImgBuf *uint8
|
||||
Width, Height int
|
||||
@ -209,9 +227,9 @@ func GetPixelColor(x, y int, displayId ...int) string {
|
||||
return PadHex(GetPxColor(x, y, displayId...))
|
||||
}
|
||||
|
||||
// GetMouseColor get the mouse pos's color
|
||||
func GetMouseColor(displayId ...int) string {
|
||||
x, y := GetMousePos()
|
||||
// GetLocationColor get the location pos's color
|
||||
func GetLocationColor(displayId ...int) string {
|
||||
x, y := Location()
|
||||
return GetPixelColor(x, y, displayId...)
|
||||
}
|
||||
|
||||
@ -236,6 +254,11 @@ func getNumDisplays() int {
|
||||
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
|
||||
func SysScale(displayId ...int) float64 {
|
||||
display := displayIdx(displayId...)
|
||||
@ -243,7 +266,7 @@ func SysScale(displayId ...int) float64 {
|
||||
return float64(s)
|
||||
}
|
||||
|
||||
// Scaled get the screen scaled size
|
||||
// Scaled get the screen scaled return scale size
|
||||
func Scaled(x int, displayId ...int) int {
|
||||
f := ScaleF(displayId...)
|
||||
return Scaled0(x, f)
|
||||
@ -254,6 +277,11 @@ func Scaled0(x int, f float64) int {
|
||||
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
|
||||
func GetScreenSize() (int, int) {
|
||||
size := C.getMainDisplaySize()
|
||||
@ -272,7 +300,8 @@ func GetScreenRect(displayId ...int) Rect {
|
||||
int(rect.size.w), int(rect.size.h)
|
||||
|
||||
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)
|
||||
}
|
||||
return Rect{
|
||||
@ -311,13 +340,21 @@ func CaptureScreen(args ...int) CBitmap {
|
||||
} else {
|
||||
// Get the main screen rect.
|
||||
rect := GetScreenRect(displayId)
|
||||
// x = C.int32_t(rect.X)
|
||||
// y = C.int32_t(rect.Y)
|
||||
if runtime.GOOS == "windows" {
|
||||
x = C.int32_t(rect.X)
|
||||
y = C.int32_t(rect.Y)
|
||||
}
|
||||
|
||||
w = C.int32_t(rect.W)
|
||||
h = C.int32_t(rect.H)
|
||||
}
|
||||
|
||||
bit := C.capture_screen(x, y, w, h, C.int32_t(displayId))
|
||||
isPid := 0
|
||||
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)
|
||||
}
|
||||
|
||||
@ -329,12 +366,15 @@ func CaptureGo(args ...int) Bitmap {
|
||||
return ToBitmap(bit)
|
||||
}
|
||||
|
||||
// CaptureImg capture the screen and return image.Image
|
||||
func CaptureImg(args ...int) image.Image {
|
||||
// CaptureImg capture the screen and return image.Image, error
|
||||
func CaptureImg(args ...int) (image.Image, error) {
|
||||
bit := CaptureScreen(args...)
|
||||
if bit == nil {
|
||||
return nil, errors.New("Capture image not found.")
|
||||
}
|
||||
defer FreeBitmap(bit)
|
||||
|
||||
return ToImage(bit)
|
||||
return ToImage(bit), nil
|
||||
}
|
||||
|
||||
// FreeBitmap free and dealloc the C bitmap
|
||||
@ -423,6 +463,11 @@ func GetXDisplayName() string {
|
||||
return gname
|
||||
}
|
||||
|
||||
// CloseMainDisplay close the main X11 display
|
||||
func CloseMainDisplay() {
|
||||
C.close_main_display()
|
||||
}
|
||||
|
||||
// Deprecated: use the ScaledF(),
|
||||
//
|
||||
// ScaleX get the primary display horizontal DPI scale factor, drop
|
||||
@ -430,45 +475,6 @@ func ScaleX() int {
|
||||
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
|
||||
}
|
||||
|
||||
/*
|
||||
.___ ___. ______ __ __ _______. _______
|
||||
| \/ | / __ \ | | | | / || ____|
|
||||
@ -498,23 +504,24 @@ func CheckMouse(btn string) C.MMMouseButton {
|
||||
return C.LEFT_BUTTON
|
||||
}
|
||||
|
||||
// Deprecated: use the Move(),
|
||||
//
|
||||
// MoveMouse move the mouse
|
||||
func MoveMouse(x, y int) {
|
||||
Move(x, y)
|
||||
// MoveScale calculate the os scale factor x, y
|
||||
func MoveScale(x, y int, displayId ...int) (int, int) {
|
||||
if Scale || runtime.GOOS == "windows" {
|
||||
f := ScaleF()
|
||||
x, y = Scaled1(x, f), Scaled1(y, f)
|
||||
}
|
||||
|
||||
return x, y
|
||||
}
|
||||
|
||||
// Move move the mouse to (x, y)
|
||||
//
|
||||
// Examples:
|
||||
// robotgo.MouseSleep = 100 // 100 millisecond
|
||||
// robotgo.Move(10, 10)
|
||||
func Move(x, y int) {
|
||||
// if runtime.GOOS == "windows" {
|
||||
// f := ScaleF()
|
||||
// x, y = Scaled0(x, f), Scaled0(y, f)
|
||||
// }
|
||||
//
|
||||
// robotgo.MouseSleep = 100 // 100 millisecond
|
||||
// robotgo.Move(10, 10)
|
||||
func Move(x, y int, displayId ...int) {
|
||||
x, y = MoveScale(x, y, displayId...)
|
||||
|
||||
cx := C.int32_t(x)
|
||||
cy := C.int32_t(y)
|
||||
@ -523,23 +530,13 @@ func Move(x, y int) {
|
||||
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(),
|
||||
//
|
||||
// Drag drag the mouse to (x, y),
|
||||
// It's not valid now, use the DragSmooth()
|
||||
func Drag(x, y int, args ...string) {
|
||||
x, y = MoveScale(x, y)
|
||||
|
||||
var button C.MMMouseButton = C.LEFT_BUTTON
|
||||
cx := C.int32_t(x)
|
||||
cy := C.int32_t(y)
|
||||
@ -555,6 +552,7 @@ func Drag(x, y int, args ...string) {
|
||||
// DragSmooth drag the mouse like smooth to (x, y)
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// robotgo.DragSmooth(10, 10)
|
||||
func DragSmooth(x, y int, args ...interface{}) {
|
||||
Toggle("left")
|
||||
@ -563,20 +561,13 @@ func DragSmooth(x, y int, args ...interface{}) {
|
||||
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,
|
||||
// moves mouse to x, y human like, with the mouse button up.
|
||||
//
|
||||
// robotgo.MoveSmooth(x, y int, low, high float64, mouseDelay int)
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// robotgo.MoveSmooth(10, 10)
|
||||
// robotgo.MoveSmooth(10, 10, 1.0, 2.0)
|
||||
func MoveSmooth(x, y int, args ...interface{}) bool {
|
||||
@ -584,6 +575,7 @@ func MoveSmooth(x, y int, args ...interface{}) bool {
|
||||
// f := ScaleF()
|
||||
// x, y = Scaled0(x, f), Scaled0(y, f)
|
||||
// }
|
||||
x, y = MoveScale(x, y)
|
||||
|
||||
cx := C.int32_t(x)
|
||||
cy := C.int32_t(y)
|
||||
@ -614,7 +606,7 @@ func MoveSmooth(x, y int, args ...interface{}) bool {
|
||||
|
||||
// MoveArgs get the mouse relative args
|
||||
func MoveArgs(x, y int) (int, int) {
|
||||
mx, my := GetMousePos()
|
||||
mx, my := Location()
|
||||
mx = mx + x
|
||||
my = my + y
|
||||
|
||||
@ -632,22 +624,18 @@ func MoveSmoothRelative(x, y int, args ...interface{}) {
|
||||
MoveSmooth(mx, my, args...)
|
||||
}
|
||||
|
||||
// GetMousePos get the mouse's position return x, y
|
||||
func GetMousePos() (int, int) {
|
||||
pos := C.getMousePos()
|
||||
// Location get the mouse location position return x, y
|
||||
func Location() (int, int) {
|
||||
pos := C.location()
|
||||
x := int(pos.x)
|
||||
y := int(pos.y)
|
||||
|
||||
return x, y
|
||||
}
|
||||
if Scale || runtime.GOOS == "windows" {
|
||||
f := ScaleF()
|
||||
x, y = Scaled0(x, f), Scaled0(y, f)
|
||||
}
|
||||
|
||||
// Deprecated: use the Click(),
|
||||
//
|
||||
// MouseClick click the mouse
|
||||
//
|
||||
// robotgo.MouseClick(button string, double bool)
|
||||
func MouseClick(args ...interface{}) {
|
||||
Click(args...)
|
||||
return x, y
|
||||
}
|
||||
|
||||
// Click click the mouse button
|
||||
@ -655,7 +643,8 @@ func MouseClick(args ...interface{}) {
|
||||
// robotgo.Click(button string, double bool)
|
||||
//
|
||||
// Examples:
|
||||
// robotgo.Click() // default is left button
|
||||
//
|
||||
// robotgo.Click() // default is left button
|
||||
// robotgo.Click("right")
|
||||
// robotgo.Click("wheelLeft")
|
||||
func Click(args ...interface{}) {
|
||||
@ -686,6 +675,7 @@ func Click(args ...interface{}) {
|
||||
// robotgo.MoveClick(x, y int, button string, double bool)
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// robotgo.MouseSleep = 100
|
||||
// robotgo.MoveClick(10, 10)
|
||||
func MoveClick(x, y int, args ...interface{}) {
|
||||
@ -704,35 +694,39 @@ func MovesClick(x, y int, args ...interface{}) {
|
||||
}
|
||||
|
||||
// Toggle toggle the mouse, support button:
|
||||
// "left", "center", "right",
|
||||
// "wheelDown", "wheelUp", "wheelLeft", "wheelRight"
|
||||
//
|
||||
// "left", "center", "right",
|
||||
// "wheelDown", "wheelUp", "wheelLeft", "wheelRight"
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// robotgo.Toggle("left") // default is down
|
||||
// robotgo.Toggle("left", "up")
|
||||
func Toggle(key ...string) error {
|
||||
func Toggle(key ...interface{}) error {
|
||||
var button C.MMMouseButton = C.LEFT_BUTTON
|
||||
if len(key) > 0 {
|
||||
button = CheckMouse(key[0])
|
||||
button = CheckMouse(key[0].(string))
|
||||
}
|
||||
|
||||
down := true
|
||||
if len(key) > 1 && key[1] == "up" {
|
||||
if len(key) > 1 && key[1].(string) == "up" {
|
||||
down = false
|
||||
}
|
||||
C.toggleMouse(C.bool(down), button)
|
||||
MilliSleep(MouseSleep)
|
||||
if len(key) > 2 {
|
||||
MilliSleep(MouseSleep)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MouseDown send mouse down event
|
||||
func MouseDown(key ...string) error {
|
||||
func MouseDown(key ...interface{}) error {
|
||||
return Toggle(key...)
|
||||
}
|
||||
|
||||
// MouseUp send mouse up event
|
||||
func MouseUp(key ...string) error {
|
||||
func MouseUp(key ...interface{}) error {
|
||||
if len(key) <= 0 {
|
||||
key = append(key, "left")
|
||||
}
|
||||
@ -744,6 +738,7 @@ func MouseUp(key ...string) error {
|
||||
// robotgo.Scroll(x, y, msDelay int)
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// robotgo.Scroll(10, 10)
|
||||
func Scroll(x, y int, args ...int) {
|
||||
var msDelay = 10
|
||||
@ -758,16 +753,17 @@ func Scroll(x, y int, args ...int) {
|
||||
MilliSleep(MouseSleep + msDelay)
|
||||
}
|
||||
|
||||
// ScrollMouse scroll the mouse to (x, "up")
|
||||
// ScrollDir scroll the mouse with direction to (x, "up")
|
||||
// supported: "up", "down", "left", "right"
|
||||
//
|
||||
// Examples:
|
||||
// robotgo.ScrollMouse(10, "down")
|
||||
// robotgo.ScrollMouse(10, "up")
|
||||
func ScrollMouse(x int, direction ...string) {
|
||||
//
|
||||
// robotgo.ScrollDir(10, "down")
|
||||
// robotgo.ScrollDir(10, "up")
|
||||
func ScrollDir(x int, direction ...interface{}) {
|
||||
d := "down"
|
||||
if len(direction) > 0 {
|
||||
d = direction[0]
|
||||
d = direction[0].(string)
|
||||
}
|
||||
|
||||
if d == "down" {
|
||||
@ -792,6 +788,7 @@ func ScrollMouse(x int, direction ...string) {
|
||||
// robotgo.ScrollSmooth(toy, num, sleep, tox)
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// robotgo.ScrollSmooth(-10)
|
||||
// robotgo.ScrollSmooth(-10, 6, 200, -10)
|
||||
func ScrollSmooth(to int, args ...int) {
|
||||
@ -823,6 +820,7 @@ func ScrollSmooth(to int, args ...int) {
|
||||
// ScrollRelative scroll mouse with relative
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// robotgo.ScrollRelative(10, 10)
|
||||
func ScrollRelative(x, y int, args ...int) {
|
||||
mx, my := MoveArgs(x, y)
|
||||
@ -883,67 +881,77 @@ func IsValid() bool {
|
||||
}
|
||||
|
||||
// SetActive set the window active
|
||||
func SetActive(win C.MData) {
|
||||
func SetActive(win Handle) {
|
||||
SetActiveC(C.MData(win))
|
||||
}
|
||||
|
||||
// SetActiveC set the window active
|
||||
func SetActiveC(win C.MData) {
|
||||
C.set_active(win)
|
||||
}
|
||||
|
||||
// GetActive get the active window
|
||||
func GetActive() C.MData {
|
||||
func GetActive() Handle {
|
||||
return Handle(GetActiveC())
|
||||
}
|
||||
|
||||
// GetActiveC get the active window
|
||||
func GetActiveC() C.MData {
|
||||
mdata := C.get_active()
|
||||
// fmt.Println("active----", mdata)
|
||||
return mdata
|
||||
}
|
||||
|
||||
// MinWindow set the window min
|
||||
func MinWindow(pid int32, args ...interface{}) {
|
||||
func MinWindow(pid int, args ...interface{}) {
|
||||
var (
|
||||
state = true
|
||||
hwnd int
|
||||
isPid int
|
||||
)
|
||||
|
||||
if len(args) > 0 {
|
||||
state = args[0].(bool)
|
||||
}
|
||||
if len(args) > 1 {
|
||||
hwnd = args[1].(int)
|
||||
if len(args) > 1 || NotPid {
|
||||
isPid = 1
|
||||
}
|
||||
|
||||
C.min_window(C.uintptr(pid), C.bool(state), C.uintptr(hwnd))
|
||||
C.min_window(C.uintptr(pid), C.bool(state), C.int8_t(isPid))
|
||||
}
|
||||
|
||||
// MaxWindow set the window max
|
||||
func MaxWindow(pid int32, args ...interface{}) {
|
||||
func MaxWindow(pid int, args ...interface{}) {
|
||||
var (
|
||||
state = true
|
||||
hwnd int
|
||||
isPid int
|
||||
)
|
||||
|
||||
if len(args) > 0 {
|
||||
state = args[0].(bool)
|
||||
}
|
||||
if len(args) > 1 {
|
||||
hwnd = args[1].(int)
|
||||
if len(args) > 1 || NotPid {
|
||||
isPid = 1
|
||||
}
|
||||
|
||||
C.max_window(C.uintptr(pid), C.bool(state), C.uintptr(hwnd))
|
||||
C.max_window(C.uintptr(pid), C.bool(state), C.int8_t(isPid))
|
||||
}
|
||||
|
||||
// CloseWindow close the window
|
||||
func CloseWindow(args ...int32) {
|
||||
func CloseWindow(args ...int) {
|
||||
if len(args) <= 0 {
|
||||
C.close_main_window()
|
||||
return
|
||||
}
|
||||
|
||||
var hwnd, isHwnd int32
|
||||
var pid, isPid int
|
||||
if len(args) > 0 {
|
||||
hwnd = args[0]
|
||||
pid = args[0]
|
||||
}
|
||||
if len(args) > 1 {
|
||||
isHwnd = args[1]
|
||||
if len(args) > 1 || NotPid {
|
||||
isPid = 1
|
||||
}
|
||||
|
||||
C.close_window_by_PId(C.uintptr(hwnd), C.uintptr(isHwnd))
|
||||
C.close_window_by_PId(C.uintptr(pid), C.int8_t(isPid))
|
||||
}
|
||||
|
||||
// SetHandle set the window handle
|
||||
@ -953,23 +961,44 @@ func SetHandle(hwnd int) {
|
||||
}
|
||||
|
||||
// SetHandlePid set the window handle by pid
|
||||
func SetHandlePid(pid int32, args ...int32) {
|
||||
var isHwnd int32
|
||||
if len(args) > 0 {
|
||||
isHwnd = args[0]
|
||||
func SetHandlePid(pid int, args ...int) {
|
||||
var isPid int
|
||||
if len(args) > 0 || NotPid {
|
||||
isPid = 1
|
||||
}
|
||||
|
||||
C.set_handle_pid_mData(C.uintptr(pid), C.uintptr(isHwnd))
|
||||
C.set_handle_pid_mData(C.uintptr(pid), C.int8_t(isPid))
|
||||
}
|
||||
|
||||
// GetHandPid get handle mdata by pid
|
||||
func GetHandPid(pid int32, args ...int32) C.MData {
|
||||
var isHwnd int32
|
||||
// GetHandById get handle mdata by id
|
||||
func GetHandById(id int, args ...int) Handle {
|
||||
isPid := 1
|
||||
if len(args) > 0 {
|
||||
isHwnd = args[0]
|
||||
isPid = args[0]
|
||||
}
|
||||
return GetHandByPid(id, isPid)
|
||||
}
|
||||
|
||||
// GetHandByPid get handle mdata by pid
|
||||
func GetHandByPid(pid int, args ...int) Handle {
|
||||
return Handle(GetHandByPidC(pid, args...))
|
||||
}
|
||||
|
||||
// Deprecated: use the GetHandByPid(),
|
||||
//
|
||||
// GetHandPid get handle mdata by pid
|
||||
func GetHandPid(pid int, args ...int) Handle {
|
||||
return GetHandByPid(pid, args...)
|
||||
}
|
||||
|
||||
// GetHandByPidC get handle mdata by pid
|
||||
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.uintptr(isHwnd))
|
||||
return C.set_handle_pid(C.uintptr(pid), C.int8_t(isPid))
|
||||
}
|
||||
|
||||
// GetHandle get the window handle
|
||||
@ -982,7 +1011,7 @@ func GetHandle() int {
|
||||
|
||||
// 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
|
||||
func GetBHandle() int {
|
||||
@ -993,8 +1022,8 @@ func GetBHandle() int {
|
||||
return ghwnd
|
||||
}
|
||||
|
||||
func cgetTitle(hwnd, isHwnd int32) string {
|
||||
title := C.get_title_by_pid(C.uintptr(hwnd), C.uintptr(isHwnd))
|
||||
func cgetTitle(pid, isPid int) string {
|
||||
title := C.get_title_by_pid(C.uintptr(pid), C.int8_t(isPid))
|
||||
gtitle := C.GoString(title)
|
||||
|
||||
return gtitle
|
||||
@ -1003,11 +1032,12 @@ func cgetTitle(hwnd, isHwnd int32) string {
|
||||
// GetTitle get the window title return string
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// fmt.Println(robotgo.GetTitle())
|
||||
//
|
||||
// ids, _ := robotgo.FindIds()
|
||||
// robotgo.GetTitle(ids[0])
|
||||
func GetTitle(args ...int32) string {
|
||||
func GetTitle(args ...int) string {
|
||||
if len(args) <= 0 {
|
||||
title := C.get_main_title()
|
||||
gtitle := C.GoString(title)
|
||||
@ -1021,21 +1051,21 @@ func GetTitle(args ...int32) string {
|
||||
return internalGetTitle(args[0])
|
||||
}
|
||||
|
||||
// GetPID get the process id return int32
|
||||
func GetPID() int32 {
|
||||
// GetPid get the process id return int32
|
||||
func GetPid() int {
|
||||
pid := C.get_PID()
|
||||
return int32(pid)
|
||||
return int(pid)
|
||||
}
|
||||
|
||||
// internalGetBounds get the window bounds
|
||||
func internalGetBounds(pid int32, hwnd int) (int, int, int, int) {
|
||||
bounds := C.get_bounds(C.uintptr(pid), C.uintptr(hwnd))
|
||||
func internalGetBounds(pid, isPid int) (int, int, int, int) {
|
||||
bounds := C.get_bounds(C.uintptr(pid), C.int8_t(isPid))
|
||||
return int(bounds.X), int(bounds.Y), int(bounds.W), int(bounds.H)
|
||||
}
|
||||
|
||||
// internalGetClient get the window client bounds
|
||||
func internalGetClient(pid int32, hwnd int) (int, int, int, int) {
|
||||
bounds := C.get_client(C.uintptr(pid), C.uintptr(hwnd))
|
||||
func internalGetClient(pid, isPid int) (int, int, int, int) {
|
||||
bounds := C.get_client(C.uintptr(pid), C.int8_t(isPid))
|
||||
return int(bounds.X), int(bounds.Y), int(bounds.W), int(bounds.H)
|
||||
}
|
||||
|
||||
@ -1045,29 +1075,30 @@ func Is64Bit() bool {
|
||||
return bool(b)
|
||||
}
|
||||
|
||||
func internalActive(pid int32, hwnd int) {
|
||||
C.active_PID(C.uintptr(pid), C.uintptr(hwnd))
|
||||
func internalActive(pid, isPid int) {
|
||||
C.active_PID(C.uintptr(pid), C.int8_t(isPid))
|
||||
}
|
||||
|
||||
// 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
|
||||
// func ActivePID(pid int32, args ...int) {
|
||||
// var hwnd int
|
||||
// func ActivePid(pid int32, args ...int) {
|
||||
// var isPid int
|
||||
// if len(args) > 0 {
|
||||
// hwnd = args[0]
|
||||
// isPid = args[0]
|
||||
// }
|
||||
|
||||
// C.active_PID(C.uintptr(pid), C.uintptr(hwnd))
|
||||
// C.active_PID(C.uintptr(pid), C.uintptr(isPid))
|
||||
// }
|
||||
|
||||
// ActiveName active the window by name
|
||||
//
|
||||
// Examples:
|
||||
// robotgo.ActiveName("chrome")
|
||||
//
|
||||
// robotgo.ActiveName("chrome")
|
||||
func ActiveName(name string) error {
|
||||
pids, err := FindIds(name)
|
||||
if err == nil && len(pids) > 0 {
|
||||
return ActivePID(pids[0])
|
||||
return ActivePid(pids[0])
|
||||
}
|
||||
|
||||
return err
|
||||
|
95
robotgo_fn_v1.go
Normal file
95
robotgo_fn_v1.go
Normal file
@ -0,0 +1,95 @@
|
||||
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
|
||||
}
|
@ -18,7 +18,7 @@ package robotgo
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// GetMianId get the main display id
|
||||
// GetMainId get the main display id
|
||||
func GetMainId() int {
|
||||
return int(C.CGMainDisplayID())
|
||||
}
|
||||
|
@ -14,50 +14,51 @@
|
||||
package robotgo
|
||||
|
||||
// GetBounds get the window bounds
|
||||
func GetBounds(pid int32, args ...int) (int, int, int, int) {
|
||||
var hwnd int
|
||||
if len(args) > 0 {
|
||||
hwnd = args[0]
|
||||
func GetBounds(pid int, args ...int) (int, int, int, int) {
|
||||
var isPid int
|
||||
if len(args) > 0 || NotPid {
|
||||
isPid = 1
|
||||
}
|
||||
|
||||
return internalGetBounds(pid, hwnd)
|
||||
return internalGetBounds(pid, isPid)
|
||||
}
|
||||
|
||||
// GetClient get the window client bounds
|
||||
func GetClient(pid int32, args ...int) (int, int, int, int) {
|
||||
var hwnd int
|
||||
if len(args) > 0 {
|
||||
hwnd = args[0]
|
||||
func GetClient(pid int, args ...int) (int, int, int, int) {
|
||||
var isPid int
|
||||
if len(args) > 0 || NotPid {
|
||||
isPid = 1
|
||||
}
|
||||
|
||||
return internalGetClient(pid, hwnd)
|
||||
return internalGetClient(pid, isPid)
|
||||
}
|
||||
|
||||
// internalGetTitle get the window title
|
||||
func internalGetTitle(pid int32, args ...int32) string {
|
||||
var isHwnd int32
|
||||
if len(args) > 0 {
|
||||
isHwnd = args[0]
|
||||
func internalGetTitle(pid int, args ...int) string {
|
||||
var isPid int
|
||||
if len(args) > 0 || NotPid {
|
||||
isPid = 1
|
||||
}
|
||||
gtitle := cgetTitle(pid, isHwnd)
|
||||
gtitle := cgetTitle(pid, isPid)
|
||||
|
||||
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
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// ids, _ := robotgo.FindIds()
|
||||
// robotgo.ActivePID(ids[0])
|
||||
func ActivePID(pid int32, args ...int) error {
|
||||
var hwnd int
|
||||
if len(args) > 0 {
|
||||
hwnd = args[0]
|
||||
// robotgo.ActivePid(ids[0])
|
||||
func ActivePid(pid int, args ...int) error {
|
||||
var isPid int
|
||||
if len(args) > 0 || NotPid {
|
||||
isPid = 1
|
||||
}
|
||||
|
||||
internalActive(pid, hwnd)
|
||||
internalActive(pid, isPid)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -71,6 +72,7 @@ func DisplaysNum() int {
|
||||
// If cancel button is not given, only the default button is displayed
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// robotgo.Alert("hi", "window", "ok", "cancel")
|
||||
func Alert(title, msg string, args ...string) bool {
|
||||
return showAlert(title, msg, args...)
|
||||
|
@ -42,7 +42,7 @@ func TestSize(t *testing.T) {
|
||||
func TestMoveMouse(t *testing.T) {
|
||||
Move(20, 20)
|
||||
MilliSleep(50)
|
||||
x, y := GetMousePos()
|
||||
x, y := Location()
|
||||
|
||||
tt.Equal(t, 20, x)
|
||||
tt.Equal(t, 20, y)
|
||||
@ -51,7 +51,7 @@ func TestMoveMouse(t *testing.T) {
|
||||
func TestMoveMouseSmooth(t *testing.T) {
|
||||
b := MoveSmooth(100, 100)
|
||||
MilliSleep(50)
|
||||
x, y := GetMousePos()
|
||||
x, y := Location()
|
||||
|
||||
tt.True(t, b)
|
||||
tt.Equal(t, 100, x)
|
||||
@ -61,15 +61,15 @@ func TestMoveMouseSmooth(t *testing.T) {
|
||||
func TestDragMouse(t *testing.T) {
|
||||
DragSmooth(500, 500)
|
||||
MilliSleep(50)
|
||||
x, y := GetMousePos()
|
||||
x, y := Location()
|
||||
|
||||
tt.Equal(t, 500, x)
|
||||
tt.Equal(t, 500, y)
|
||||
}
|
||||
|
||||
func TestScrollMouse(t *testing.T) {
|
||||
ScrollMouse(120, "up")
|
||||
ScrollMouse(100, "right")
|
||||
ScrollDir(120, "up")
|
||||
ScrollDir(100, "right")
|
||||
|
||||
Scroll(0, 120)
|
||||
MilliSleep(100)
|
||||
@ -85,7 +85,7 @@ func TestMoveRelative(t *testing.T) {
|
||||
MoveRelative(10, -10)
|
||||
MilliSleep(50)
|
||||
|
||||
x, y := GetMousePos()
|
||||
x, y := Location()
|
||||
tt.Equal(t, 210, x)
|
||||
tt.Equal(t, 190, y)
|
||||
}
|
||||
@ -97,7 +97,7 @@ func TestMoveSmoothRelative(t *testing.T) {
|
||||
MoveSmoothRelative(10, -10)
|
||||
MilliSleep(50)
|
||||
|
||||
x, y := GetMousePos()
|
||||
x, y := Location()
|
||||
tt.Equal(t, 210, x)
|
||||
tt.Equal(t, 190, y)
|
||||
}
|
||||
@ -179,7 +179,8 @@ func TestImage(t *testing.T) {
|
||||
err := SavePng(img, "robot_test.png")
|
||||
tt.Nil(t, err)
|
||||
|
||||
img1 := CaptureImg(10, 10, 20, 20)
|
||||
img1, err := CaptureImg(10, 10, 20, 20)
|
||||
tt.Nil(t, err)
|
||||
e := Save(img1, "robot_img.jpeg", 50)
|
||||
tt.Nil(t, e)
|
||||
|
||||
@ -194,7 +195,7 @@ func TestImage(t *testing.T) {
|
||||
func TestPs(t *testing.T) {
|
||||
id, err := Pids()
|
||||
tt.Not(t, "[]", id)
|
||||
tt.IsType(t, "[]int32", id)
|
||||
tt.IsType(t, "[]int", id)
|
||||
tt.Nil(t, err)
|
||||
|
||||
ps, e := Process()
|
||||
@ -217,9 +218,14 @@ func TestPs(t *testing.T) {
|
||||
|
||||
id, err = FindIds(n1[0])
|
||||
tt.Not(t, "[]", id)
|
||||
tt.IsType(t, "[]int32", id)
|
||||
tt.IsType(t, "[]int", id)
|
||||
tt.Nil(t, err)
|
||||
|
||||
if len(id) > 0 {
|
||||
e := KeyTap("v", id[0], "cmd")
|
||||
tt.Nil(t, e)
|
||||
}
|
||||
|
||||
// n, e = FindPath(id[0])
|
||||
// tt.NotEmpty(t, n)
|
||||
// tt.Nil(t, e)
|
||||
|
@ -17,7 +17,8 @@ import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/lxn/win"
|
||||
// "github.com/lxn/win"
|
||||
"github.com/tailscale/win"
|
||||
)
|
||||
|
||||
// FindWindow find window hwnd by name
|
||||
@ -52,30 +53,48 @@ func SetFocus(hwnd win.HWND) win.HWND {
|
||||
return win.SetFocus(hwnd)
|
||||
}
|
||||
|
||||
// GetMian get the main display hwnd
|
||||
// SetForeg set the window into the foreground by hwnd
|
||||
func SetForeg(hwnd win.HWND) bool {
|
||||
return win.SetForegroundWindow(hwnd)
|
||||
}
|
||||
|
||||
// GetMain get the main display hwnd
|
||||
func GetMain() win.HWND {
|
||||
return win.GetActiveWindow()
|
||||
}
|
||||
|
||||
// GetMianId get the main display id
|
||||
// GetMainId get the main display id
|
||||
func GetMainId() int {
|
||||
return int(GetMain())
|
||||
}
|
||||
|
||||
// ScaleF get the system scale val
|
||||
// ScaleF get the system scale value
|
||||
// if "displayId == -2" this function will get the desktop scale value
|
||||
func ScaleF(displayId ...int) (f float64) {
|
||||
if len(displayId) > 0 && displayId[0] != -1 {
|
||||
dpi := GetDPI(win.HWND(displayId[0]))
|
||||
f = float64(dpi) / 96.0
|
||||
if displayId[0] >= 0 {
|
||||
dpi := GetDPI(win.HWND(displayId[0]))
|
||||
f = float64(dpi) / 96.0
|
||||
}
|
||||
|
||||
if displayId[0] == -2 {
|
||||
f = float64(GetDPI(GetDesktopWindow())) / 96.0
|
||||
}
|
||||
} else {
|
||||
f = float64(GetMainDPI()) / 96.0
|
||||
}
|
||||
|
||||
if f == 0.0 {
|
||||
f = 1.0
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// GetDesktopWindow get the desktop window hwnd id
|
||||
func GetDesktopWindow() win.HWND {
|
||||
return win.GetDesktopWindow()
|
||||
}
|
||||
|
||||
// GetMainDPI get the display dpi
|
||||
func GetMainDPI() int {
|
||||
return int(GetDPI(GetHWND()))
|
||||
|
@ -15,7 +15,6 @@ package robotgo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/robotn/xgb"
|
||||
@ -28,81 +27,81 @@ import (
|
||||
var xu *xgbutil.XUtil
|
||||
|
||||
// GetBounds get the window bounds
|
||||
func GetBounds(pid int32, args ...int) (int, int, int, int) {
|
||||
var hwnd int
|
||||
if len(args) > 0 {
|
||||
hwnd = args[0]
|
||||
return internalGetBounds(pid, hwnd)
|
||||
func GetBounds(pid int, args ...int) (int, int, int, int) {
|
||||
var isPid int
|
||||
if len(args) > 0 || NotPid {
|
||||
isPid = 1
|
||||
return internalGetBounds(pid, isPid)
|
||||
}
|
||||
|
||||
xid, err := GetXId(xu, pid)
|
||||
xid, err := GetXid(xu, pid)
|
||||
if err != nil {
|
||||
log.Println("Get Xid from Pid errors is: ", err)
|
||||
return 0, 0, 0, 0
|
||||
}
|
||||
|
||||
return internalGetBounds(int32(xid), hwnd)
|
||||
return internalGetBounds(int(xid), isPid)
|
||||
}
|
||||
|
||||
// GetClient get the window client bounds
|
||||
func GetClient(pid int32, args ...int) (int, int, int, int) {
|
||||
var hwnd int
|
||||
if len(args) > 0 {
|
||||
hwnd = args[0]
|
||||
return internalGetClient(pid, hwnd)
|
||||
func GetClient(pid int, args ...int) (int, int, int, int) {
|
||||
var isPid int
|
||||
if len(args) > 0 || NotPid {
|
||||
isPid = 1
|
||||
return internalGetClient(pid, isPid)
|
||||
}
|
||||
|
||||
xid, err := GetXId(xu, pid)
|
||||
xid, err := GetXid(xu, pid)
|
||||
if err != nil {
|
||||
log.Println("Get Xid from Pid errors is: ", err)
|
||||
return 0, 0, 0, 0
|
||||
}
|
||||
|
||||
return internalGetClient(int32(xid), hwnd)
|
||||
return internalGetClient(int(xid), isPid)
|
||||
}
|
||||
|
||||
// internalGetTitle get the window title
|
||||
func internalGetTitle(pid int32, args ...int32) string {
|
||||
var hwnd int32
|
||||
if len(args) > 0 {
|
||||
hwnd = args[0]
|
||||
return cgetTitle(pid, hwnd)
|
||||
func internalGetTitle(pid int, args ...int) string {
|
||||
var isPid int
|
||||
if len(args) > 0 || NotPid {
|
||||
isPid = 1
|
||||
return cgetTitle(pid, isPid)
|
||||
}
|
||||
|
||||
xid, err := GetXId(xu, pid)
|
||||
xid, err := GetXid(xu, pid)
|
||||
if err != nil {
|
||||
log.Println("Get Xid from Pid errors is: ", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return cgetTitle(int32(xid), hwnd)
|
||||
return cgetTitle(int(xid), isPid)
|
||||
}
|
||||
|
||||
// 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
|
||||
func ActivePIDC(pid int32, args ...int) error {
|
||||
var hwnd int
|
||||
if len(args) > 0 {
|
||||
hwnd = args[0]
|
||||
internalActive(pid, hwnd)
|
||||
func ActivePidC(pid int, args ...int) error {
|
||||
var isPid int
|
||||
if len(args) > 0 || NotPid {
|
||||
isPid = 1
|
||||
internalActive(pid, isPid)
|
||||
return nil
|
||||
}
|
||||
|
||||
xid, err := GetXId(xu, pid)
|
||||
xid, err := GetXid(xu, pid)
|
||||
if err != nil {
|
||||
log.Println("Get Xid from Pid errors is: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
internalActive(int32(xid), hwnd)
|
||||
internalActive(int(xid), isPid)
|
||||
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 unix platform via a xid to active
|
||||
func ActivePID(pid int32, args ...int) error {
|
||||
func ActivePid(pid int, args ...int) error {
|
||||
if xu == nil {
|
||||
var err error
|
||||
xu, err = xgbutil.NewConn()
|
||||
@ -134,8 +133,8 @@ func ActivePID(pid int32, args ...int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetXId get the xid return window and error
|
||||
func GetXId(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
|
||||
// GetXid get the xid return window and error
|
||||
func GetXid(xu *xgbutil.XUtil, pid int) (xproto.Window, error) {
|
||||
if xu == nil {
|
||||
var err error
|
||||
xu, err = xgbutil.NewConn()
|
||||
@ -149,8 +148,8 @@ func GetXId(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
|
||||
return xid, err
|
||||
}
|
||||
|
||||
// GetXidFromPid get the xide from pid
|
||||
func GetXidFromPid(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
|
||||
// GetXidFromPid get the xid from pid
|
||||
func GetXidFromPid(xu *xgbutil.XUtil, pid int) (xproto.Window, error) {
|
||||
windows, err := ewmh.ClientListGet(xu)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@ -191,7 +190,7 @@ func DisplaysNum() int {
|
||||
return int(reply.Number)
|
||||
}
|
||||
|
||||
// GetMianId get the main display id
|
||||
// GetMainId get the main display id
|
||||
func GetMainId() int {
|
||||
conn, err := xgb.NewConn()
|
||||
if err != nil {
|
||||
@ -215,6 +214,7 @@ func GetMainId() int {
|
||||
// If cancel button is not given, only the default button is displayed
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// robotgo.Alert("hi", "window", "ok", "cancel")
|
||||
func Alert(title, msg string, args ...string) bool {
|
||||
defaultBtn, cancelBtn := alertArgs(args...)
|
||||
@ -224,10 +224,11 @@ func Alert(title, msg string, args ...string) bool {
|
||||
c += cancelBtn + ":1"
|
||||
}
|
||||
c += ` -default ` + defaultBtn
|
||||
c += ` -geometry 400x200`
|
||||
|
||||
out, err := Run(c)
|
||||
if err != nil {
|
||||
fmt.Println("Alert: ", err, ". ", string(out))
|
||||
// fmt.Println("Alert: ", err, ". ", string(out))
|
||||
return false
|
||||
}
|
||||
|
||||
|
63
screen.go
Normal file
63
screen.go
Normal file
@ -0,0 +1,63 @@
|
||||
// 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)
|
||||
}
|
@ -9,10 +9,9 @@
|
||||
// except according to those terms.
|
||||
|
||||
#include "../base/types.h"
|
||||
#include "../base/pubs.h"
|
||||
#include "../base/rgb.h"
|
||||
#include "../base/win32.h"
|
||||
#include "screengrab_c.h"
|
||||
#include "screen_c.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void padHex(MMRGBHex color, char* hex) {
|
||||
@ -51,7 +50,7 @@ MMRGBHex get_px_color(int32_t x, int32_t y, int32_t display_id) {
|
||||
return color;
|
||||
}
|
||||
|
||||
bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1), display_id);
|
||||
bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1), display_id, 0);
|
||||
color = MMRGBHexAtPoint(bitmap, 0, 0);
|
||||
destroyMMBitmap(bitmap);
|
||||
|
||||
@ -79,6 +78,14 @@ char* get_XDisplay_name() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void close_main_display() {
|
||||
#if defined(USE_X11)
|
||||
XCloseMainDisplay();
|
||||
#else
|
||||
//
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t get_num_displays() {
|
||||
#if defined(IS_MACOSX)
|
||||
uint32_t count = 0;
|
||||
@ -97,6 +104,15 @@ uint32_t get_num_displays() {
|
||||
#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) {
|
||||
if (bitmap != NULL) {
|
||||
destroyMMBitmap(bitmap);
|
||||
@ -105,8 +121,8 @@ void bitmap_dealloc(MMBitmapRef bitmap) {
|
||||
}
|
||||
|
||||
// capture_screen capture screen
|
||||
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);
|
||||
MMBitmapRef capture_screen(int32_t x, int32_t y, int32_t w, int32_t h, int32_t display_id, int8_t isPid) {
|
||||
MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, w, h), display_id, isPid);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,70 @@
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#elif defined(USE_X11)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xresource.h>
|
||||
// #include "../base/xdisplay_c.h"
|
||||
#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) {
|
||||
#if defined(IS_MACOSX)
|
||||
CGDirectDisplayID displayID = CGMainDisplayID();
|
||||
@ -22,15 +83,9 @@ MMSizeInt32 getMainDisplaySize(void) {
|
||||
(int32_t)DisplayWidth(display, screen),
|
||||
(int32_t)DisplayHeight(display, screen));
|
||||
#elif defined(IS_WINDOWS)
|
||||
if (GetSystemMetrics(SM_CMONITORS) == 1) {
|
||||
return MMSizeInt32Make(
|
||||
return MMSizeInt32Make(
|
||||
(int32_t)GetSystemMetrics(SM_CXSCREEN),
|
||||
(int32_t)GetSystemMetrics(SM_CYSCREEN));
|
||||
} else {
|
||||
return MMSizeInt32Make(
|
||||
(int32_t)GetSystemMetrics(SM_CXVIRTUALSCREEN),
|
||||
(int32_t)GetSystemMetrics(SM_CYVIRTUALSCREEN));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -56,7 +111,8 @@ MMRectInt32 getScreenRect(int32_t display_id) {
|
||||
(int32_t)DisplayWidth(display, screen),
|
||||
(int32_t)DisplayHeight(display, screen));
|
||||
#elif defined(IS_WINDOWS)
|
||||
if (GetSystemMetrics(SM_CMONITORS) == 1) {
|
||||
if (GetSystemMetrics(SM_CMONITORS) == 1
|
||||
|| display_id == -1 || display_id == 0) {
|
||||
return MMRectInt32Make(
|
||||
(int32_t)0,
|
||||
(int32_t)0,
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#include <OpenGL/gl.h>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include <ScreenCaptureKit/ScreenCaptureKit.h>
|
||||
#elif defined(USE_X11)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
@ -12,22 +13,79 @@
|
||||
#elif defined(IS_WINDOWS)
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include "screen_c.h"
|
||||
|
||||
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id) {
|
||||
#if defined(IS_MACOSX) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 140400
|
||||
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)
|
||||
MMBitmapRef bitmap = NULL;
|
||||
uint8_t *buffer = NULL;
|
||||
size_t bufferSize = 0;
|
||||
|
||||
CGDirectDisplayID displayID = (CGDirectDisplayID) display_id;
|
||||
if (displayID == -1) {
|
||||
if (displayID == -1 || displayID == 0) {
|
||||
displayID = CGMainDisplayID();
|
||||
}
|
||||
|
||||
CGImageRef image = CGDisplayCreateImageForRect(displayID,
|
||||
CGRectMake(rect.origin.x, rect.origin.y, rect.size.w, rect.size.h));
|
||||
MMPointInt32 o = rect.origin; MMSizeInt32 s = rect.size;
|
||||
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 140400
|
||||
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; }
|
||||
|
||||
|
||||
CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image));
|
||||
if (!imageData) { return NULL; }
|
||||
|
||||
@ -52,14 +110,15 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id)
|
||||
display = XGetMainDisplay();
|
||||
}
|
||||
|
||||
MMPointInt32 o = rect.origin; MMSizeInt32 s = rect.size;
|
||||
XImage *image = XGetImage(display, XDefaultRootWindow(display),
|
||||
(int)rect.origin.x, (int)rect.origin.y,
|
||||
(unsigned int)rect.size.w, (unsigned int)rect.size.h, AllPlanes, ZPixmap);
|
||||
(int)o.x, (int)o.y, (unsigned int)s.w, (unsigned int)s.h,
|
||||
AllPlanes, ZPixmap);
|
||||
XCloseDisplay(display);
|
||||
if (image == NULL) { return NULL; }
|
||||
|
||||
bitmap = createMMBitmap_c((uint8_t *)image->data,
|
||||
rect.size.w, rect.size.h, (size_t)image->bytes_per_line,
|
||||
s.w, s.h, (size_t)image->bytes_per_line,
|
||||
(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. */
|
||||
XDestroyImage(image);
|
||||
@ -72,44 +131,52 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id)
|
||||
HBITMAP dib;
|
||||
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. */
|
||||
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
|
||||
bi.bmiHeader.biWidth = (long)rect.size.w;
|
||||
bi.bmiHeader.biHeight = -(long)rect.size.h; /* Non-cartesian, please */
|
||||
bi.bmiHeader.biWidth = (long) w;
|
||||
bi.bmiHeader.biHeight = -(long) h; /* Non-cartesian, please */
|
||||
bi.bmiHeader.biPlanes = 1;
|
||||
bi.bmiHeader.biBitCount = 32;
|
||||
bi.bmiHeader.biCompression = BI_RGB;
|
||||
bi.bmiHeader.biSizeImage = (DWORD)(4 * rect.size.w * rect.size.h);
|
||||
bi.bmiHeader.biSizeImage = (DWORD)(4 * w * h);
|
||||
bi.bmiHeader.biXPelsPerMeter = 0;
|
||||
bi.bmiHeader.biYPelsPerMeter = 0;
|
||||
bi.bmiHeader.biClrUsed = 0;
|
||||
bi.bmiHeader.biClrImportant = 0;
|
||||
|
||||
if (display_id == -1) {
|
||||
screen = GetDC(NULL); /* Get entire screen */
|
||||
HWND hwnd;
|
||||
if (display_id == -1 || isPid == 0) {
|
||||
// screen = GetDC(NULL); /* Get entire screen */
|
||||
hwnd = GetDesktopWindow();
|
||||
} else {
|
||||
screen = GetDC((HWND) (uintptr) display_id);
|
||||
hwnd = (HWND) (uintptr) display_id;
|
||||
}
|
||||
screen = GetDC(hwnd);
|
||||
|
||||
if (screen == NULL) { return NULL; }
|
||||
|
||||
// Todo: Use DXGI
|
||||
screenMem = CreateCompatibleDC(screen);
|
||||
/* Get screen data in display device context. */
|
||||
dib = CreateDIBSection(screen, &bi, DIB_RGB_COLORS, &data, NULL, 0);
|
||||
|
||||
/* Copy the data into a bitmap struct. */
|
||||
BOOL smem = (screenMem = CreateCompatibleDC(screen)) == NULL;
|
||||
BOOL bitb = BitBlt(screenMem, (int)0, (int)0, (int)rect.size.w, (int)rect.size.h,
|
||||
screen, rect.origin.x, rect.origin.y, SRCCOPY);
|
||||
if (smem || SelectObject(screenMem, dib) == NULL || !bitb) {
|
||||
BOOL b = (screenMem == NULL) ||
|
||||
SelectObject(screenMem, dib) == NULL ||
|
||||
!BitBlt(screenMem, (int)0, (int)0, (int)w, (int)h, screen, x, y, SRCCOPY);
|
||||
if (b) {
|
||||
/* Error copying data. */
|
||||
ReleaseDC(NULL, screen);
|
||||
ReleaseDC(hwnd, screen);
|
||||
DeleteObject(dib);
|
||||
if (screenMem != NULL) { DeleteDC(screenMem); }
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bitmap = createMMBitmap_c(NULL, rect.size.w, rect.size.h, 4 * rect.size.w,
|
||||
(uint8_t)bi.bmiHeader.biBitCount, 4);
|
||||
bitmap = createMMBitmap_c(NULL, w, h, 4 * w, (uint8_t)bi.bmiHeader.biBitCount, 4);
|
||||
|
||||
/* Copy the data to our pixel buffer. */
|
||||
if (bitmap != NULL) {
|
||||
@ -117,7 +184,7 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id)
|
||||
memcpy(bitmap->imageBuffer, data, bitmap->bytewidth * bitmap->height);
|
||||
}
|
||||
|
||||
ReleaseDC(NULL, screen);
|
||||
ReleaseDC(hwnd, screen);
|
||||
DeleteObject(dib);
|
||||
DeleteDC(screenMem);
|
||||
|
||||
|
38
test/index.html
Normal file
38
test/index.html
Normal file
@ -0,0 +1,38 @@
|
||||
<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>
|
2
wayland_n.go
Normal file
2
wayland_n.go
Normal file
@ -0,0 +1,2 @@
|
||||
// +bulid linux,next
|
||||
package robotgo
|
@ -18,6 +18,7 @@ int showAlert(const char *title, const char *msg,
|
||||
CFStringRef defaultButtonTitle = CFStringCreateWithUTF8String(defaultButton);
|
||||
CFStringRef cancelButtonTitle = CFStringCreateWithUTF8String(cancelButton);
|
||||
CFOptionFlags responseFlags;
|
||||
|
||||
SInt32 err = CFUserNotificationDisplayAlert(
|
||||
0.0, kCFUserNotificationNoteAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage,
|
||||
defaultButtonTitle, cancelButtonTitle, NULL, &responseFlags);
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "window.h"
|
||||
#include "win_sys.h"
|
||||
|
||||
void min_window(uintptr pid, bool state, uintptr isHwnd){
|
||||
void min_window(uintptr pid, bool state, int8_t isPid){
|
||||
#if defined(IS_MACOSX)
|
||||
// return 0;
|
||||
AXUIElementRef axID = AXUIElementCreateApplication(pid);
|
||||
@ -23,16 +23,12 @@ void min_window(uintptr pid, bool state, uintptr isHwnd){
|
||||
XDismissErrors();
|
||||
// SetState((Window)pid, STATE_MINIMIZE, state);
|
||||
#elif defined(IS_WINDOWS)
|
||||
if (isHwnd == 0) {
|
||||
HWND hwnd = GetHwndByPId(pid);
|
||||
win_min(hwnd, state);
|
||||
} else {
|
||||
win_min((HWND)pid, state);
|
||||
}
|
||||
HWND hwnd = getHwnd(pid, isPid);
|
||||
win_min(hwnd, state);
|
||||
#endif
|
||||
}
|
||||
|
||||
void max_window(uintptr pid, bool state, uintptr isHwnd){
|
||||
void max_window(uintptr pid, bool state, int8_t isPid){
|
||||
#if defined(IS_MACOSX)
|
||||
// return 0;
|
||||
#elif defined(USE_X11)
|
||||
@ -40,12 +36,8 @@ void max_window(uintptr pid, bool state, uintptr isHwnd){
|
||||
// SetState((Window)pid, STATE_MINIMIZE, false);
|
||||
// SetState((Window)pid, STATE_MAXIMIZE, state);
|
||||
#elif defined(IS_WINDOWS)
|
||||
if (isHwnd == 0) {
|
||||
HWND hwnd = GetHwndByPId(pid);
|
||||
win_max(hwnd, state);
|
||||
} else {
|
||||
win_max((HWND)pid, state);
|
||||
}
|
||||
HWND hwnd = getHwnd(pid, isPid);
|
||||
win_max(hwnd, state);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -63,15 +55,15 @@ uintptr get_handle(){
|
||||
|
||||
uintptr b_get_handle() {
|
||||
#if defined(IS_MACOSX)
|
||||
return (uintptr)mData.CgID;
|
||||
return (uintptr)pub_mData.CgID;
|
||||
#elif defined(USE_X11)
|
||||
return (uintptr)mData.XWin;
|
||||
return (uintptr)pub_mData.XWin;
|
||||
#elif defined(IS_WINDOWS)
|
||||
return (uintptr)mData.HWnd;
|
||||
return (uintptr)pub_mData.HWnd;
|
||||
#endif
|
||||
}
|
||||
|
||||
void active_PID(uintptr pid, uintptr isHwnd){
|
||||
MData win = set_handle_pid(pid, isHwnd);
|
||||
void active_PID(uintptr pid, int8_t isPid){
|
||||
MData win = set_handle_pid(pid, isPid);
|
||||
set_active(win);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ struct _MData{
|
||||
};
|
||||
|
||||
typedef struct _MData MData;
|
||||
MData mData;
|
||||
MData pub_mData;
|
||||
|
||||
struct _Bounds {
|
||||
int32_t X; // Top left X coordinate
|
||||
@ -191,6 +191,7 @@ typedef struct _Bounds Bounds;
|
||||
if (items != NULL) {
|
||||
*items = (uint32_t) nItems;
|
||||
}
|
||||
XCloseDisplay(rDisplay);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -267,6 +268,8 @@ typedef struct _Bounds Bounds;
|
||||
|
||||
|
||||
#elif defined(IS_WINDOWS)
|
||||
HWND getHwnd(uintptr pid, int8_t isPid);
|
||||
|
||||
void win_min(HWND hwnd, bool state){
|
||||
if (state) {
|
||||
ShowWindow(hwnd, SW_MINIMIZE);
|
||||
|
@ -8,72 +8,13 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#if defined(USE_X11)
|
||||
#include <X11/Xresource.h>
|
||||
#endif
|
||||
// #if defined(USE_X11)
|
||||
// #include <X11/Xresource.h>
|
||||
// #endif
|
||||
|
||||
Bounds get_client(uintptr pid, uintptr isHwnd);
|
||||
intptr scaleX();
|
||||
Bounds get_client(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){
|
||||
Bounds get_bounds(uintptr pid, int8_t isPid){
|
||||
// Check if the window is valid
|
||||
Bounds bounds;
|
||||
if (!is_valid()) { return bounds; }
|
||||
@ -118,7 +59,7 @@ Bounds get_bounds(uintptr pid, uintptr isHwnd){
|
||||
MData win;
|
||||
win.XWin = (Window)pid;
|
||||
|
||||
Bounds client = get_client(pid, isHwnd);
|
||||
Bounds client = get_client(pid, isPid);
|
||||
Bounds frame = GetFrame(win);
|
||||
|
||||
bounds.X = client.X - frame.X;
|
||||
@ -128,12 +69,7 @@ Bounds get_bounds(uintptr pid, uintptr isHwnd){
|
||||
|
||||
return bounds;
|
||||
#elif defined(IS_WINDOWS)
|
||||
HWND hwnd;
|
||||
if (isHwnd == 0) {
|
||||
hwnd= GetHwndByPId(pid);
|
||||
} else {
|
||||
hwnd = (HWND)pid;
|
||||
}
|
||||
HWND hwnd = getHwnd(pid, isPid);
|
||||
|
||||
RECT rect = { 0 };
|
||||
GetWindowRect(hwnd, &rect);
|
||||
@ -147,13 +83,13 @@ Bounds get_bounds(uintptr pid, uintptr isHwnd){
|
||||
#endif
|
||||
}
|
||||
|
||||
Bounds get_client(uintptr pid, uintptr isHwnd) {
|
||||
Bounds get_client(uintptr pid, int8_t isPid) {
|
||||
// Check if the window is valid
|
||||
Bounds bounds;
|
||||
if (!is_valid()) { return bounds; }
|
||||
|
||||
#if defined(IS_MACOSX)
|
||||
return get_bounds(pid, isHwnd);
|
||||
return get_bounds(pid, isPid);
|
||||
#elif defined(USE_X11)
|
||||
Display *rDisplay = XOpenDisplay(NULL);
|
||||
|
||||
@ -193,12 +129,7 @@ Bounds get_client(uintptr pid, uintptr isHwnd) {
|
||||
|
||||
return bounds;
|
||||
#elif defined(IS_WINDOWS)
|
||||
HWND hwnd;
|
||||
if (isHwnd == 0) {
|
||||
hwnd = GetHwndByPId(pid);
|
||||
} else {
|
||||
hwnd = (HWND)pid;
|
||||
}
|
||||
HWND hwnd = getHwnd(pid, isPid);
|
||||
|
||||
RECT rect = { 0 };
|
||||
GetClientRect(hwnd, &rect);
|
||||
|
113
window/window.h
113
window/window.h
@ -15,7 +15,7 @@ bool is_valid();
|
||||
bool IsAxEnabled(bool options);
|
||||
|
||||
MData get_active(void);
|
||||
void initWindow();
|
||||
void initWindow(uintptr handle);
|
||||
char* get_title_by_hand(MData m_data);
|
||||
void close_window_by_Id(MData m_data);
|
||||
|
||||
@ -24,8 +24,8 @@ uintptr initHandle = 0;
|
||||
|
||||
void initWindow(uintptr handle){
|
||||
#if defined(IS_MACOSX)
|
||||
mData.CgID = 0;
|
||||
mData.AxID = 0;
|
||||
pub_mData.CgID = 0;
|
||||
pub_mData.AxID = 0;
|
||||
#elif defined(USE_X11)
|
||||
Display *rDisplay = XOpenDisplay(NULL);
|
||||
// If atoms loaded
|
||||
@ -34,10 +34,10 @@ void initWindow(uintptr handle){
|
||||
if (rDisplay != NULL) {LoadAtoms();}
|
||||
}
|
||||
|
||||
mData.XWin = 0;
|
||||
pub_mData.XWin = 0;
|
||||
XCloseDisplay(rDisplay);
|
||||
#elif defined(IS_WINDOWS)
|
||||
mData.HWnd = 0;
|
||||
pub_mData.HWnd = 0;
|
||||
#endif
|
||||
setHandle(handle);
|
||||
}
|
||||
@ -50,7 +50,7 @@ bool Is64Bit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
MData set_handle_pid(uintptr pid, uintptr isHwnd){
|
||||
MData set_handle_pid(uintptr pid, int8_t isPid){
|
||||
MData win;
|
||||
#if defined(IS_MACOSX)
|
||||
// Handle to a AXUIElementRef
|
||||
@ -59,45 +59,41 @@ MData set_handle_pid(uintptr pid, uintptr isHwnd){
|
||||
win.XWin = (Window)pid; // Handle to an X11 window
|
||||
#elif defined(IS_WINDOWS)
|
||||
// win.HWnd = (HWND)pid; // Handle to a window HWND
|
||||
if (isHwnd == 0) {
|
||||
win.HWnd = GetHwndByPId(pid);
|
||||
} else {
|
||||
win.HWnd = (HWND)pid;
|
||||
}
|
||||
win.HWnd = getHwnd(pid, isPid);
|
||||
#endif
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
void set_handle_pid_mData(uintptr pid, uintptr isHwnd){
|
||||
MData win = set_handle_pid(pid, isHwnd);
|
||||
mData = win;
|
||||
void set_handle_pid_mData(uintptr pid, int8_t isPid){
|
||||
MData win = set_handle_pid(pid, isPid);
|
||||
pub_mData = win;
|
||||
}
|
||||
|
||||
bool is_valid() {
|
||||
initWindow(initHandle);
|
||||
if (!IsAxEnabled(true)) {
|
||||
printf("%s\n", "Window: Accessibility API is disabled!\n"
|
||||
"Failed to enable access for assistive devices.");
|
||||
printf("%s\n", "Window: Accessibility API is disabled! "
|
||||
"Failed to enable access for assistive devices. \n");
|
||||
}
|
||||
MData actdata = get_active();
|
||||
|
||||
#if defined(IS_MACOSX)
|
||||
mData.CgID = actdata.CgID;
|
||||
mData.AxID = actdata.AxID;
|
||||
if (mData.CgID == 0 || mData.AxID == 0) { return false; }
|
||||
pub_mData.CgID = actdata.CgID;
|
||||
pub_mData.AxID = actdata.AxID;
|
||||
if (pub_mData.CgID == 0 || pub_mData.AxID == 0) { return false; }
|
||||
|
||||
CFTypeRef r = NULL;
|
||||
// Attempt to get the window role
|
||||
if (AXUIElementCopyAttributeValue(mData.AxID, kAXRoleAttribute, &r) == kAXErrorSuccess && r){
|
||||
if (AXUIElementCopyAttributeValue(pub_mData.AxID, kAXRoleAttribute, &r) == kAXErrorSuccess && r){
|
||||
CFRelease(r);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#elif defined(USE_X11)
|
||||
mData.XWin = actdata.XWin;
|
||||
if (mData.XWin == 0) { return false; }
|
||||
pub_mData.XWin = actdata.XWin;
|
||||
if (pub_mData.XWin == 0) { return false; }
|
||||
|
||||
Display *rDisplay = XOpenDisplay(NULL);
|
||||
// Check for a valid X-Window display
|
||||
@ -107,8 +103,11 @@ bool is_valid() {
|
||||
XDismissErrors();
|
||||
|
||||
// Get the window PID property
|
||||
void* result = GetWindowProperty(mData, WM_PID,NULL);
|
||||
if (result == NULL) { return false; }
|
||||
void* result = GetWindowProperty(pub_mData, WM_PID,NULL);
|
||||
if (result == NULL) {
|
||||
XCloseDisplay(rDisplay);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Free result and return true
|
||||
XFree(result);
|
||||
@ -116,12 +115,12 @@ bool is_valid() {
|
||||
|
||||
return true;
|
||||
#elif defined(IS_WINDOWS)
|
||||
mData.HWnd = actdata.HWnd;
|
||||
if (mData.HWnd == 0) {
|
||||
pub_mData.HWnd = actdata.HWnd;
|
||||
if (pub_mData.HWnd == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsWindow(mData.HWnd) != 0;
|
||||
return IsWindow(pub_mData.HWnd) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -176,13 +175,13 @@ bool IsAxEnabled(bool options){
|
||||
bool setHandle(uintptr handle){
|
||||
#if defined(IS_MACOSX)
|
||||
// Release the AX element
|
||||
if (mData.AxID != NULL) {
|
||||
CFRelease(mData.AxID);
|
||||
if (pub_mData.AxID != NULL) {
|
||||
CFRelease(pub_mData.AxID);
|
||||
}
|
||||
|
||||
// Reset both values
|
||||
mData.CgID = 0;
|
||||
mData.AxID = 0;
|
||||
pub_mData.CgID = 0;
|
||||
pub_mData.AxID = 0;
|
||||
|
||||
if (handle == 0) {
|
||||
// return 0;
|
||||
@ -193,8 +192,8 @@ bool setHandle(uintptr handle){
|
||||
CGWindowID cgID = (CGWindowID)handle;
|
||||
AXUIElementRef axID = GetUIElement(cgID);
|
||||
if (axID != NULL){
|
||||
mData.CgID = cgID;
|
||||
mData.AxID = axID;
|
||||
pub_mData.CgID = cgID;
|
||||
pub_mData.AxID = axID;
|
||||
// return 0;
|
||||
return true;
|
||||
}
|
||||
@ -202,7 +201,7 @@ bool setHandle(uintptr handle){
|
||||
// return 1;
|
||||
return false;
|
||||
#elif defined(USE_X11)
|
||||
mData.XWin = (Window)handle;
|
||||
pub_mData.XWin = (Window)handle;
|
||||
if (handle == 0) {
|
||||
return true;
|
||||
}
|
||||
@ -211,10 +210,10 @@ bool setHandle(uintptr handle){
|
||||
return true;
|
||||
}
|
||||
|
||||
mData.XWin = 0;
|
||||
pub_mData.XWin = 0;
|
||||
return false;
|
||||
#elif defined(IS_WINDOWS)
|
||||
mData.HWnd = (HWND)handle;
|
||||
pub_mData.HWnd = (HWND)handle;
|
||||
if (handle == 0) {
|
||||
return true;
|
||||
}
|
||||
@ -223,7 +222,7 @@ bool setHandle(uintptr handle){
|
||||
return true;
|
||||
}
|
||||
|
||||
mData.HWnd = 0;
|
||||
pub_mData.HWnd = 0;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@ -238,7 +237,7 @@ bool IsTopMost(void){
|
||||
// XDismissErrors ();
|
||||
// return GetState (mData.XWin, STATE_TOPMOST);
|
||||
#elif defined(IS_WINDOWS)
|
||||
return (GetWindowLongPtr(mData.HWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
|
||||
return (GetWindowLongPtr(pub_mData.HWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -248,7 +247,7 @@ bool IsMinimized(void){
|
||||
#if defined(IS_MACOSX)
|
||||
CFBooleanRef data = NULL;
|
||||
// Determine whether the window is minimized
|
||||
if (AXUIElementCopyAttributeValue(mData.AxID, kAXMinimizedAttribute,
|
||||
if (AXUIElementCopyAttributeValue(pub_mData.AxID, kAXMinimizedAttribute,
|
||||
(CFTypeRef*) &data) == kAXErrorSuccess && data != NULL) {
|
||||
// Convert resulting data into a bool
|
||||
bool result = CFBooleanGetValue(data);
|
||||
@ -262,7 +261,7 @@ bool IsMinimized(void){
|
||||
// XDismissErrors();
|
||||
// return GetState(mData.XWin, STATE_MINIMIZE);
|
||||
#elif defined(IS_WINDOWS)
|
||||
return (GetWindowLongPtr(mData.HWnd, GWL_STYLE) & WS_MINIMIZE) != 0;
|
||||
return (GetWindowLongPtr(pub_mData.HWnd, GWL_STYLE) & WS_MINIMIZE) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -277,7 +276,7 @@ bool IsMaximized(void){
|
||||
// XDismissErrors();
|
||||
// return GetState(mData.XWin, STATE_MAXIMIZE);
|
||||
#elif defined(IS_WINDOWS)
|
||||
return (GetWindowLongPtr(mData.HWnd, GWL_STYLE) & WS_MAXIMIZE) != 0;
|
||||
return (GetWindowLongPtr(pub_mData.HWnd, GWL_STYLE) & WS_MAXIMIZE) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -368,11 +367,11 @@ MData get_active(void) {
|
||||
if (focused == NULL) { return result; } // Verify
|
||||
|
||||
AXUIElementRef element;
|
||||
CGWindowID win = 0;
|
||||
// Retrieve the currently focused window
|
||||
if (AXUIElementCopyAttributeValue(focused, kAXFocusedWindowAttribute, (CFTypeRef*) &element)
|
||||
== kAXErrorSuccess && element) {
|
||||
|
||||
CGWindowID win = 0;
|
||||
// Use undocumented API to get WID
|
||||
if (_AXUIElementGetWindow(element, &win) == kAXErrorSuccess && win) {
|
||||
// Manually set internals
|
||||
@ -381,6 +380,9 @@ MData get_active(void) {
|
||||
} else {
|
||||
CFRelease(element);
|
||||
}
|
||||
} else {
|
||||
result.CgID = win;
|
||||
result.AxID = element;
|
||||
}
|
||||
CFRelease(focused);
|
||||
|
||||
@ -409,6 +411,7 @@ MData get_active(void) {
|
||||
if (window != 0) {
|
||||
// Set and return the foreground window
|
||||
result.XWin = (Window)window;
|
||||
XCloseDisplay(rDisplay);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -450,9 +453,9 @@ void SetTopMost(bool state){
|
||||
#elif defined(USE_X11)
|
||||
// Ignore X errors
|
||||
// XDismissErrors();
|
||||
// SetState(mData.XWin, STATE_TOPMOST, state);
|
||||
// SetState(pub_mData.XWin, STATE_TOPMOST, state);
|
||||
#elif defined(IS_WINDOWS)
|
||||
SetWindowPos(mData.HWnd, state ? HWND_TOPMOST : HWND_NOTOPMOST,
|
||||
SetWindowPos(pub_mData.HWnd, state ? HWND_TOPMOST : HWND_NOTOPMOST,
|
||||
0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||
#endif
|
||||
}
|
||||
@ -461,11 +464,11 @@ void close_main_window () {
|
||||
// Check if the window is valid
|
||||
if (!is_valid()) { return; }
|
||||
|
||||
close_window_by_Id(mData);
|
||||
close_window_by_Id(pub_mData);
|
||||
}
|
||||
|
||||
void close_window_by_PId(uintptr pid, uintptr isHwnd){
|
||||
MData win = set_handle_pid(pid, isHwnd);
|
||||
void close_window_by_PId(uintptr pid, int8_t isPid){
|
||||
MData win = set_handle_pid(pid, isPid);
|
||||
close_window_by_Id(win);
|
||||
}
|
||||
|
||||
@ -498,13 +501,13 @@ void close_window_by_Id(MData m_data){
|
||||
char* get_main_title(){
|
||||
// Check if the window is valid
|
||||
if (!is_valid()) { return "is_valid failed."; }
|
||||
|
||||
return get_title_by_hand(mData);
|
||||
|
||||
return get_title_by_hand(pub_mData);
|
||||
}
|
||||
|
||||
char* get_title_by_pid(uintptr pid, uintptr isHwnd){
|
||||
MData win = set_handle_pid(pid, isHwnd);
|
||||
return get_title_by_hand(win);
|
||||
char* get_title_by_pid(uintptr pid, int8_t isPid){
|
||||
MData win = set_handle_pid(pid, isPid);
|
||||
return get_title_by_hand(win);
|
||||
}
|
||||
|
||||
char* named(void *result) {
|
||||
@ -588,7 +591,7 @@ int32_t get_PID(void) {
|
||||
#if defined(IS_MACOSX)
|
||||
pid_t pid = 0;
|
||||
// Attempt to retrieve the window pid
|
||||
if (AXUIElementGetPid(mData.AxID, &pid)== kAXErrorSuccess) {
|
||||
if (AXUIElementGetPid(pub_mData.AxID, &pid)== kAXErrorSuccess) {
|
||||
return pid;
|
||||
}
|
||||
return 0;
|
||||
@ -597,7 +600,7 @@ int32_t get_PID(void) {
|
||||
XDismissErrors();
|
||||
|
||||
// Get the window PID
|
||||
long* result = (long*)GetWindowProperty(mData, WM_PID,NULL);
|
||||
long* result = (long*)GetWindowProperty(pub_mData, WM_PID,NULL);
|
||||
// Check result and convert it
|
||||
if (result == NULL) { return 0; }
|
||||
|
||||
@ -606,7 +609,7 @@ int32_t get_PID(void) {
|
||||
return pid;
|
||||
#elif defined(IS_WINDOWS)
|
||||
DWORD id = 0;
|
||||
GetWindowThreadProcessId(mData.HWnd, &id);
|
||||
GetWindowThreadProcessId(pub_mData.HWnd, &id);
|
||||
return id;
|
||||
#endif
|
||||
}
|
||||
|
2
windows_n.go
Normal file
2
windows_n.go
Normal file
@ -0,0 +1,2 @@
|
||||
// +bulid windows,next
|
||||
package robotgo
|
Loading…
Reference in New Issue
Block a user