mirror of
https://github.com/go-vgo/robotgo.git
synced 2025-06-03 23:53:54 +00:00
Compare commits
248 Commits
v1.0.0-bet
...
master
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c431c8f974 | ||
![]() |
a183783e9c | ||
![]() |
c1115cebc7 | ||
![]() |
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 | ||
![]() |
45b85e1ec3 | ||
![]() |
c395a0dcd6 | ||
![]() |
5d651eb627 | ||
![]() |
c0ef98e712 | ||
![]() |
d14fae83be | ||
![]() |
8aa3348a2a | ||
![]() |
ebdc6878e5 | ||
![]() |
a9d995fdf6 | ||
![]() |
be9b02c588 | ||
![]() |
264f658a46 | ||
![]() |
6c1e845183 | ||
![]() |
84d85b1995 | ||
![]() |
4a043157ad | ||
![]() |
1fac32d382 | ||
![]() |
74c3f6e08e | ||
![]() |
76b123142f | ||
![]() |
b543a49322 | ||
![]() |
fafd2bfcd4 | ||
![]() |
b439c59d85 | ||
![]() |
5d460e5100 | ||
![]() |
d82ca8cee4 | ||
![]() |
3655e795d7 | ||
![]() |
f0b614d78e | ||
![]() |
c61fe44788 | ||
![]() |
2d52e2c008 | ||
![]() |
75cfe774b3 | ||
![]() |
00fa7ff5fc | ||
![]() |
4599d66f5b | ||
![]() |
2502329583 | ||
![]() |
82cde2281e | ||
![]() |
99963bc6fc | ||
![]() |
c5446b655d | ||
![]() |
ed45411f5c | ||
![]() |
b6ef01a929 | ||
![]() |
149d0f8307 | ||
![]() |
e81c9ec843 | ||
![]() |
cd7ed72bf2 | ||
![]() |
72167ef467 | ||
![]() |
5c0f1d340b | ||
![]() |
70f6c276ac | ||
![]() |
8ad853dca2 | ||
![]() |
9d145c042c | ||
![]() |
427d2b4d61 | ||
![]() |
ce43fa6621 | ||
![]() |
76abeff3ff | ||
![]() |
80ee9fcc43 | ||
![]() |
18243a2192 | ||
![]() |
168a26ff5d | ||
![]() |
969478625a | ||
![]() |
540bf594ff | ||
![]() |
b8b8450f67 | ||
![]() |
bafa051f92 |
.circleci
.github
.travis.ymlCONTRIBUTING.mdREADME.mdREADME_zh.mdappveyor.ymlbase
MMBitmap.hbase.gobitmap_free_c.hdeadbeef_rand.hdeadbeef_rand_c.hendian.hinline_keywords.hmicrosleep.hms_stdbool.hms_stdint.hos.hpubs.hrgb.htypes.hxdisplay.hxdisplay_c.h
clipboard
doc.godocs
examples
go.modgo.sumimg.gokey.gokey
keycode.gomouse
ps.gorobot_info_test.gorobotgo.gorobotgo_fn_v1.gorobotgo_mac.gorobotgo_mac_win.gorobotgo_ocr.gorobotgo_test.gorobotgo_win.gorobotgo_x11.goscreen.goscreen
test
wayland_n.gowindow
windows_n.go@ -5,7 +5,7 @@ jobs:
|
|||||||
docker:
|
docker:
|
||||||
# using custom image, see .circleci/images/primary/Dockerfile
|
# using custom image, see .circleci/images/primary/Dockerfile
|
||||||
# - image: govgo/robotgoci:1.10.3
|
# - image: govgo/robotgoci:1.10.3
|
||||||
- image: golang:1.17.6
|
- image: golang:1.23.0
|
||||||
working_directory: /gopath/src/github.com/go-vgo/robotgo
|
working_directory: /gopath/src/github.com/go-vgo/robotgo
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
@ -20,7 +20,6 @@ jobs:
|
|||||||
- run: apt -y install xvfb
|
- run: apt -y install xvfb
|
||||||
#
|
#
|
||||||
# override:
|
# override:
|
||||||
# - run: go get -u github.com/go-vgo/robotgo
|
|
||||||
- run: go get -v -t -d ./...
|
- run: go get -v -t -d ./...
|
||||||
- run: xvfb-run go test -v ./...
|
- run: xvfb-run go test -v ./...
|
||||||
#
|
#
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# FROM golang:1.10.1
|
# 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
|
# FROM govgo/go:1.11.1
|
||||||
|
|
||||||
RUN apt update && apt install -y --no-install-recommends \
|
RUN apt update && apt install -y --no-install-recommends \
|
||||||
|
5
.github/issue_template.md
vendored
5
.github/issue_template.md
vendored
@ -1,11 +1,12 @@
|
|||||||
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**.
|
2. Please take a moment to **search** that an issue **doesn't already exist**.
|
||||||
3. Please make sure `Golang, GCC` is installed correctly before installing RobotGo.
|
3. Please make sure `Golang, GCC` is installed correctly before installing RobotGo.
|
||||||
4. Please ask questions or config/deploy problems on our Gitter channel: https://gitter.im/go-vgo/robotgo
|
<!-- 4. Please ask questions or config/deploy problems on our Gitter channel: https://gitter.im/go-vgo/robotgo -->
|
||||||
5. Please give all relevant information below for bug reports, incomplete details will be handled as an invalid report.
|
5. Please give all relevant information below for bug reports, incomplete details will be handled as an invalid report.
|
||||||
|
|
||||||
**You MUST delete the content above including this line before posting, otherwise your issue will be invalid.**
|
**You MUST delete the content above including this line before posting, otherwise your issue will be invalid.**
|
||||||
|
|
||||||
|
|
||||||
- Robotgo version (or commit ref):
|
- Robotgo version (or commit ref):
|
||||||
- Go version:
|
- Go version:
|
||||||
- Gcc version:
|
- Gcc version:
|
||||||
|
3
.github/pull_request_template.md
vendored
3
.github/pull_request_template.md
vendored
@ -5,10 +5,11 @@ The pull request will be closed without any reasons if it does not satisfy any o
|
|||||||
3. Please read contributing guidelines: [CONTRIBUTING](https://github.com/go-vgo/robotgo/blob/master/CONTRIBUTING.md)
|
3. Please read contributing guidelines: [CONTRIBUTING](https://github.com/go-vgo/robotgo/blob/master/CONTRIBUTING.md)
|
||||||
4. Describe what your pull request does and which issue you're targeting (if any and **Please use English**)
|
4. Describe what your pull request does and which issue you're targeting (if any and **Please use English**)
|
||||||
5. ... if it is not related to any particular issues, explain why we should not reject your pull request.
|
5. ... if it is not related to any particular issues, explain why we should not reject your pull request.
|
||||||
6. The Commits must use English, must be test and No useless submissions.
|
6. The Commits must **use English**, must be test and No useless submissions.
|
||||||
|
|
||||||
**You MUST delete the content above including this line before posting, otherwise your pull request will be invalid.**
|
**You MUST delete the content above including this line before posting, otherwise your pull request will be invalid.**
|
||||||
|
|
||||||
|
|
||||||
**Please provide Issues links to:**
|
**Please provide Issues links to:**
|
||||||
|
|
||||||
- Issues: #1
|
- Issues: #1
|
||||||
|
4
.github/workflows/go.yml
vendored
4
.github/workflows/go.yml
vendored
@ -10,10 +10,10 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go 1.17
|
- name: Set up Go 1.24.0
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v1
|
||||||
with:
|
with:
|
||||||
go-version: 1.17
|
go-version: 1.24.0
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
|
@ -15,7 +15,9 @@ go:
|
|||||||
# - 1.14.x
|
# - 1.14.x
|
||||||
# - 1.15.x
|
# - 1.15.x
|
||||||
# - 1.16.x
|
# - 1.16.x
|
||||||
- 1.17.x
|
# - 1.17.x
|
||||||
|
# - 1.18.x
|
||||||
|
- 1.19.x
|
||||||
# - tip
|
# - tip
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
|
@ -24,7 +24,7 @@ This process gives everyone a chance to validate the design, helps prevent dupli
|
|||||||
|
|
||||||
## Testing redux
|
## Testing redux
|
||||||
|
|
||||||
Before sending code out for review, run all the tests for the whole tree to make sure the changes don't break other usage and keep the compatibility on upgrade. You must be test on Mac, Windows, Linux and other. You should install the CLI for Circle CI, as we are using the server for 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
|
## Code review
|
||||||
|
|
||||||
|
242
README.md
242
README.md
@ -4,31 +4,33 @@
|
|||||||
<!--[](https://travis-ci.org/go-vgo/robotgo)
|
<!--[](https://travis-ci.org/go-vgo/robotgo)
|
||||||
[](https://codecov.io/gh/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>-->
|
<!--<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://github.com/go-vgo/robotgo/commits/master)
|
||||||
[](https://circleci.com/gh/go-vgo/robotgo)
|
[](https://circleci.com/gh/go-vgo/robotgo)
|
||||||
[](https://travis-ci.org/go-vgo/robotgo)
|
[](https://travis-ci.org/go-vgo/robotgo)
|
||||||

|

|
||||||
[](https://goreportcard.com/report/github.com/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://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://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) -->
|
<!-- [](https://github.com/go-vgo/robotgo/releases/latest) -->
|
||||||
<!-- <a href="https://github.com/go-vgo/robotgo/releases"><img src="https://img.shields.io/badge/%20version%20-%206.0.0%20-blue.svg?style=flat-square" alt="Releases"></a> -->
|
<!-- <a href="https://github.com/go-vgo/robotgo/releases"><img src="https://img.shields.io/badge/%20version%20-%206.0.0%20-blue.svg?style=flat-square" alt="Releases"></a> -->
|
||||||
|
|
||||||
> Golang Desktop Automation. Control the mouse, keyboard, 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.
|
RobotGo supports Mac, Windows, and Linux(X11); and robotgo supports arm64 and x86-amd64.
|
||||||
|
|
||||||
[Chinese Simplified](https://github.com/go-vgo/robotgo/blob/master/README_zh.md)
|
|
||||||
|
|
||||||
## Contents
|
## Contents
|
||||||
|
|
||||||
- [Docs](#docs)
|
- [Docs](#docs)
|
||||||
- [Binding](#binding)
|
- [Binding](#binding)
|
||||||
- [Requirements](#requirements)
|
- [Requirements](#requirements)
|
||||||
- [Installation](#installation)
|
- [Installation](#installation)
|
||||||
- [Update](#update)
|
- [Update](#update)
|
||||||
- [Examples](#examples)
|
- [Examples](#examples)
|
||||||
- [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)
|
- [Authors](#authors)
|
||||||
- [Plans](#plans)
|
- [Plans](#plans)
|
||||||
- [Donate](#donate)
|
- [Donate](#donate)
|
||||||
@ -36,12 +38,12 @@ RobotGo supports Mac, Windows, and Linux(X11); and robotgo supports arm64 and x8
|
|||||||
- [License](#license)
|
- [License](#license)
|
||||||
|
|
||||||
## Docs
|
## Docs
|
||||||
- [GoDoc](https://godoc.org/github.com/go-vgo/robotgo) <br>
|
|
||||||
|
- [GoDoc](https://godoc.org/github.com/go-vgo/robotgo) <br>
|
||||||
- [API Docs](https://github.com/go-vgo/robotgo/blob/master/docs/doc.md) (Deprecated, no updated)
|
- [API Docs](https://github.com/go-vgo/robotgo/blob/master/docs/doc.md) (Deprecated, no updated)
|
||||||
- [Chinese Docs](https://github.com/go-vgo/robotgo/blob/master/docs/doc_zh.md) (Deprecated, no updated)
|
|
||||||
|
|
||||||
## Binding:
|
## Binding:
|
||||||
|
|
||||||
[ADB](https://github.com/vcaesar/adb), packaging android adb API.
|
[ADB](https://github.com/vcaesar/adb), packaging android adb API.
|
||||||
|
|
||||||
[Robotn](https://github.com/vcaesar/robotn), binding JavaScript and other, support more language.
|
[Robotn](https://github.com/vcaesar/robotn), binding JavaScript and other, support more language.
|
||||||
@ -51,69 +53,96 @@ RobotGo supports Mac, Windows, and Linux(X11); and robotgo supports arm64 and x8
|
|||||||
Now, Please make sure `Golang, GCC` is installed correctly before installing RobotGo.
|
Now, Please make sure `Golang, GCC` is installed correctly before installing RobotGo.
|
||||||
|
|
||||||
### ALL:
|
### ALL:
|
||||||
|
|
||||||
```
|
```
|
||||||
Golang
|
Golang
|
||||||
|
|
||||||
GCC
|
GCC
|
||||||
```
|
```
|
||||||
|
|
||||||
#### For 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
|
xcode-select --install
|
||||||
```
|
```
|
||||||
|
|
||||||
#### For Windows:
|
#### 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.
|
winget install MartinStorsjo.LLVM-MinGW.UCRT
|
||||||
Or you can removed the bitmap.go.
|
|
||||||
|
|
||||||
In the plans, the bitmap.go will moves to the bitmap dir, but break the API. )
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Or [MinGW-w64](https://sourceforge.net/projects/mingw-w64/files) (Use recommended) or others Mingw [llvm-mingw](https://github.com/mstorsjo/llvm-mingw);
|
||||||
|
|
||||||
|
Download the Mingw, then set system environment variables `C:\mingw64\bin` to the Path.
|
||||||
|
[Set environment variables to run GCC from command line](https://www.youtube.com/results?search_query=Set+environment+variables+to+run+GCC+from+command+line).
|
||||||
|
|
||||||
|
`Or the other GCC` (But you should compile the "libpng" with yourself when use the [bitmap](https://github.com/vcaesar/bitmap).)
|
||||||
|
|
||||||
#### For everything else:
|
#### For everything else:
|
||||||
|
|
||||||
```
|
```
|
||||||
GCC,
|
GCC
|
||||||
libpng (bitmap)
|
|
||||||
|
|
||||||
X11 with the XTest extension (also known as the Xtst library)
|
X11 with the XTest extension (the Xtst library)
|
||||||
|
|
||||||
Event:
|
"Clipboard": xsel xclip
|
||||||
|
|
||||||
xcb, xkb, libxkbcommon
|
|
||||||
|
|
||||||
Clipboard:
|
"Bitmap": libpng (Just used by the "bitmap".)
|
||||||
|
|
||||||
|
"Event-Gohook": xcb, xkb, libxkbcommon (Just used by the "hook".)
|
||||||
|
|
||||||
xsel xclip
|
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Ubuntu:
|
##### Ubuntu:
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
|
# sudo apt install golang
|
||||||
|
sudo snap install go --classic
|
||||||
|
|
||||||
# gcc
|
# gcc
|
||||||
sudo apt install gcc libc6-dev
|
sudo apt install gcc libc6-dev
|
||||||
|
|
||||||
sudo apt install libx11-dev xorg-dev libxtst-dev libpng++-dev
|
# x11
|
||||||
|
sudo apt install libx11-dev xorg-dev libxtst-dev
|
||||||
|
|
||||||
|
# Clipboard
|
||||||
|
sudo apt install xsel xclip
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bitmap
|
||||||
|
sudo apt install libpng++-dev
|
||||||
|
|
||||||
|
# GoHook
|
||||||
sudo apt install xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev libxkbcommon-dev
|
sudo apt install xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev libxkbcommon-dev
|
||||||
|
|
||||||
sudo apt install xsel xclip
|
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Fedora:
|
##### Fedora:
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
sudo dnf install libXtst-devel 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
|
sudo dnf install libpng-devel
|
||||||
|
|
||||||
sudo dnf install xsel xclip
|
# GoHook
|
||||||
|
sudo dnf install libxkbcommon-devel libxkbcommon-x11-devel xorg-x11-xkb-utils-devel
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation:
|
## Installation:
|
||||||
@ -133,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).
|
png.h: No such file or directory? Please see [issues/47](https://github.com/go-vgo/robotgo/issues/47).
|
||||||
|
|
||||||
## Update:
|
## Update:
|
||||||
|
|
||||||
```
|
```
|
||||||
go get -u github.com/go-vgo/robotgo
|
go get -u github.com/go-vgo/robotgo
|
||||||
```
|
```
|
||||||
@ -140,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).
|
Note go1.10.x C file compilation cache problem, [golang #24355](https://github.com/golang/go/issues/24355).
|
||||||
`go mod vendor` problem, [golang #26366](https://github.com/golang/go/issues/26366).
|
`go mod vendor` problem, [golang #26366](https://github.com/golang/go/issues/26366).
|
||||||
|
|
||||||
|
|
||||||
## [Examples:](https://github.com/go-vgo/robotgo/blob/master/examples)
|
## [Examples:](https://github.com/go-vgo/robotgo/blob/master/examples)
|
||||||
|
|
||||||
#### [Mouse](https://github.com/go-vgo/robotgo/blob/master/examples/mouse/main.go)
|
#### [Mouse](https://github.com/go-vgo/robotgo/blob/master/examples/mouse/main.go)
|
||||||
@ -149,11 +178,22 @@ Note go1.10.x C file compilation cache problem, [golang #24355](https://github.c
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/go-vgo/robotgo"
|
"github.com/go-vgo/robotgo"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// robotgo.ScrollMouse(10, "up")
|
robotgo.MouseSleep = 300
|
||||||
|
|
||||||
|
robotgo.Move(100, 100)
|
||||||
|
fmt.Println(robotgo.Location())
|
||||||
|
robotgo.Move(100, -200) // multi screen supported
|
||||||
|
robotgo.MoveSmooth(120, -150)
|
||||||
|
fmt.Println(robotgo.Location())
|
||||||
|
|
||||||
|
robotgo.ScrollDir(10, "up")
|
||||||
|
robotgo.ScrollDir(20, "right")
|
||||||
|
|
||||||
robotgo.Scroll(0, -10)
|
robotgo.Scroll(0, -10)
|
||||||
robotgo.Scroll(100, 0)
|
robotgo.Scroll(100, 0)
|
||||||
|
|
||||||
@ -161,10 +201,9 @@ func main() {
|
|||||||
robotgo.ScrollSmooth(-10, 6)
|
robotgo.ScrollSmooth(-10, 6)
|
||||||
// robotgo.ScrollRelative(10, -100)
|
// robotgo.ScrollRelative(10, -100)
|
||||||
|
|
||||||
robotgo.MouseSleep = 100
|
|
||||||
robotgo.Move(10, 20)
|
robotgo.Move(10, 20)
|
||||||
robotgo.MoveRelative(0, -10)
|
robotgo.MoveRelative(0, -10)
|
||||||
robotgo.Drag(10, 10)
|
robotgo.DragSmooth(10, 10)
|
||||||
|
|
||||||
robotgo.Click("wheelRight")
|
robotgo.Click("wheelRight")
|
||||||
robotgo.Click("left", true)
|
robotgo.Click("left", true)
|
||||||
@ -188,10 +227,11 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
robotgo.TypeStr("Hello World")
|
robotgo.TypeStr("Hello World")
|
||||||
robotgo.TypeStr("だんしゃり", 1.0)
|
robotgo.TypeStr("だんしゃり", 0, 1)
|
||||||
// robotgo.TypeStr("テストする")
|
// 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)
|
robotgo.Sleep(1)
|
||||||
|
|
||||||
// ustr := uint32(robotgo.CharCodeAt("Test", 0))
|
// ustr := uint32(robotgo.CharCodeAt("Test", 0))
|
||||||
@ -200,9 +240,9 @@ func main() {
|
|||||||
robotgo.KeySleep = 100
|
robotgo.KeySleep = 100
|
||||||
robotgo.KeyTap("enter")
|
robotgo.KeyTap("enter")
|
||||||
// robotgo.TypeStr("en")
|
// robotgo.TypeStr("en")
|
||||||
robotgo.KeyTap("i", "alt", "command")
|
robotgo.KeyTap("i", "alt", "cmd")
|
||||||
|
|
||||||
arr := []string{"alt", "command"}
|
arr := []string{"alt", "cmd"}
|
||||||
robotgo.KeyTap("i", arr)
|
robotgo.KeyTap("i", arr)
|
||||||
|
|
||||||
robotgo.MilliSleep(100)
|
robotgo.MilliSleep(100)
|
||||||
@ -224,13 +264,14 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/go-vgo/robotgo"
|
"github.com/go-vgo/robotgo"
|
||||||
"github.com/vcaesar/imgo"
|
"github.com/vcaesar/imgo"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
x, y := robotgo.GetMousePos()
|
x, y := robotgo.Location()
|
||||||
fmt.Println("pos: ", x, y)
|
fmt.Println("pos: ", x, y)
|
||||||
|
|
||||||
color := robotgo.GetPixelColor(100, 200)
|
color := robotgo.GetPixelColor(100, 200)
|
||||||
@ -241,14 +282,30 @@ func main() {
|
|||||||
|
|
||||||
bit := robotgo.CaptureScreen(10, 10, 30, 30)
|
bit := robotgo.CaptureScreen(10, 10, 30, 30)
|
||||||
defer robotgo.FreeBitmap(bit)
|
defer robotgo.FreeBitmap(bit)
|
||||||
robotgo.SaveBitmap(bit, "test_1.png")
|
|
||||||
|
|
||||||
img := robotgo.ToImage(bit)
|
img := robotgo.ToImage(bit)
|
||||||
imgo.Save("test.png", img)
|
imgo.Save("test.png", img)
|
||||||
|
|
||||||
|
num := robotgo.DisplaysNum()
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
robotgo.DisplayID = i
|
||||||
|
img1, _ := robotgo.CaptureImg()
|
||||||
|
path1 := "save_" + strconv.Itoa(i)
|
||||||
|
robotgo.Save(img1, path1+".png")
|
||||||
|
robotgo.SaveJpeg(img1, path1+".jpeg", 50)
|
||||||
|
|
||||||
|
img2, _ := robotgo.CaptureImg(10, 10, 20, 20)
|
||||||
|
robotgo.Save(img2, "test_"+strconv.Itoa(i)+".png")
|
||||||
|
|
||||||
|
x, y, w, h := robotgo.GetDisplayBounds(i)
|
||||||
|
img3, err := robotgo.CaptureImg(x, y, w, h)
|
||||||
|
fmt.Println("Capture error: ", err)
|
||||||
|
robotgo.Save(img3, path1+"_1.png")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### [Bitmap](https://github.com/go-vgo/robotgo/blob/master/examples/bitmap/main.go)
|
#### [Bitmap](https://github.com/vcaesar/bitmap/blob/main/examples/main.go)
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
package main
|
package main
|
||||||
@ -257,30 +314,31 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/go-vgo/robotgo"
|
"github.com/go-vgo/robotgo"
|
||||||
|
"github.com/vcaesar/bitmap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
bitmap := robotgo.CaptureScreen(10, 20, 30, 40)
|
bit := robotgo.CaptureScreen(10, 20, 30, 40)
|
||||||
// use `defer robotgo.FreeBitmap(bit)` to free the bitmap
|
// use `defer robotgo.FreeBitmap(bit)` to free the bitmap
|
||||||
defer robotgo.FreeBitmap(bitmap)
|
defer robotgo.FreeBitmap(bit)
|
||||||
|
|
||||||
fmt.Println("bitmap...", bitmap)
|
fmt.Println("bitmap...", bit)
|
||||||
img := robotgo.ToImage(bitmap)
|
img := robotgo.ToImage(bit)
|
||||||
robotgo.SavePng(img, "test_1.png")
|
// robotgo.SavePng(img, "test_1.png")
|
||||||
|
robotgo.Save(img, "test_1.png")
|
||||||
|
|
||||||
bit2 := robotgo.ToCBitmap(robotgo.ImgToBitmap(img))
|
bit2 := robotgo.ToCBitmap(robotgo.ImgToBitmap(img))
|
||||||
fx, fy := robotgo.FindBitmap(bit2)
|
fx, fy := bitmap.Find(bit2)
|
||||||
fmt.Println("FindBitmap------ ", fx, fy)
|
fmt.Println("FindBitmap------ ", fx, fy)
|
||||||
robotgo.Move(fx, fy)
|
robotgo.Move(fx, fy)
|
||||||
|
|
||||||
arr := robotgo.FindAllBitmap(bit2)
|
arr := bitmap.FindAll(bit2)
|
||||||
fmt.Println("Find all bitmap: ", arr)
|
fmt.Println("Find all bitmap: ", arr)
|
||||||
robotgo.SaveBitmap(bitmap, "test.png")
|
|
||||||
|
|
||||||
fx, fy = robotgo.FindBitmap(bitmap)
|
fx, fy = bitmap.Find(bit)
|
||||||
fmt.Println("FindBitmap------ ", fx, fy)
|
fmt.Println("FindBitmap------ ", fx, fy)
|
||||||
|
|
||||||
robotgo.SaveBitmap(bitmap, "test.png")
|
bitmap.Save(bit, "test.png")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -295,6 +353,7 @@ import (
|
|||||||
|
|
||||||
"github.com/go-vgo/robotgo"
|
"github.com/go-vgo/robotgo"
|
||||||
"github.com/vcaesar/gcv"
|
"github.com/vcaesar/gcv"
|
||||||
|
"github.com/vcaesar/bitmap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -311,18 +370,18 @@ func opencv() {
|
|||||||
fmt.Println(gcv.FindImgFile(name1, name))
|
fmt.Println(gcv.FindImgFile(name1, name))
|
||||||
fmt.Println(gcv.FindAllImgFile(name1, name))
|
fmt.Println(gcv.FindAllImgFile(name1, name))
|
||||||
|
|
||||||
bit := robotgo.OpenBitmap(name1)
|
bit := bitmap.Open(name1)
|
||||||
defer robotgo.FindBitmap(bit)
|
defer robotgo.FreeBitmap(bit)
|
||||||
fmt.Print("find bitmap: ")
|
fmt.Print("find bitmap: ")
|
||||||
fmt.Println(robotgo.FindBitmap(bit))
|
fmt.Println(bitmap.Find(bit))
|
||||||
|
|
||||||
// bit0 := robotgo.CaptureScreen()
|
// bit0 := robotgo.CaptureScreen()
|
||||||
// img := robotgo.ToImage(bit0)
|
// img := robotgo.ToImage(bit0)
|
||||||
// bit1 := robotgo.CaptureScreen(10, 10, 30, 30)
|
// bit1 := robotgo.CaptureScreen(10, 10, 30, 30)
|
||||||
// img1 := robotgo.ToImage(bit1)
|
// img1 := robotgo.ToImage(bit1)
|
||||||
// defer robotgo.FreeBitmapArr(bit0, bit1)
|
// defer robotgo.FreeBitmapArr(bit0, bit1)
|
||||||
img := robotgo.CaptureImg()
|
img, _ := robotgo.CaptureImg()
|
||||||
img1 := robotgo.CaptureImg(10, 10, 30, 30)
|
img1, _ := robotgo.CaptureImg(10, 10, 30, 30)
|
||||||
|
|
||||||
fmt.Print("gcv find image: ")
|
fmt.Print("gcv find image: ")
|
||||||
fmt.Println(gcv.FindImg(img1, img))
|
fmt.Println(gcv.FindImg(img1, img))
|
||||||
@ -346,7 +405,7 @@ func opencv() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### [Event](https://github.com/go-vgo/robotgo/blob/master/examples/gohook/main.go)
|
#### [Event](https://github.com/robotn/gohook/blob/master/examples/main.go)
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
package main
|
package main
|
||||||
@ -354,7 +413,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/go-vgo/robotgo"
|
// "github.com/go-vgo/robotgo"
|
||||||
hook "github.com/robotn/gohook"
|
hook "github.com/robotn/gohook"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -366,18 +425,18 @@ func main() {
|
|||||||
|
|
||||||
func add() {
|
func add() {
|
||||||
fmt.Println("--- Please press ctrl + shift + q to stop hook ---")
|
fmt.Println("--- Please press ctrl + shift + q to stop hook ---")
|
||||||
robotgo.EventHook(hook.KeyDown, []string{"q", "ctrl", "shift"}, func(e hook.Event) {
|
hook.Register(hook.KeyDown, []string{"q", "ctrl", "shift"}, func(e hook.Event) {
|
||||||
fmt.Println("ctrl-shift-q")
|
fmt.Println("ctrl-shift-q")
|
||||||
robotgo.EventEnd()
|
hook.End()
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println("--- Please press w---")
|
fmt.Println("--- Please press w---")
|
||||||
robotgo.EventHook(hook.KeyDown, []string{"w"}, func(e hook.Event) {
|
hook.Register(hook.KeyDown, []string{"w"}, func(e hook.Event) {
|
||||||
fmt.Println("w")
|
fmt.Println("w")
|
||||||
})
|
})
|
||||||
|
|
||||||
s := robotgo.EventStart()
|
s := hook.Start()
|
||||||
<-robotgo.EventProcess(s)
|
<-hook.Process(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func low() {
|
func low() {
|
||||||
@ -390,17 +449,17 @@ func low() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func event() {
|
func event() {
|
||||||
ok := robotgo.AddEvents("q", "ctrl", "shift")
|
ok := hook.AddEvents("q", "ctrl", "shift")
|
||||||
if ok {
|
if ok {
|
||||||
fmt.Println("add events...")
|
fmt.Println("add events...")
|
||||||
}
|
}
|
||||||
|
|
||||||
keve := robotgo.AddEvent("k")
|
keve := hook.AddEvent("k")
|
||||||
if keve {
|
if keve {
|
||||||
fmt.Println("you press... ", "k")
|
fmt.Println("you press... ", "k")
|
||||||
}
|
}
|
||||||
|
|
||||||
mleft := robotgo.AddEvent("mleft")
|
mleft := hook.AddEvent("mleft")
|
||||||
if mleft {
|
if mleft {
|
||||||
fmt.Println("you press... ", "mouse left button")
|
fmt.Println("you press... ", "mouse left button")
|
||||||
}
|
}
|
||||||
@ -424,7 +483,13 @@ func main() {
|
|||||||
fmt.Println("pids... ", fpid)
|
fmt.Println("pids... ", fpid)
|
||||||
|
|
||||||
if len(fpid) > 0 {
|
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])
|
robotgo.Kill(fpid[0])
|
||||||
}
|
}
|
||||||
@ -439,7 +504,7 @@ func main() {
|
|||||||
robotgo.Kill(100)
|
robotgo.Kill(100)
|
||||||
}
|
}
|
||||||
|
|
||||||
abool := robotgo.ShowAlert("test", "robotgo")
|
abool := robotgo.Alert("test", "robotgo")
|
||||||
if abool {
|
if abool {
|
||||||
fmt.Println("ok@@@ ", "ok")
|
fmt.Println("ok@@@ ", "ok")
|
||||||
}
|
}
|
||||||
@ -449,46 +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):
|
|
||||||
```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
|
## Authors
|
||||||
* [The author is vz](https://github.com/vcaesar)
|
|
||||||
* [Maintainers](https://github.com/orgs/go-vgo/people)
|
- [The author is vz](https://github.com/vcaesar)
|
||||||
* [Contributors](https://github.com/go-vgo/robotgo/graphs/contributors)
|
- [Maintainers](https://github.com/orgs/go-vgo/people)
|
||||||
|
- [Contributors](https://github.com/go-vgo/robotgo/graphs/contributors)
|
||||||
|
|
||||||
## Plans
|
## Plans
|
||||||
- Update Find an image on screen, read pixels from an image
|
|
||||||
|
- Refactor some C code to Go (such as x11, windows)
|
||||||
|
- Better multiscreen support
|
||||||
|
- Wayland support
|
||||||
- Update Window Handle
|
- Update Window Handle
|
||||||
- Try support Android, maybe support IOS
|
- Try to support Android and IOS
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
|
12
README_zh.md
12
README_zh.md
@ -1,5 +1,7 @@
|
|||||||
# Robotgo
|
# Robotgo
|
||||||
|
|
||||||
|
## !!! Warning: this page not updated !!!
|
||||||
|
|
||||||
[](https://github.com/go-vgo/robotgo/commits/master)
|
[](https://github.com/go-vgo/robotgo/commits/master)
|
||||||
[](https://circleci.com/gh/go-vgo/robotgo)
|
[](https://circleci.com/gh/go-vgo/robotgo)
|
||||||
[](https://travis-ci.org/go-vgo/robotgo)
|
[](https://travis-ci.org/go-vgo/robotgo)
|
||||||
@ -15,7 +17,7 @@ RobotGo 支持 Mac, Windows, and Linux(X11).
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
提 Issues 请到 [Github](https://github.com/go-vgo/robotgo), 便于统一管理和即时更新
|
提 Issues 请到 [Github](https://github.com/go-vgo/robotgo), 便于统一管理和即时更新; `REDAME_zh.md 已废弃, 不再更新`
|
||||||
|
|
||||||
## Contents
|
## Contents
|
||||||
- [Docs](#docs)
|
- [Docs](#docs)
|
||||||
@ -34,8 +36,8 @@ RobotGo 支持 Mac, Windows, and Linux(X11).
|
|||||||
## Docs
|
## Docs
|
||||||
- [GoDoc](https://godoc.org/github.com/go-vgo/robotgo) <br>
|
- [GoDoc](https://godoc.org/github.com/go-vgo/robotgo) <br>
|
||||||
|
|
||||||
- [中文文档](https://github.com/go-vgo/robotgo/blob/master/docs/doc_zh.md) (弃用)
|
<!-- - [中文文档](https://github.com/go-vgo/robotgo/blob/master/docs/doc_zh.md) (弃用)
|
||||||
- [English Docs](https://github.com/go-vgo/robotgo/blob/master/docs/doc.md) (弃用)
|
- [English Docs](https://github.com/go-vgo/robotgo/blob/master/docs/doc.md) (弃用) -->
|
||||||
|
|
||||||
## Binding:
|
## Binding:
|
||||||
|
|
||||||
@ -67,7 +69,7 @@ xcode-select --install
|
|||||||
|
|
||||||
```
|
```
|
||||||
Or the other GCC (But you should compile the "libpng" with yourself.
|
Or the other GCC (But you should compile the "libpng" with yourself.
|
||||||
Or you can removed the bitmap.go )
|
Or you can removed the bitmap.go.)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### For everything else (Linux 等其他系统):
|
#### For everything else (Linux 等其他系统):
|
||||||
@ -430,7 +432,7 @@ func main() {
|
|||||||
robotgo.Kill(100)
|
robotgo.Kill(100)
|
||||||
}
|
}
|
||||||
|
|
||||||
abool := robotgo.ShowAlert("test", "robotgo")
|
abool := robotgo.Alert("test", "robotgo")
|
||||||
if abool {
|
if abool {
|
||||||
fmt.Println("ok@@@ ", "ok")
|
fmt.Println("ok@@@ ", "ok")
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ environment:
|
|||||||
PATH: C:\msys64\mingw32\bin\;C:\Program Files (x86)\NSIS\;%PATH%
|
PATH: C:\msys64\mingw32\bin\;C:\Program Files (x86)\NSIS\;%PATH%
|
||||||
# - COMPILER: MINGW_W64
|
# - COMPILER: MINGW_W64
|
||||||
# ARCHITECTURE: x64
|
# ARCHITECTURE: x64
|
||||||
GOVERSION: 1.17.6
|
GOVERSION: 1.23.0
|
||||||
# GOPATH: c:\gopath
|
# GOPATH: c:\gopath
|
||||||
|
|
||||||
# scripts that run after cloning repository
|
# scripts that run after cloning repository
|
||||||
|
@ -5,89 +5,32 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "rgb.h"
|
#include "rgb.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
// #include <stdint.h>
|
#include <stdint.h>
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#include "ms_stdint.h"
|
|
||||||
#else
|
|
||||||
#include <stdint.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct _MMBitmap {
|
struct _MMBitmap {
|
||||||
uint8_t *imageBuffer; /* Pixels stored in Quad I format; i.e., origin is in
|
uint8_t *imageBuffer; /* Pixels stored in Quad I format; */
|
||||||
* top left. Length should be height * bytewidth. */
|
int32_t width; /* Never 0, unless image is NULL. */
|
||||||
size_t width; /* Never 0, unless image is NULL. */
|
int32_t height; /* Never 0, unless image is NULL. */
|
||||||
size_t height; /* Never 0, unless image is NULL. */
|
|
||||||
size_t bytewidth; /* The aligned width (width + padding). */
|
int32_t bytewidth; /* The aligned width (width + padding). */
|
||||||
uint8_t bitsPerPixel; /* Should be either 24 or 32. */
|
uint8_t bitsPerPixel; /* Should be either 24 or 32. */
|
||||||
uint8_t bytesPerPixel; /* For convenience; should be bitsPerPixel / 8. */
|
uint8_t bytesPerPixel; /* For convenience; should be bitsPerPixel / 8. */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _MMBitmap MMBitmap;
|
typedef struct _MMBitmap MMBitmap;
|
||||||
typedef MMBitmap *MMBitmapRef;
|
typedef MMBitmap *MMBitmapRef;
|
||||||
// MMBitmapRef bitmap;
|
|
||||||
|
|
||||||
/* Creates new MMBitmap with the given values.
|
#define MMBitmapPointInBounds(image, p) ((p).x < (image)->width && (p).y < (image)->height)
|
||||||
* Follows the Create Rule (caller is responsible for destroy()'ing object). */
|
|
||||||
MMBitmapRef createMMBitmap_c(uint8_t *buffer, size_t width, size_t height,
|
|
||||||
size_t bytewidth, uint8_t bitsPerPixel,
|
|
||||||
uint8_t bytesPerPixel);
|
|
||||||
|
|
||||||
/* Releases memory occupied by MMBitmap. */
|
/* Get pointer to pixel of MMBitmapRef. No bounds checking is performed */
|
||||||
void destroyMMBitmap(MMBitmapRef bitmap);
|
|
||||||
|
|
||||||
/* Releases memory occupied by MMBitmap. Acts via CallBack method*/
|
|
||||||
void destroyMMBitmapBuffer(char * bitmapBuffer, void * hint);
|
|
||||||
|
|
||||||
// /* Returns copy of MMBitmap, to be destroy()'d by caller. */
|
|
||||||
// MMBitmapRef copyMMBitmap(MMBitmapRef bitmap);
|
|
||||||
|
|
||||||
// /* Returns copy of one MMBitmap juxtaposed in another (to be destroy()'d
|
|
||||||
// * by the caller.), or NULL on error. */
|
|
||||||
// MMBitmapRef copyMMBitmapFromPortion(MMBitmapRef source, MMRect rect);
|
|
||||||
|
|
||||||
#define MMBitmapPointInBounds(image, p) ((p).x < (image)->width && \
|
|
||||||
(p).y < (image)->height)
|
|
||||||
#define MMBitmapRectInBounds(image, r) \
|
|
||||||
(((r).origin.x + (r).size.width <= (image)->width) && \
|
|
||||||
((r).origin.y + (r).size.height <= (image)->height))
|
|
||||||
|
|
||||||
#define MMBitmapGetBounds(image) MMRectMake(0, 0, image->width, image->height)
|
|
||||||
|
|
||||||
/* Get pointer to pixel of MMBitmapRef. No bounds checking is performed (check
|
|
||||||
* yourself before calling this with MMBitmapPointInBounds(). */
|
|
||||||
#define MMRGBColorRefAtPoint(image, x, y) \
|
#define MMRGBColorRefAtPoint(image, x, y) \
|
||||||
(MMRGBColor *)(assert(MMBitmapPointInBounds(image, MMPointMake(x, y))), \
|
(MMRGBColor *)(assert(MMBitmapPointInBounds(image, MMPointInt32Make(x, y))), \
|
||||||
((image)->imageBuffer) + (((image)->bytewidth * (y)) \
|
((image)->imageBuffer) + (((image)->bytewidth * (y)) + ((x) * (image)->bytesPerPixel)))
|
||||||
+ ((x) * (image)->bytesPerPixel)))
|
|
||||||
|
|
||||||
/* Dereference pixel of MMBitmapRef. Again, no bounds checking is performed. */
|
/* Dereference pixel of MMBitmapRef. Again, no bounds checking is performed. */
|
||||||
#define MMRGBColorAtPoint(image, x, y) *MMRGBColorRefAtPoint(image, x, y)
|
#define MMRGBColorAtPoint(image, x, y) *MMRGBColorRefAtPoint(image, x, y)
|
||||||
|
|
||||||
/* Hex/integer value of color at point. */
|
/* Hex/integer value of color at point. */
|
||||||
#define MMRGBHexAtPoint(image, x, y) \
|
#define MMRGBHexAtPoint(image, x, y) hexFromMMRGB(MMRGBColorAtPoint(image, x, y))
|
||||||
hexFromMMRGB(MMRGBColorAtPoint(image, x, y))
|
|
||||||
|
|
||||||
// /* Increment either point.x or point.y depending on the position of point.x.
|
|
||||||
// * That is, if x + 1 is >= width, increment y and start x at the beginning.
|
|
||||||
// * Otherwise, increment x.
|
|
||||||
// *
|
|
||||||
// * This is used as a convenience macro to scan rows when calling functions such
|
|
||||||
// * as findColorInRectAt() and findBitmapInBitmapAt(). */
|
|
||||||
// #define ITER_NEXT_POINT(pixel, width, start_x) \
|
|
||||||
// do { \
|
|
||||||
// if (++(pixel).x >= (width)) { \
|
|
||||||
// (pixel).x = start_x; \
|
|
||||||
// ++(point).y; \
|
|
||||||
// } \
|
|
||||||
// } while (0);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* MMBITMAP_H */
|
#endif /* MMBITMAP_H */
|
2
base/base.go
Normal file
2
base/base.go
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// https://github.com/golang/go/issues/26366
|
||||||
|
package base
|
@ -2,14 +2,9 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
MMBitmapRef createMMBitmap_c(
|
MMBitmapRef createMMBitmap_c(uint8_t *buffer, int32_t width, int32_t height,
|
||||||
uint8_t *buffer,
|
int32_t bytewidth, uint8_t bitsPerPixel, uint8_t bytesPerPixel
|
||||||
size_t width,
|
) {
|
||||||
size_t height,
|
|
||||||
size_t bytewidth,
|
|
||||||
uint8_t bitsPerPixel,
|
|
||||||
uint8_t bytesPerPixel
|
|
||||||
){
|
|
||||||
MMBitmapRef bitmap = malloc(sizeof(MMBitmap));
|
MMBitmapRef bitmap = malloc(sizeof(MMBitmap));
|
||||||
if (bitmap == NULL) { return NULL; }
|
if (bitmap == NULL) { return NULL; }
|
||||||
|
|
||||||
|
@ -4,11 +4,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define DEADBEEF_MAX UINT32_MAX
|
#define DEADBEEF_MAX UINT32_MAX
|
||||||
|
/* Dead Beef Random Number Generator From: http://inglorion.net/software/deadbeef_rand */
|
||||||
/* Dead Beef Random Number Generator
|
|
||||||
* From: http://inglorion.net/software/deadbeef_rand
|
|
||||||
* A fast, portable psuedo-random number generator by BJ Amsterdam Zuidoost.
|
|
||||||
* Stated in license terms: "Feel free to use the code in your own software." */
|
|
||||||
|
|
||||||
/* Generates a random number between 0 and DEADBEEF_MAX. */
|
/* Generates a random number between 0 and DEADBEEF_MAX. */
|
||||||
uint32_t deadbeef_rand(void);
|
uint32_t deadbeef_rand(void);
|
||||||
@ -22,14 +18,11 @@ uint32_t deadbeef_generate_seed(void);
|
|||||||
/* Seeds with the above function. */
|
/* Seeds with the above function. */
|
||||||
#define deadbeef_srand_time() deadbeef_srand(deadbeef_generate_seed())
|
#define deadbeef_srand_time() deadbeef_srand(deadbeef_generate_seed())
|
||||||
|
|
||||||
/* Returns random double in the range [a, b).
|
/* Returns random double in the range [a, b).*/
|
||||||
* Taken directly from the rand() man page. */
|
|
||||||
#define DEADBEEF_UNIFORM(a, b) \
|
#define DEADBEEF_UNIFORM(a, b) \
|
||||||
((a) + (deadbeef_rand() / (((double)DEADBEEF_MAX / (b - a) + 1))))
|
((a) + (deadbeef_rand() / (((double)DEADBEEF_MAX / (b - a) + 1))))
|
||||||
|
|
||||||
/* Returns random integer in the range [a, b).
|
/* Returns random integer in the range [a, b).*/
|
||||||
* Also taken from the rand() man page. */
|
#define DEADBEEF_RANDRANGE(a, b) (uint32_t)DEADBEEF_UNIFORM(a, b)
|
||||||
#define DEADBEEF_RANDRANGE(a, b) \
|
|
||||||
(uint32_t)DEADBEEF_UNIFORM(a, b)
|
|
||||||
|
|
||||||
#endif /* DEADBEEF_RAND_H */
|
#endif /* DEADBEEF_RAND_H */
|
||||||
|
@ -15,8 +15,7 @@ void deadbeef_srand(uint32_t x) {
|
|||||||
deadbeef_beef = 0xdeadbeef;
|
deadbeef_beef = 0xdeadbeef;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Taken directly from the documentation:
|
/* Taken directly from the documentation: http://inglorion.net/software/cstuff/deadbeef_rand/ */
|
||||||
* http://inglorion.net/software/cstuff/deadbeef_rand/ */
|
|
||||||
uint32_t deadbeef_generate_seed(void) {
|
uint32_t deadbeef_generate_seed(void) {
|
||||||
uint32_t t = (uint32_t)time(NULL);
|
uint32_t t = (uint32_t)time(NULL);
|
||||||
uint32_t c = (uint32_t)clock();
|
uint32_t c = (uint32_t)clock();
|
||||||
|
123
base/endian.h
123
base/endian.h
@ -1,123 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef ENDIAN_H
|
|
||||||
#define ENDIAN_H
|
|
||||||
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (Mostly) cross-platform endian definitions and bit swapping macros.
|
|
||||||
* Unfortunately, there is no standard C header for this, so we just
|
|
||||||
* include the most common ones and fallback to our own custom macros.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(__linux__) /* Linux */
|
|
||||||
#include <endian.h>
|
|
||||||
#include <byteswap.h>
|
|
||||||
#elif (defined(__FreeBSD__) && __FreeBSD_version >= 470000) || \
|
|
||||||
defined(__OpenBSD__) || defined(__NetBSD__) /* (Free|Open|Net)BSD */
|
|
||||||
#include <sys/endian.h>
|
|
||||||
#define __BIG_ENDIAN BIG_ENDIAN
|
|
||||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
|
||||||
#define __BYTE_ORDER BYTE_ORDER
|
|
||||||
#elif defined(IS_MACOSX) || (defined(BSD) && (BSD >= 199103)) /* Other BSD */
|
|
||||||
#include <machine/endian.h>
|
|
||||||
#define __BIG_ENDIAN BIG_ENDIAN
|
|
||||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
|
||||||
#define __BYTE_ORDER BYTE_ORDER
|
|
||||||
#elif defined(IS_WINDOWS) /* Windows is assumed to be little endian only. */
|
|
||||||
#define __BIG_ENDIAN 4321
|
|
||||||
#define __LITTLE_ENDIAN 1234
|
|
||||||
#define __BYTE_ORDER __LITTLE_ENDIAN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Fallback to custom constants. */
|
|
||||||
#if !defined(__BIG_ENDIAN)
|
|
||||||
#define __BIG_ENDIAN 4321
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(__LITTLE_ENDIAN)
|
|
||||||
#define __LITTLE_ENDIAN 1234
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Prefer compiler flag settings if given. */
|
|
||||||
#if defined(MM_BIG_ENDIAN)
|
|
||||||
#undef __BYTE_ORDER /* Avoid redefined macro compiler warning. */
|
|
||||||
#define __BYTE_ORDER __BIG_ENDIAN
|
|
||||||
#elif defined(MM_LITTLE_ENDIAN)
|
|
||||||
#undef __BYTE_ORDER /* Avoid redefined macro compiler warning. */
|
|
||||||
#define __BYTE_ORDER __LITTLE_ENDIAN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Define default endian-ness. */
|
|
||||||
#ifndef __LITTLE_ENDIAN
|
|
||||||
#define __LITTLE_ENDIAN 1234
|
|
||||||
#endif /* __LITTLE_ENDIAN */
|
|
||||||
|
|
||||||
#ifndef __BIG_ENDIAN
|
|
||||||
#define __BIG_ENDIAN 4321
|
|
||||||
#endif /* __BIG_ENDIAN */
|
|
||||||
|
|
||||||
#ifndef __BYTE_ORDER
|
|
||||||
#warning "Byte order not defined on your system; assuming little endian"
|
|
||||||
#define __BYTE_ORDER __LITTLE_ENDIAN
|
|
||||||
#endif /* __BYTE_ORDER */
|
|
||||||
|
|
||||||
#if __BYTE_ORDER != __BIG_ENDIAN && __BYTE_ORDER != __LITTLE_ENDIAN
|
|
||||||
#error "__BYTE_ORDER set to unknown byte order"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
|
||||||
#include <libkern/OSByteOrder.h>
|
|
||||||
|
|
||||||
/* OS X system functions. */
|
|
||||||
#define bitswap16(i) OSSwapInt16(i)
|
|
||||||
#define bitswap32(i) OSSwapInt32(i)
|
|
||||||
#define swapLittleAndHost32(i) OSSwapLittleToHostInt32(i)
|
|
||||||
#define swapLittleAndHost16(i) OSSwapLittleToHostInt16(i)
|
|
||||||
#else
|
|
||||||
#ifndef bitswap16
|
|
||||||
#if defined(bswap16)
|
|
||||||
#define bitswap16(i) bswap16(i) /* FreeBSD system function */
|
|
||||||
#elif defined(bswap_16)
|
|
||||||
#define bitswap16(i) bswap_16(i) /* Linux system function */
|
|
||||||
#else /* Default macro */
|
|
||||||
#define bitswap16(i) (((uint16_t)(i) & 0xFF00) >> 8) | \
|
|
||||||
(((uint16_t)(i) & 0x00FF) << 8)
|
|
||||||
#endif
|
|
||||||
#endif /* bitswap16 */
|
|
||||||
|
|
||||||
#ifndef bitswap32
|
|
||||||
#if defined(bswap32)
|
|
||||||
#define bitswap32(i) bswap32(i) /* FreeBSD system function. */
|
|
||||||
#elif defined(bswap_32)
|
|
||||||
#define bitswap32(i) bswap_32(i) /* Linux system function. */
|
|
||||||
#else /* Default macro */
|
|
||||||
#define bitswap32(i) (((uint32_t)(i) & 0xFF000000) >> 24) | \
|
|
||||||
((uint32_t)((i) & 0x00FF0000) >> 8) | \
|
|
||||||
((uint32_t)((i) & 0x0000FF00) << 8) | \
|
|
||||||
((uint32_t)((i) & 0x000000FF) << 24)
|
|
||||||
#endif
|
|
||||||
#endif /* bitswap32 */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
|
||||||
/* Little endian to/from host byte order (big endian). */
|
|
||||||
#ifndef swapLittleAndHost16
|
|
||||||
#define swapLittleAndHost16(i) bitswap16(i)
|
|
||||||
#endif /* swapLittleAndHost16 */
|
|
||||||
|
|
||||||
#ifndef swapLittleAndHost32
|
|
||||||
#define swapLittleAndHost32(i) bitswap32(i)
|
|
||||||
#endif /* swapLittleAndHost32 */
|
|
||||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
/* We are already little endian, so no conversion is needed. */
|
|
||||||
#ifndef swapLittleAndHost16
|
|
||||||
#define swapLittleAndHost16(i) i
|
|
||||||
#endif /* swapLittleAndHost16 */
|
|
||||||
|
|
||||||
#ifndef swapLittleAndHost32
|
|
||||||
#define swapLittleAndHost32(i) i
|
|
||||||
#endif /* swapLittleAndHost32 */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* ENDIAN_H */
|
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/* A complicated, portable model for declaring inline functions in
|
/* A complicated, portable model for declaring inline functions in header files. */
|
||||||
* header files. */
|
|
||||||
#if !defined(H_INLINE)
|
#if !defined(H_INLINE)
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
#define H_INLINE static __inline__ __attribute__((always_inline))
|
#define H_INLINE static __inline__ __attribute__((always_inline))
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "inline_keywords.h"
|
#include "inline_keywords.h"
|
||||||
|
|
||||||
|
// todo: removed
|
||||||
#if !defined(IS_WINDOWS)
|
#if !defined(IS_WINDOWS)
|
||||||
/* Make sure nanosleep gets defined even when using C89. */
|
/* Make sure nanosleep gets defined even when using C89. */
|
||||||
#if !defined(__USE_POSIX199309) || !__USE_POSIX199309
|
#if !defined(__USE_POSIX199309) || !__USE_POSIX199309
|
||||||
@ -14,21 +15,12 @@
|
|||||||
#include <time.h> /* For nanosleep() */
|
#include <time.h> /* For nanosleep() */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/* A more widely supported alternative to usleep(), based on Sleep() in Windows and nanosleep() */
|
||||||
* A more widely supported alternative to usleep(), based on Sleep() in Windows
|
|
||||||
* and nanosleep() everywhere else.
|
|
||||||
*
|
|
||||||
* Pauses execution for the given amount of milliseconds.
|
|
||||||
*/
|
|
||||||
H_INLINE void microsleep(double milliseconds) {
|
H_INLINE void microsleep(double milliseconds) {
|
||||||
#if defined(IS_WINDOWS)
|
#if defined(IS_WINDOWS)
|
||||||
Sleep((DWORD)milliseconds); /* (Unfortunately truncated to a 32-bit integer.) */
|
Sleep((DWORD)milliseconds); /* (Unfortunately truncated to a 32-bit integer.) */
|
||||||
#else
|
#else
|
||||||
/* Technically, nanosleep() is not an ANSI function, but it is the most
|
/* Technically, nanosleep() is not an ANSI function */
|
||||||
* supported precise sleeping function I can find.
|
|
||||||
*
|
|
||||||
* If it is really necessary, it may be possible to emulate this with some
|
|
||||||
* hack using select() in the future if we really have to. */
|
|
||||||
struct timespec sleepytime;
|
struct timespec sleepytime;
|
||||||
sleepytime.tv_sec = milliseconds / 1000;
|
sleepytime.tv_sec = milliseconds / 1000;
|
||||||
sleepytime.tv_nsec = (milliseconds - (sleepytime.tv_sec * 1000)) * 1000000;
|
sleepytime.tv_nsec = (milliseconds - (sleepytime.tv_sec * 1000)) * 1000000;
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#if !defined(MS_STDBOOL_H) && \
|
|
||||||
(!defined(__bool_true_false_are_defined) || __bool_true_false_are_defined)
|
|
||||||
#define MS_STDBOOL_H
|
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
|
||||||
#endif /* _MSC_VER */
|
|
||||||
|
|
||||||
#define __bool_true_false_are_defined 1
|
|
||||||
|
|
||||||
#ifndef __cplusplus
|
|
||||||
|
|
||||||
#if defined(true) || defined(false) || defined(bool)
|
|
||||||
#error "Boolean type already defined"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum {
|
|
||||||
false = 0,
|
|
||||||
true = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef unsigned char bool;
|
|
||||||
|
|
||||||
#endif /* !__cplusplus */
|
|
||||||
|
|
||||||
#endif /* MS_STDBOOL_H */
|
|
224
base/ms_stdint.h
224
base/ms_stdint.h
@ -1,224 +0,0 @@
|
|||||||
/* ISO C9x compliant stdint.h for Microsoft Visual Studio
|
|
||||||
* Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
|
||||||
*
|
|
||||||
* Copyright (c) 2006-2008 Alexander Chemeris
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* 3. The name of the author may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
||||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
|
||||||
#endif /* _MSC_VER */
|
|
||||||
|
|
||||||
#ifndef MSC_STDINT_H
|
|
||||||
#define MSC_STDINT_H
|
|
||||||
|
|
||||||
#if _MSC_VER > 1000
|
|
||||||
#pragma once
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
/* For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
|
||||||
* compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
|
|
||||||
* or compiler give many errors like this: */
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
extern "C" {
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
#include <wchar.h>
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
/* Define _W64 macros to mark types changing their size, like intptr_t. */
|
|
||||||
#ifndef _W64
|
|
||||||
#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
|
||||||
#define _W64 __w64
|
|
||||||
#else
|
|
||||||
#define _W64
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* 7.18.1 Integer types */
|
|
||||||
|
|
||||||
/* 7.18.1.1 Exact-width integer types */
|
|
||||||
|
|
||||||
/* Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
|
||||||
* realize that, e.g. char has the same size as __int8
|
|
||||||
* so we give up on __intX for them. */
|
|
||||||
#if _MSC_VER < 1300
|
|
||||||
typedef signed char int8_t;
|
|
||||||
typedef signed short int16_t;
|
|
||||||
typedef signed int int32_t;
|
|
||||||
typedef unsigned char uint8_t;
|
|
||||||
typedef unsigned short uint16_t;
|
|
||||||
typedef unsigned int uint32_t;
|
|
||||||
#else
|
|
||||||
typedef signed __int8 int8_t;
|
|
||||||
typedef signed __int16 int16_t;
|
|
||||||
typedef signed __int32 int32_t;
|
|
||||||
typedef unsigned __int8 uint8_t;
|
|
||||||
typedef unsigned __int16 uint16_t;
|
|
||||||
typedef unsigned __int32 uint32_t;
|
|
||||||
#endif
|
|
||||||
typedef signed __int64 int64_t;
|
|
||||||
typedef unsigned __int64 uint64_t;
|
|
||||||
|
|
||||||
/* 7.18.1.2 Minimum-width integer types */
|
|
||||||
typedef int8_t int_least8_t;
|
|
||||||
typedef int16_t int_least16_t;
|
|
||||||
typedef int32_t int_least32_t;
|
|
||||||
typedef int64_t int_least64_t;
|
|
||||||
typedef uint8_t uint_least8_t;
|
|
||||||
typedef uint16_t uint_least16_t;
|
|
||||||
typedef uint32_t uint_least32_t;
|
|
||||||
typedef uint64_t uint_least64_t;
|
|
||||||
|
|
||||||
/* 7.18.1.3 Fastest minimum-width integer types */
|
|
||||||
typedef int8_t int_fast8_t;
|
|
||||||
typedef int16_t int_fast16_t;
|
|
||||||
typedef int32_t int_fast32_t;
|
|
||||||
typedef int64_t int_fast64_t;
|
|
||||||
typedef uint8_t uint_fast8_t;
|
|
||||||
typedef uint16_t uint_fast16_t;
|
|
||||||
typedef uint32_t uint_fast32_t;
|
|
||||||
typedef uint64_t uint_fast64_t;
|
|
||||||
|
|
||||||
/* 7.18.1.4 Integer types capable of holding object pointers */
|
|
||||||
#if defined(_WIN64)
|
|
||||||
typedef signed __int64 intptr_t;
|
|
||||||
typedef unsigned __int64 uintptr_t;
|
|
||||||
#else
|
|
||||||
typedef _W64 signed int intptr_t;
|
|
||||||
typedef _W64 unsigned int uintptr_t;
|
|
||||||
#endif /* _WIN64 ] */
|
|
||||||
|
|
||||||
/* 7.18.1.5 Greatest-width integer types */
|
|
||||||
typedef int64_t intmax_t;
|
|
||||||
typedef uint64_t uintmax_t;
|
|
||||||
|
|
||||||
/* 7.18.2 Limits of specified-width integer types */
|
|
||||||
|
|
||||||
/* See footnote 220 at page 257 and footnote 221 at page 259 */
|
|
||||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
|
|
||||||
|
|
||||||
/* 7.18.2.1 Limits of exact-width integer types */
|
|
||||||
#define INT8_MIN ((int8_t)_I8_MIN)
|
|
||||||
#define INT8_MAX _I8_MAX
|
|
||||||
#define INT16_MIN ((int16_t)_I16_MIN)
|
|
||||||
#define INT16_MAX _I16_MAX
|
|
||||||
#define INT32_MIN ((int32_t)_I32_MIN)
|
|
||||||
#define INT32_MAX _I32_MAX
|
|
||||||
#define INT64_MIN ((int64_t)_I64_MIN)
|
|
||||||
#define INT64_MAX _I64_MAX
|
|
||||||
#define UINT8_MAX _UI8_MAX
|
|
||||||
#define UINT16_MAX _UI16_MAX
|
|
||||||
#define UINT32_MAX _UI32_MAX
|
|
||||||
#define UINT64_MAX _UI64_MAX
|
|
||||||
|
|
||||||
/* 7.18.2.2 Limits of minimum-width integer types */
|
|
||||||
#define INT_LEAST8_MIN INT8_MIN
|
|
||||||
#define INT_LEAST8_MAX INT8_MAX
|
|
||||||
#define INT_LEAST16_MIN INT16_MIN
|
|
||||||
#define INT_LEAST16_MAX INT16_MAX
|
|
||||||
#define INT_LEAST32_MIN INT32_MIN
|
|
||||||
#define INT_LEAST32_MAX INT32_MAX
|
|
||||||
#define INT_LEAST64_MIN INT64_MIN
|
|
||||||
#define INT_LEAST64_MAX INT64_MAX
|
|
||||||
#define UINT_LEAST8_MAX UINT8_MAX
|
|
||||||
#define UINT_LEAST16_MAX UINT16_MAX
|
|
||||||
#define UINT_LEAST32_MAX UINT32_MAX
|
|
||||||
#define UINT_LEAST64_MAX UINT64_MAX
|
|
||||||
|
|
||||||
/* 7.18.2.4 Limits of integer types capable of holding object pointers */
|
|
||||||
#if defined(_WIN64)
|
|
||||||
#define INTPTR_MIN INT64_MIN
|
|
||||||
#define INTPTR_MAX INT64_MAX
|
|
||||||
#define UINTPTR_MAX UINT64_MAX
|
|
||||||
#else
|
|
||||||
#define INTPTR_MIN INT32_MIN
|
|
||||||
#define INTPTR_MAX INT32_MAX
|
|
||||||
#define UINTPTR_MAX UINT32_MAX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* 7.18.3 Limits of other integer types */
|
|
||||||
|
|
||||||
#if defined(_WIN64)
|
|
||||||
#define PTRDIFF_MIN _I64_MIN
|
|
||||||
#define PTRDIFF_MAX _I64_MAX
|
|
||||||
#else
|
|
||||||
#define PTRDIFF_MIN _I32_MIN
|
|
||||||
#define PTRDIFF_MAX _I32_MAX
|
|
||||||
#endif /* _WIN64 */
|
|
||||||
|
|
||||||
#define SIG_ATOMIC_MIN INT_MIN
|
|
||||||
#define SIG_ATOMIC_MAX INT_MAX
|
|
||||||
|
|
||||||
#ifndef SIZE_MAX
|
|
||||||
#if defined(_WIN64)
|
|
||||||
#define SIZE_MAX _UI64_MAX
|
|
||||||
#else
|
|
||||||
#define SIZE_MAX _UI32_MAX
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h> */
|
|
||||||
#ifndef WCHAR_MIN
|
|
||||||
#define WCHAR_MIN 0
|
|
||||||
#endif /* WCHAR_MIN */
|
|
||||||
|
|
||||||
#ifndef WCHAR_MAX
|
|
||||||
#define WCHAR_MAX _UI16_MAX
|
|
||||||
#endif /* WCHAR_MAX */
|
|
||||||
|
|
||||||
#define WINT_MIN 0
|
|
||||||
#define WINT_MAX _UI16_MAX
|
|
||||||
#endif /* __STDC_LIMIT_MACROS */
|
|
||||||
|
|
||||||
|
|
||||||
/* 7.18.4 Limits of other integer types */
|
|
||||||
|
|
||||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) /* See footnote 224 at page 260 */
|
|
||||||
|
|
||||||
/* 7.18.4.1 Macros for minimum-width integer constants */
|
|
||||||
|
|
||||||
#define INT8_C(val) val##i8
|
|
||||||
#define INT16_C(val) val##i16
|
|
||||||
#define INT32_C(val) val##i32
|
|
||||||
#define INT64_C(val) val##i64
|
|
||||||
|
|
||||||
#define UINT8_C(val) val##ui8
|
|
||||||
#define UINT16_C(val) val##ui16
|
|
||||||
#define UINT32_C(val) val##ui32
|
|
||||||
#define UINT64_C(val) val##ui64
|
|
||||||
|
|
||||||
/* 7.18.4.2 Macros for greatest-width integer constants */
|
|
||||||
#define INTMAX_C INT64_C
|
|
||||||
#define UINTMAX_C UINT64_C
|
|
||||||
|
|
||||||
#endif /* __STDC_CONSTANT_MACROS */
|
|
||||||
|
|
||||||
#endif /* MSC_STDINT_H */
|
|
12
base/os.h
12
base/os.h
@ -2,19 +2,12 @@
|
|||||||
#ifndef OS_H
|
#ifndef OS_H
|
||||||
#define OS_H
|
#define OS_H
|
||||||
|
|
||||||
/* Python versions under 2.5 don't support this macro, but it's not
|
|
||||||
* terribly difficult to replicate: */
|
|
||||||
#ifndef PyModule_AddIntMacro
|
|
||||||
#define PyModule_AddIntMacro(module, macro) \
|
|
||||||
PyModule_AddIntConstant(module, #macro, macro)
|
|
||||||
#endif /* PyModule_AddIntMacro */
|
|
||||||
|
|
||||||
#if !defined(IS_MACOSX) && defined(__APPLE__) && defined(__MACH__)
|
#if !defined(IS_MACOSX) && defined(__APPLE__) && defined(__MACH__)
|
||||||
#define IS_MACOSX
|
#define IS_MACOSX
|
||||||
#endif /* IS_MACOSX */
|
#endif /* IS_MACOSX */
|
||||||
|
|
||||||
#if !defined(IS_WINDOWS) && (defined(WIN32) || defined(_WIN32) || \
|
#if !defined(IS_WINDOWS) && (defined(WIN32) || defined(_WIN32) || \
|
||||||
defined(__WIN32__) || defined(__WINDOWS__) || defined(__CYGWIN__))
|
defined(__WIN32__) || defined(__WINDOWS__) || defined(__CYGWIN__))
|
||||||
#define IS_WINDOWS
|
#define IS_WINDOWS
|
||||||
#endif /* IS_WINDOWS */
|
#endif /* IS_WINDOWS */
|
||||||
|
|
||||||
@ -30,8 +23,7 @@
|
|||||||
#error "Sorry, this platform isn't supported yet!"
|
#error "Sorry, this platform isn't supported yet!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Interval to align by for large buffers (e.g. bitmaps). */
|
/* Interval to align by for large buffers (e.g. bitmaps). Must be a power of 2. */
|
||||||
/* Must be a power of 2. */
|
|
||||||
#ifndef BYTE_ALIGN
|
#ifndef BYTE_ALIGN
|
||||||
#define BYTE_ALIGN 4 /* Bytes to align pixel buffers to. */
|
#define BYTE_ALIGN 4 /* Bytes to align pixel buffers to. */
|
||||||
/* #include <stddef.h> */
|
/* #include <stddef.h> */
|
||||||
|
@ -22,13 +22,12 @@
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND GetHwndByPId(DWORD dwProcessId) {
|
HWND GetHwndByPid(DWORD dwProcessId) {
|
||||||
WNDINFO info = {0};
|
WNDINFO info = {0};
|
||||||
info.hWnd = NULL;
|
info.hWnd = NULL;
|
||||||
info.dwPid = dwProcessId;
|
info.dwPid = dwProcessId;
|
||||||
EnumWindows(EnumWindowsProc, (LPARAM)&info);
|
EnumWindows(EnumWindowsProc, (LPARAM)&info);
|
||||||
// printf("%d\n", info.hWnd);
|
|
||||||
return info.hWnd;
|
return info.hWnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
52
base/rgb.h
52
base/rgb.h
@ -5,21 +5,7 @@
|
|||||||
#include <stdlib.h> /* For abs() */
|
#include <stdlib.h> /* For abs() */
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "inline_keywords.h" /* For H_INLINE */
|
#include "inline_keywords.h" /* For H_INLINE */
|
||||||
// #include <stdint.h>
|
#include <stdint.h>
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#include "ms_stdint.h"
|
|
||||||
#else
|
|
||||||
#include <stdint.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* RGB colors in MMBitmaps are stored as BGR for convenience in converting
|
|
||||||
* to/from certain formats (mainly OpenGL).
|
|
||||||
*
|
|
||||||
* It is best not to rely on the order (simply use rgb.{blue,green,red} to
|
|
||||||
* access values), but some situations (e.g., glReadPixels) require one to
|
|
||||||
* do so. In that case, check to make sure to use MMRGB_IS_BGR for future
|
|
||||||
* compatibility. */
|
|
||||||
|
|
||||||
/* #define MMRGB_IS_BGR (offsetof(MMRGBColor, red) > offsetof(MMRGBColor, blue)) */
|
/* #define MMRGB_IS_BGR (offsetof(MMRGBColor, red) > offsetof(MMRGBColor, blue)) */
|
||||||
#define MMRGB_IS_BGR 1
|
#define MMRGB_IS_BGR 1
|
||||||
@ -29,25 +15,19 @@ struct _MMRGBColor {
|
|||||||
uint8_t green;
|
uint8_t green;
|
||||||
uint8_t red;
|
uint8_t red;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _MMRGBColor MMRGBColor;
|
typedef struct _MMRGBColor MMRGBColor;
|
||||||
|
|
||||||
/* MMRGBHex is a hexadecimal color value, akin to HTML's, in the form 0xRRGGBB
|
/* MMRGBHex is a hexadecimal color value*/
|
||||||
* where RR is the red value expressed as hexadecimal, GG is the green value,
|
|
||||||
* and BB is the blue value. */
|
|
||||||
typedef uint32_t MMRGBHex;
|
typedef uint32_t MMRGBHex;
|
||||||
|
|
||||||
#define MMRGBHEX_MIN 0x000000
|
#define MMRGBHEX_MIN 0x000000
|
||||||
#define MMRGBHEX_MAX 0xFFFFFF
|
#define MMRGBHEX_MAX 0xFFFFFF
|
||||||
|
|
||||||
/* Converts rgb color to hexadecimal value.
|
/* Converts rgb color to hexadecimal value. */
|
||||||
* |red|, |green|, and |blue| should each be of the type |uint8_t|, where the
|
|
||||||
* range is 0 - 255. */
|
|
||||||
#define RGB_TO_HEX(red, green, blue) (((red) << 16) | ((green) << 8) | (blue))
|
#define RGB_TO_HEX(red, green, blue) (((red) << 16) | ((green) << 8) | (blue))
|
||||||
|
|
||||||
/* Convenience wrapper for MMRGBColors. */
|
/* Convenience wrapper for MMRGBColors. */
|
||||||
H_INLINE MMRGBHex hexFromMMRGB(MMRGBColor rgb)
|
H_INLINE MMRGBHex hexFromMMRGB(MMRGBColor rgb) {
|
||||||
{
|
|
||||||
return RGB_TO_HEX(rgb.red, rgb.green, rgb.blue);
|
return RGB_TO_HEX(rgb.red, rgb.green, rgb.blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,8 +36,7 @@ H_INLINE MMRGBHex hexFromMMRGB(MMRGBColor rgb)
|
|||||||
#define BLUE_FROM_HEX(hex) (hex & 0xFF)
|
#define BLUE_FROM_HEX(hex) (hex & 0xFF)
|
||||||
|
|
||||||
/* Converts hexadecimal color to MMRGBColor. */
|
/* Converts hexadecimal color to MMRGBColor. */
|
||||||
H_INLINE MMRGBColor MMRGBFromHex(MMRGBHex hex)
|
H_INLINE MMRGBColor MMRGBFromHex(MMRGBHex hex) {
|
||||||
{
|
|
||||||
MMRGBColor color;
|
MMRGBColor color;
|
||||||
color.red = RED_FROM_HEX(hex);
|
color.red = RED_FROM_HEX(hex);
|
||||||
color.green = GREEN_FROM_HEX(hex);
|
color.green = GREEN_FROM_HEX(hex);
|
||||||
@ -70,12 +49,8 @@ H_INLINE MMRGBColor MMRGBFromHex(MMRGBHex hex)
|
|||||||
(c1).blue == (c2).blue && \
|
(c1).blue == (c2).blue && \
|
||||||
(c1).green == (c2).green)
|
(c1).green == (c2).green)
|
||||||
|
|
||||||
/* Returns whether two colors are similar within the given range, |tolerance|.
|
/* Returns whether two colors are similar within the given range, |tolerance|.*/
|
||||||
* Tolerance can be in the range 0.0f - 1.0f, where 0 denotes the exact
|
H_INLINE int MMRGBColorSimilarToColor(MMRGBColor c1, MMRGBColor c2, float tolerance) {
|
||||||
* color and 1 denotes any color. */
|
|
||||||
H_INLINE int MMRGBColorSimilarToColor(MMRGBColor c1, MMRGBColor c2,
|
|
||||||
float tolerance)
|
|
||||||
{
|
|
||||||
/* Speedy case */
|
/* Speedy case */
|
||||||
if (tolerance <= 0.0f) {
|
if (tolerance <= 0.0f) {
|
||||||
return MMRGBColorEqualToColor(c1, c2);
|
return MMRGBColorEqualToColor(c1, c2);
|
||||||
@ -83,27 +58,20 @@ H_INLINE int MMRGBColorSimilarToColor(MMRGBColor c1, MMRGBColor c2,
|
|||||||
uint8_t d1 = c1.red - c2.red;
|
uint8_t d1 = c1.red - c2.red;
|
||||||
uint8_t d2 = c1.green - c2.green;
|
uint8_t d2 = c1.green - c2.green;
|
||||||
uint8_t d3 = c1.blue - c2.blue;
|
uint8_t d3 = c1.blue - c2.blue;
|
||||||
return sqrt((double)(d1 * d1) +
|
return sqrt((double)(d1 * d1) + (d2 * d2) +
|
||||||
(d2 * d2) +
|
|
||||||
(d3 * d3)) <= (tolerance * 442.0f);
|
(d3 * d3)) <= (tolerance * 442.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Identical to MMRGBColorSimilarToColor, only for hex values. */
|
/* Identical to MMRGBColorSimilarToColor, only for hex values. */
|
||||||
H_INLINE int MMRGBHexSimilarToColor(MMRGBHex h1, MMRGBHex h2, float tolerance)
|
H_INLINE int MMRGBHexSimilarToColor(MMRGBHex h1, MMRGBHex h2, float tolerance) {
|
||||||
{
|
|
||||||
if (tolerance <= 0.0f) {
|
if (tolerance <= 0.0f) {
|
||||||
return h1 == h2;
|
return h1 == h2;
|
||||||
} else {
|
} else {
|
||||||
// uint8_t d1 = RED_FROM_HEX(h1) - RED_FROM_HEX(h2);
|
|
||||||
// uint8_t d2 = GREEN_FROM_HEX(h1) - GREEN_FROM_HEX(h2);
|
|
||||||
// uint8_t d3 = BLUE_FROM_HEX(h1) - BLUE_FROM_HEX(h2);
|
|
||||||
int d1 = RED_FROM_HEX(h1) - RED_FROM_HEX(h2);
|
int d1 = RED_FROM_HEX(h1) - RED_FROM_HEX(h2);
|
||||||
int d2 = GREEN_FROM_HEX(h1) - GREEN_FROM_HEX(h2);
|
int d2 = GREEN_FROM_HEX(h1) - GREEN_FROM_HEX(h2);
|
||||||
int d3 = BLUE_FROM_HEX(h1) - BLUE_FROM_HEX(h2);
|
int d3 = BLUE_FROM_HEX(h1) - BLUE_FROM_HEX(h2);
|
||||||
return sqrt((double)(d1 * d1) +
|
return sqrt((double)(d1 * d1) + (d2 * d2) +
|
||||||
(d2 * d2) +
|
|
||||||
(d3 * d3)) <= (tolerance * 442.0f);
|
(d3 * d3)) <= (tolerance * 442.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
77
base/types.h
77
base/types.h
@ -6,9 +6,9 @@
|
|||||||
#include "inline_keywords.h" /* For H_INLINE */
|
#include "inline_keywords.h" /* For H_INLINE */
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/* Some generic, cross-platform types. */
|
/* Some generic, cross-platform types. */
|
||||||
|
|
||||||
#ifdef RobotGo_64
|
#ifdef RobotGo_64
|
||||||
typedef int64_t intptr;
|
typedef int64_t intptr;
|
||||||
typedef uint64_t uintptr;
|
typedef uint64_t uintptr;
|
||||||
@ -17,113 +17,52 @@
|
|||||||
typedef uint32_t uintptr; // Unsigned pointer integer
|
typedef uint32_t uintptr; // Unsigned pointer integer
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct _MMPoint {
|
|
||||||
size_t x;
|
|
||||||
size_t y;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _MMPoint MMPoint;
|
|
||||||
|
|
||||||
struct _MMPointInt32 {
|
struct _MMPointInt32 {
|
||||||
int32_t x;
|
int32_t x;
|
||||||
int32_t y;
|
int32_t y;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _MMPointInt32 MMPointInt32;
|
typedef struct _MMPointInt32 MMPointInt32;
|
||||||
|
|
||||||
struct _MMSize {
|
|
||||||
size_t width;
|
|
||||||
size_t height;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _MMSize MMSize;
|
|
||||||
|
|
||||||
struct _MMSizeInt32 {
|
struct _MMSizeInt32 {
|
||||||
int32_t w;
|
int32_t w;
|
||||||
int32_t h;
|
int32_t h;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _MMSizeInt32 MMSizeInt32;
|
typedef struct _MMSizeInt32 MMSizeInt32;
|
||||||
|
|
||||||
|
|
||||||
struct _MMRect {
|
|
||||||
MMPoint origin;
|
|
||||||
MMSize size;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _MMRect MMRect;
|
|
||||||
|
|
||||||
struct _MMRectInt32 {
|
struct _MMRectInt32 {
|
||||||
MMPointInt32 origin;
|
MMPointInt32 origin;
|
||||||
MMSizeInt32 size;
|
MMSizeInt32 size;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _MMRectInt32 MMRectInt32;
|
typedef struct _MMRectInt32 MMRectInt32;
|
||||||
|
|
||||||
H_INLINE MMPoint MMPointMake(size_t x, size_t y)
|
H_INLINE MMPointInt32 MMPointInt32Make(int32_t x, int32_t y) {
|
||||||
{
|
|
||||||
MMPoint point;
|
|
||||||
point.x = x;
|
|
||||||
point.y = y;
|
|
||||||
return point;
|
|
||||||
}
|
|
||||||
|
|
||||||
H_INLINE MMPointInt32 MMPointInt32Make(int32_t x, int32_t y)
|
|
||||||
{
|
|
||||||
MMPointInt32 point;
|
MMPointInt32 point;
|
||||||
point.x = x;
|
point.x = x;
|
||||||
point.y = y;
|
point.y = y;
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
H_INLINE MMSize MMSizeMake(size_t width, size_t height)
|
H_INLINE MMSizeInt32 MMSizeInt32Make(int32_t w, int32_t h) {
|
||||||
{
|
|
||||||
MMSize size;
|
|
||||||
size.width = width;
|
|
||||||
size.height = height;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
H_INLINE MMSizeInt32 MMSizeInt32Make(int32_t w, int32_t h)
|
|
||||||
{
|
|
||||||
MMSizeInt32 size;
|
MMSizeInt32 size;
|
||||||
size.w = w;
|
size.w = w;
|
||||||
size.h = h;
|
size.h = h;
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
H_INLINE MMRect MMRectMake(size_t x, size_t y, size_t width, size_t height)
|
H_INLINE MMRectInt32 MMRectInt32Make(int32_t x, int32_t y, int32_t w, int32_t h) {
|
||||||
{
|
|
||||||
MMRect rect;
|
|
||||||
rect.origin = MMPointMake(x, y);
|
|
||||||
rect.size = MMSizeMake(width, height);
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
H_INLINE MMRectInt32 MMRectInt32Make(int32_t x, int32_t y, int32_t w, int32_t h)
|
|
||||||
{
|
|
||||||
MMRectInt32 rect;
|
MMRectInt32 rect;
|
||||||
rect.origin = MMPointInt32Make(x, y);
|
rect.origin = MMPointInt32Make(x, y);
|
||||||
rect.size = MMSizeInt32Make(w, h);
|
rect.size = MMSizeInt32Make(w, h);
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
#define MMPointZero MMPointInt32Make(0, 0)
|
||||||
#define MMPointZero MMPointMake(0, 0)
|
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
|
#define CGPointFromMMPointInt32(p) CGPointMake((CGFloat)(p).x, (CGFloat)(p).y)
|
||||||
#define CGPointFromMMPoint(p) CGPointMake((CGFloat)(p).x, (CGFloat)(p).y)
|
#define MMPointInt32FromCGPoint(p) MMPointInt32Make((int32_t)(p).x, (int32_t)(p).y)
|
||||||
#define MMPointFromCGPoint(p) MMPointMake((size_t)(p).x, (size_t)(p).y)
|
|
||||||
|
|
||||||
#define CGPointFromMMPointInt32(p) CGPointMake((CGFloat)(p).x, (CGFloat)(p).y)
|
|
||||||
#define MMPointInt32FromCGPoint(p) MMPointInt32Make((int32_t)(p).x, (int32_t)(p).y)
|
|
||||||
|
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
|
#define MMPointInt32FromPOINT(p) MMPointInt32Make((int32_t)p.x, (int32_t)p.y)
|
||||||
#define MMPointFromPOINT(p) MMPointMake((size_t)p.x, (size_t)p.y)
|
|
||||||
#define MMPointInt32FromPOINT(p) MMPointInt32Make((int32_t)p.x, (int32_t)p.y)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* TYPES_H */
|
#endif /* TYPES_H */
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef XDISPLAY_H
|
|
||||||
#define XDISPLAY_H
|
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
|
|
||||||
/* Returns the main display, closed either on exit or when closeMainDisplay()
|
|
||||||
* is invoked. This removes a bit of the overhead of calling XOpenDisplay() &
|
|
||||||
* XCloseDisplay() everytime the main display needs to be used.
|
|
||||||
*
|
|
||||||
* Note that this is almost certainly not thread safe. */
|
|
||||||
Display *XGetMainDisplay(void);
|
|
||||||
|
|
||||||
/* Closes the main display if it is open, or does nothing if not. */
|
|
||||||
void XCloseMainDisplay(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char *getXDisplay(void);
|
|
||||||
void setXDisplay(char *name);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* XDISPLAY_H */
|
|
@ -1,6 +1,6 @@
|
|||||||
#include "xdisplay.h"
|
|
||||||
#include <stdio.h> /* For fputs() */
|
#include <stdio.h> /* For fputs() */
|
||||||
#include <stdlib.h> /* For atexit() */
|
#include <stdlib.h> /* For atexit() */
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
static Display *mainDisplay = NULL;
|
static Display *mainDisplay = NULL;
|
||||||
static int registered = 0;
|
static int registered = 0;
|
||||||
@ -8,6 +8,13 @@ static int registered = 0;
|
|||||||
static char *displayName = NULL;
|
static char *displayName = NULL;
|
||||||
static int hasDisplayNameChanged = 0;
|
static int hasDisplayNameChanged = 0;
|
||||||
|
|
||||||
|
void XCloseMainDisplay(void) {
|
||||||
|
if (mainDisplay != NULL) {
|
||||||
|
XCloseDisplay(mainDisplay);
|
||||||
|
mainDisplay = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Display *XGetMainDisplay(void) {
|
Display *XGetMainDisplay(void) {
|
||||||
/* Close the display if displayName has changed */
|
/* Close the display if displayName has changed */
|
||||||
if (hasDisplayNameChanged) {
|
if (hasDisplayNameChanged) {
|
||||||
@ -40,13 +47,6 @@ Display *XGetMainDisplay(void) {
|
|||||||
return mainDisplay;
|
return mainDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XCloseMainDisplay(void) {
|
|
||||||
if (mainDisplay != NULL) {
|
|
||||||
XCloseDisplay(mainDisplay);
|
|
||||||
mainDisplay = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setXDisplay(char *name) {
|
void setXDisplay(char *name) {
|
||||||
displayName = strdup(name);
|
displayName = strdup(name);
|
||||||
hasDisplayNameChanged = 1;
|
hasDisplayNameChanged = 1;
|
||||||
@ -55,4 +55,3 @@ void setXDisplay(char *name) {
|
|||||||
char *getXDisplay(void) {
|
char *getXDisplay(void) {
|
||||||
return displayName;
|
return displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Package clipboard read/write on clipboard
|
Package clipboard read/write on clipboard
|
||||||
*/
|
*/
|
||||||
package clipboard
|
package clipboard
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/go-vgo/robotgo/clipboard"
|
"github.com/go-vgo/robotgo/clipboard"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
out, err := ioutil.ReadAll(os.Stdin)
|
out, err := io.ReadAll(os.Stdin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
119
doc.go
Normal file
119
doc.go
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
/*
|
||||||
|
Keys are supported:
|
||||||
|
"A-Z a-z 0-9"
|
||||||
|
|
||||||
|
"backspace"
|
||||||
|
"delete"
|
||||||
|
"enter"
|
||||||
|
"tab"
|
||||||
|
"esc"
|
||||||
|
"escape"
|
||||||
|
"up" Up arrow key
|
||||||
|
"down" Down arrow key
|
||||||
|
"right" Right arrow key
|
||||||
|
"left" Left arrow key
|
||||||
|
"home"
|
||||||
|
"end"
|
||||||
|
"pageup"
|
||||||
|
"pagedown"
|
||||||
|
|
||||||
|
"f1"
|
||||||
|
"f2"
|
||||||
|
"f3"
|
||||||
|
"f4"
|
||||||
|
"f5"
|
||||||
|
"f6"
|
||||||
|
"f7"
|
||||||
|
"f8"
|
||||||
|
"f9"
|
||||||
|
"f10"
|
||||||
|
"f11"
|
||||||
|
"f12"
|
||||||
|
"f13"
|
||||||
|
"f14"
|
||||||
|
"f15"
|
||||||
|
"f16"
|
||||||
|
"f17"
|
||||||
|
"f18"
|
||||||
|
"f19"
|
||||||
|
"f20"
|
||||||
|
"f21"
|
||||||
|
"f22"
|
||||||
|
"f23"
|
||||||
|
"f24"
|
||||||
|
|
||||||
|
"cmd" this is the "win" key for windows
|
||||||
|
"lcmd" left command
|
||||||
|
"rcmd" right command
|
||||||
|
// "command"
|
||||||
|
"alt"
|
||||||
|
"lalt" left alt
|
||||||
|
"ralt" right alt
|
||||||
|
"ctrl"
|
||||||
|
"lctrl" left ctrl
|
||||||
|
"rctrl" right ctrl
|
||||||
|
"control"
|
||||||
|
"shift"
|
||||||
|
"lshift" left shift
|
||||||
|
"rshift" right shift
|
||||||
|
// "right_shift"
|
||||||
|
"capslock"
|
||||||
|
"space"
|
||||||
|
"print"
|
||||||
|
"printscreen" // No Mac support
|
||||||
|
"insert"
|
||||||
|
"menu" Windows only
|
||||||
|
|
||||||
|
"audio_mute" Mute the volume
|
||||||
|
"audio_vol_down" Lower the volume
|
||||||
|
"audio_vol_up" Increase the volume
|
||||||
|
"audio_play"
|
||||||
|
"audio_stop"
|
||||||
|
"audio_pause"
|
||||||
|
"audio_prev" Previous Track
|
||||||
|
"audio_next" Next Track
|
||||||
|
"audio_rewind" Linux only
|
||||||
|
"audio_forward" Linux only
|
||||||
|
"audio_repeat" Linux only
|
||||||
|
"audio_random" Linux only
|
||||||
|
|
||||||
|
|
||||||
|
"num0"
|
||||||
|
"num1"
|
||||||
|
"num2"
|
||||||
|
"num3"
|
||||||
|
"num4"
|
||||||
|
"num5"
|
||||||
|
"num6"
|
||||||
|
"num7"
|
||||||
|
"num8"
|
||||||
|
"num9"
|
||||||
|
"num_lock"
|
||||||
|
|
||||||
|
"num."
|
||||||
|
"num+"
|
||||||
|
"num-"
|
||||||
|
"num*"
|
||||||
|
"num/"
|
||||||
|
"num_clear"
|
||||||
|
"num_enter"
|
||||||
|
"num_equal"
|
||||||
|
|
||||||
|
"lights_mon_up" Turn up monitor brightness No Windows support
|
||||||
|
"lights_mon_down" Turn down monitor brightness No Windows support
|
||||||
|
"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
|
||||||
|
*/
|
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
|
# Keys
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
@ -118,4 +140,4 @@
|
|||||||
"lights_kbd_toggle" Toggle keyboard backlight on/off No Windows support
|
"lights_kbd_toggle" Toggle keyboard backlight on/off No Windows support
|
||||||
"lights_kbd_up" Turn up keyboard backlight brightness 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
|
"lights_kbd_down" Turn down keyboard backlight brightness No Windows support
|
||||||
```
|
```
|
||||||
|
@ -68,7 +68,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
x, y := robotgo.GetMousePos()
|
x, y := robotgo.Location()
|
||||||
fmt.Println("pos:", x, y)
|
fmt.Println("pos:", x, y)
|
||||||
color := robotgo.GetPixelColor(100, 200)
|
color := robotgo.GetPixelColor(100, 200)
|
||||||
fmt.Println("color----", color)
|
fmt.Println("color----", color)
|
||||||
|
@ -18,26 +18,29 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func typeStr() {
|
func typeStr() {
|
||||||
// importing "Hello World"
|
// typing "Hello World"
|
||||||
robotgo.TypeStr("Hello World!", 1.0)
|
robotgo.TypeStr("Hello World!", 0, 1)
|
||||||
robotgo.KeySleep = 100
|
robotgo.KeySleep = 100
|
||||||
robotgo.TypeStr("だんしゃり")
|
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.Sleep(1)
|
||||||
robotgo.TypeStr("So, hi, bye!")
|
|
||||||
|
robotgo.TypeStr("Hi, Seattle space needle, Golden gate bridge, One world trade center.")
|
||||||
robotgo.MilliSleep(100)
|
robotgo.MilliSleep(100)
|
||||||
|
|
||||||
ustr := uint32(robotgo.CharCodeAt("So, hi, bye!", 0))
|
ustr := uint32(robotgo.CharCodeAt("So, hi, bye!", 0))
|
||||||
robotgo.UnicodeType(ustr)
|
robotgo.UnicodeType(ustr)
|
||||||
|
|
||||||
robotgo.PasteStr("paste string")
|
err := robotgo.PasteStr("paste string")
|
||||||
|
fmt.Println("PasteStr: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func keyTap() {
|
func keyTap() {
|
||||||
// press "enter"
|
// press "enter"
|
||||||
robotgo.KeyTap("enter")
|
robotgo.KeyTap("enter")
|
||||||
|
robotgo.KeyTap(robotgo.Enter)
|
||||||
robotgo.KeySleep = 200
|
robotgo.KeySleep = 200
|
||||||
robotgo.KeyTap("a")
|
robotgo.KeyTap("a")
|
||||||
robotgo.MilliSleep(100)
|
robotgo.MilliSleep(100)
|
||||||
@ -45,19 +48,19 @@ func keyTap() {
|
|||||||
|
|
||||||
// hide window
|
// hide window
|
||||||
err := robotgo.KeyTap("h", "cmd")
|
err := robotgo.KeyTap("h", "cmd")
|
||||||
if err != "" {
|
if err != nil {
|
||||||
fmt.Println("robotgo.KeyTap run error is: ", err)
|
fmt.Println("robotgo.KeyTap run error is: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
robotgo.KeyTap("h", "cmd", 12)
|
robotgo.KeyTap("h", "cmd")
|
||||||
|
|
||||||
// press "i", "alt", "command" Key combination
|
// press "i", "alt", "command" Key combination
|
||||||
robotgo.KeyTap("i", "alt", "command")
|
robotgo.KeyTap(robotgo.KeyI, robotgo.Alt, robotgo.Cmd)
|
||||||
robotgo.KeyTap("i", "alt", "cmd", 11)
|
robotgo.KeyTap("i", "alt", "cmd")
|
||||||
|
|
||||||
arr := []string{"alt", "cmd"}
|
arr := []string{"alt", "cmd"}
|
||||||
robotgo.KeyTap("i", arr)
|
robotgo.KeyTap("i", arr)
|
||||||
robotgo.KeyTap("i", arr, 12)
|
robotgo.KeyTap("i", arr)
|
||||||
|
|
||||||
robotgo.KeyTap("i", "cmd", " alt", "shift")
|
robotgo.KeyTap("i", "cmd", " alt", "shift")
|
||||||
|
|
||||||
@ -71,9 +74,17 @@ func keyTap() {
|
|||||||
robotgo.KeyTap("a", "control")
|
robotgo.KeyTap("a", "control")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func special() {
|
||||||
|
robotgo.TypeStr("{}")
|
||||||
|
robotgo.KeyTap("[", "]")
|
||||||
|
|
||||||
|
robotgo.KeyToggle("(")
|
||||||
|
robotgo.KeyToggle("(", "up")
|
||||||
|
}
|
||||||
|
|
||||||
func keyToggle() {
|
func keyToggle() {
|
||||||
// robotgo.KeySleep = 150
|
// robotgo.KeySleep = 150
|
||||||
robotgo.KeyToggle("a", "down")
|
robotgo.KeyToggle(robotgo.KeyA)
|
||||||
robotgo.KeyToggle("a", "down", "alt")
|
robotgo.KeyToggle("a", "down", "alt")
|
||||||
robotgo.Sleep(1)
|
robotgo.Sleep(1)
|
||||||
|
|
||||||
@ -81,8 +92,8 @@ func keyToggle() {
|
|||||||
robotgo.MilliSleep(100)
|
robotgo.MilliSleep(100)
|
||||||
robotgo.KeyToggle("q", "up", "alt", "cmd", "shift")
|
robotgo.KeyToggle("q", "up", "alt", "cmd", "shift")
|
||||||
|
|
||||||
err := robotgo.KeyToggle("enter", "down")
|
err := robotgo.KeyToggle(robotgo.Enter)
|
||||||
if err != "" {
|
if err != nil {
|
||||||
fmt.Println("robotgo.KeyToggle run error is: ", err)
|
fmt.Println("robotgo.KeyToggle run error is: ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,6 +121,7 @@ func key() {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
typeStr()
|
typeStr()
|
||||||
|
special()
|
||||||
|
|
||||||
keyTap()
|
keyTap()
|
||||||
keyToggle()
|
keyToggle()
|
||||||
|
@ -25,9 +25,7 @@ func move() {
|
|||||||
// move the mouse to 100, 200
|
// move the mouse to 100, 200
|
||||||
robotgo.Move(100, 200)
|
robotgo.Move(100, 200)
|
||||||
|
|
||||||
robotgo.Drag(10, 10)
|
// drag mouse with smooth
|
||||||
robotgo.Drag(20, 20, "right")
|
|
||||||
//
|
|
||||||
robotgo.DragSmooth(10, 10)
|
robotgo.DragSmooth(10, 10)
|
||||||
robotgo.DragSmooth(100, 200, 1.0, 100.0)
|
robotgo.DragSmooth(100, 200, 1.0, 100.0)
|
||||||
|
|
||||||
@ -37,7 +35,7 @@ func move() {
|
|||||||
robotgo.MoveSmoothRelative(10, -100, 1.0, 30.0)
|
robotgo.MoveSmoothRelative(10, -100, 1.0, 30.0)
|
||||||
|
|
||||||
for i := 0; i < 1080; i += 1000 {
|
for i := 0; i < 1080; i += 1000 {
|
||||||
fmt.Println(i)
|
fmt.Println("i: ", i)
|
||||||
// MoveMouse(800, i)
|
// MoveMouse(800, i)
|
||||||
robotgo.Move(800, i)
|
robotgo.Move(800, i)
|
||||||
}
|
}
|
||||||
@ -57,7 +55,7 @@ func click() {
|
|||||||
|
|
||||||
func get() {
|
func get() {
|
||||||
// gets the mouse coordinates
|
// gets the mouse coordinates
|
||||||
x, y := robotgo.GetMousePos()
|
x, y := robotgo.Location()
|
||||||
fmt.Println("pos:", x, y)
|
fmt.Println("pos:", x, y)
|
||||||
if x == 456 && y == 586 {
|
if x == 456 && y == 586 {
|
||||||
fmt.Println("mouse...", "586")
|
fmt.Println("mouse...", "586")
|
||||||
@ -68,10 +66,15 @@ func get() {
|
|||||||
|
|
||||||
func toggleAndScroll() {
|
func toggleAndScroll() {
|
||||||
// scrolls the mouse either up
|
// scrolls the mouse either up
|
||||||
// robotgo.ScrollMouse(10, "up")
|
robotgo.ScrollDir(10, "up")
|
||||||
|
robotgo.ScrollDir(10, "right")
|
||||||
|
|
||||||
robotgo.Scroll(100, 10)
|
robotgo.Scroll(100, 10)
|
||||||
robotgo.Scroll(0, -10)
|
robotgo.Scroll(0, -10)
|
||||||
|
|
||||||
|
robotgo.Toggle("left")
|
||||||
|
robotgo.Toggle("left", "up")
|
||||||
|
|
||||||
// toggles the right mouse button
|
// toggles the right mouse button
|
||||||
robotgo.Toggle("right")
|
robotgo.Toggle("right")
|
||||||
robotgo.Toggle("right", "up")
|
robotgo.Toggle("right", "up")
|
||||||
|
@ -7,28 +7,43 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
//
|
|
||||||
// syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call()
|
// syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call()
|
||||||
|
|
||||||
width, height := robotgo.GetScaleSize()
|
width, height := robotgo.GetScaleSize()
|
||||||
fmt.Println("get scale screen size: ", width, height)
|
fmt.Println("get scale screen size: ", width, height)
|
||||||
|
|
||||||
bitmap := robotgo.CaptureScreen(0, 0, width, height)
|
bitmap := robotgo.CaptureScreen(0, 0, width, height)
|
||||||
// robotgo.SaveBitmap(bitmap, "test.png")
|
defer robotgo.FreeBitmap(bitmap)
|
||||||
|
// bitmap.Save(bitmap, "test.png")
|
||||||
robotgo.Save(robotgo.ToImage(bitmap), "test.png")
|
robotgo.Save(robotgo.ToImage(bitmap), "test.png")
|
||||||
|
|
||||||
sx := robotgo.ScaleX()
|
robotgo.Scale = true
|
||||||
s := robotgo.Scale()
|
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
|
robotx, roboty := 35*s/100, 25*s/100
|
||||||
fmt.Println("scale: ", sx, s, " pos: ", robotx, roboty)
|
fmt.Println("scale: ", sx, s, " pos: ", robotx, roboty)
|
||||||
|
|
||||||
mx, my := robotgo.GetMousePos()
|
mx, my := robotgo.Location()
|
||||||
sx, sy := mx*s/100, my*s/100
|
sx, sy := mx*s/100, my*s/100
|
||||||
|
|
||||||
rx, ry, rw, rh := sx, sy, robotx, roboty
|
rx, ry, rw, rh := sx, sy, robotx, roboty
|
||||||
// bit1 := robotgo.CaptureScreen(10, 20, robotw, roboth)
|
// bit1 := robotgo.CaptureScreen(10, 20, robotw, roboth)
|
||||||
bit1 := robotgo.CaptureScreen(rx, ry, rw, rh)
|
bit1 := robotgo.CaptureScreen(rx, ry, rw, rh)
|
||||||
// robotgo.SaveBitmap(bit1, "test2.png")
|
defer robotgo.FreeBitmap(bit1)
|
||||||
|
// bitmap.Save(bit1, "test2.png")
|
||||||
robotgo.Save(robotgo.ToImage(bit1), "test2.png")
|
robotgo.Save(robotgo.ToImage(bit1), "test2.png")
|
||||||
|
|
||||||
clo := robotgo.GetPixelColor(robotx, roboty)
|
clo := robotgo.GetPixelColor(robotx, roboty)
|
||||||
|
@ -12,6 +12,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/go-vgo/robotgo"
|
"github.com/go-vgo/robotgo"
|
||||||
// "go-vgo/robotgo"
|
// "go-vgo/robotgo"
|
||||||
@ -19,15 +20,39 @@ import (
|
|||||||
|
|
||||||
func bitmap() {
|
func bitmap() {
|
||||||
bit := robotgo.CaptureScreen()
|
bit := robotgo.CaptureScreen()
|
||||||
|
defer robotgo.FreeBitmap(bit)
|
||||||
fmt.Println("abitMap...", bit)
|
fmt.Println("abitMap...", bit)
|
||||||
|
|
||||||
gbit := robotgo.ToBitmap(bit)
|
gbit := robotgo.ToBitmap(bit)
|
||||||
fmt.Println("bitmap...", gbit.Width)
|
fmt.Println("bitmap...", gbit.Width)
|
||||||
|
|
||||||
gbitMap := robotgo.CaptureGo()
|
gbitMap := robotgo.CaptureGo()
|
||||||
fmt.Println("Go CaptureScreen...", gbitMap.Width)
|
fmt.Println("Go CaptureScreen...", gbitMap.Width)
|
||||||
// fmt.Println("...", gbitmap.Width, gbitmap.BytesPerPixel)
|
// fmt.Println("...", gbitmap.Width, gbitmap.BytesPerPixel)
|
||||||
|
robotgo.SaveCapture("saveCapture.png", 10, 20, 100, 100)
|
||||||
|
|
||||||
// robotgo.SaveCapture("saveCapture.png", 10, 20, 100, 100)
|
img, err := robotgo.CaptureImg()
|
||||||
|
fmt.Println("error: ", err)
|
||||||
|
robotgo.Save(img, "save.png")
|
||||||
|
|
||||||
|
num := robotgo.DisplaysNum()
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
robotgo.DisplayID = i
|
||||||
|
img1, _ := robotgo.CaptureImg()
|
||||||
|
path1 := "save_" + strconv.Itoa(i)
|
||||||
|
robotgo.Save(img1, path1+".png")
|
||||||
|
robotgo.SaveJpeg(img1, path1+".jpeg", 50)
|
||||||
|
|
||||||
|
img2, _ := robotgo.CaptureImg(10, 10, 20, 20)
|
||||||
|
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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func color() {
|
func color() {
|
||||||
@ -64,6 +89,12 @@ func screen() {
|
|||||||
// gets the screen width and height
|
// gets the screen width and height
|
||||||
sx, sy := robotgo.GetScreenSize()
|
sx, sy := robotgo.GetScreenSize()
|
||||||
fmt.Println("get screen size: ", sx, sy)
|
fmt.Println("get screen size: ", sx, sy)
|
||||||
|
for i := 0; i < robotgo.DisplaysNum(); i++ {
|
||||||
|
s1 := robotgo.ScaleF(i)
|
||||||
|
fmt.Println("ScaleF: ", s1)
|
||||||
|
}
|
||||||
|
sx, sy = robotgo.GetScaleSize()
|
||||||
|
fmt.Println("get screen scale size: ", sx, sy)
|
||||||
|
|
||||||
color()
|
color()
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ func alert() {
|
|||||||
|
|
||||||
func get() {
|
func get() {
|
||||||
// get the current process id
|
// get the current process id
|
||||||
pid := robotgo.GetPID()
|
pid := robotgo.GetPid()
|
||||||
fmt.Println("pid----", pid)
|
fmt.Println("pid----", pid)
|
||||||
|
|
||||||
// get current Window Active
|
// get current Window Active
|
||||||
@ -49,31 +49,45 @@ func get() {
|
|||||||
func findIds() {
|
func findIds() {
|
||||||
// find the process id by the process name
|
// find the process id by the process name
|
||||||
fpid, err := robotgo.FindIds("Google")
|
fpid, err := robotgo.FindIds("Google")
|
||||||
if err == nil {
|
if err != nil {
|
||||||
fmt.Println("pids...", fpid)
|
fmt.Println(err)
|
||||||
if len(fpid) > 0 {
|
return
|
||||||
robotgo.ActivePID(fpid[0])
|
}
|
||||||
|
|
||||||
tl := robotgo.GetTitle(fpid[0])
|
if len(fpid) > 0 {
|
||||||
fmt.Println("pid[0] title is: ", tl)
|
robotgo.KeyTap("a", fpid[0])
|
||||||
|
robotgo.TypeStr("Hi galaxy!", fpid[0])
|
||||||
|
|
||||||
x, y, w, h := robotgo.GetBounds(fpid[0])
|
robotgo.KeyToggle("a", fpid[0], "cmd")
|
||||||
fmt.Println("GetBounds is: ", x, y, w, h)
|
robotgo.KeyToggle("a", fpid[0], "cmd", "up")
|
||||||
|
}
|
||||||
|
|
||||||
// Windows
|
fmt.Println("pids...", fpid)
|
||||||
// hwnd := robotgo.FindWindow("google")
|
if len(fpid) > 0 {
|
||||||
// hwnd := robotgo.GetHWND()
|
err = robotgo.ActivePid(fpid[0])
|
||||||
robotgo.MinWindow(fpid[0])
|
if err != nil {
|
||||||
robotgo.MaxWindow(fpid[0])
|
fmt.Println(err)
|
||||||
robotgo.CloseWindow(fpid[0])
|
|
||||||
|
|
||||||
robotgo.Kill(fpid[0])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tl := robotgo.GetTitle(fpid[0])
|
||||||
|
fmt.Println("pid[0] title is: ", tl)
|
||||||
|
|
||||||
|
x, y, w, h := robotgo.GetBounds(fpid[0])
|
||||||
|
fmt.Println("GetBounds is: ", x, y, w, h)
|
||||||
|
|
||||||
|
// Windows
|
||||||
|
// hwnd := robotgo.FindWindow("google")
|
||||||
|
// hwnd := robotgo.GetHWND()
|
||||||
|
robotgo.MinWindow(fpid[0])
|
||||||
|
robotgo.MaxWindow(fpid[0])
|
||||||
|
robotgo.CloseWindow(fpid[0])
|
||||||
|
|
||||||
|
robotgo.Kill(fpid[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func active() {
|
func active() {
|
||||||
robotgo.ActivePID(100)
|
robotgo.ActivePid(100)
|
||||||
// robotgo.Sleep(2)
|
// robotgo.Sleep(2)
|
||||||
robotgo.ActiveName("code")
|
robotgo.ActiveName("code")
|
||||||
robotgo.Sleep(1)
|
robotgo.Sleep(1)
|
||||||
|
49
go.mod
49
go.mod
@ -1,33 +1,38 @@
|
|||||||
module github.com/go-vgo/robotgo
|
module github.com/go-vgo/robotgo
|
||||||
|
|
||||||
go 1.17
|
go 1.23.0
|
||||||
|
|
||||||
|
toolchain go1.23.6
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e
|
github.com/otiai10/gosseract/v2 v2.4.1
|
||||||
github.com/otiai10/gosseract v2.2.1+incompatible
|
|
||||||
// github.com/robotn/gohook v0.31.3
|
// github.com/robotn/gohook v0.31.3
|
||||||
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934
|
github.com/robotn/xgb v0.10.0
|
||||||
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770
|
github.com/robotn/xgbutil v0.10.0
|
||||||
github.com/vcaesar/gops v0.22.0
|
github.com/tailscale/win v0.0.0-20250213223159-5992cb43ca35
|
||||||
github.com/vcaesar/imgo v0.30.0
|
github.com/vcaesar/gops v0.41.0
|
||||||
github.com/vcaesar/keycode v0.10.0
|
github.com/vcaesar/imgo v0.41.0
|
||||||
github.com/vcaesar/tt v0.20.0
|
github.com/vcaesar/keycode v0.10.1
|
||||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
|
github.com/vcaesar/tt v0.20.1
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/dblohm7/wingoes v0.0.0-20240820181039-f2b84150679e // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/ebitengine/purego v0.8.3 // indirect
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
github.com/gen2brain/shm v0.1.1 // indirect
|
||||||
github.com/otiai10/mint v1.3.0 // indirect
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
github.com/shirou/gopsutil/v3 v3.21.12 // indirect
|
github.com/jezek/xgb v1.1.1 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.9 // indirect
|
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
|
||||||
github.com/tklauser/numcpus v0.3.0 // indirect
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
github.com/shirou/gopsutil/v4 v4.25.4 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
|
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // 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
|
// replace golang.org/x/sys => github.com/golang/sys v0.0.0-20190109145017-48ac38b7c8cb
|
||||||
|
124
go.sum
124
go.sum
@ -1,73 +1,71 @@
|
|||||||
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ=
|
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ=
|
||||||
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0=
|
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/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/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/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4=
|
||||||
github.com/otiai10/gosseract v2.2.1+incompatible h1:Ry5ltVdpdp4LAa2bMjsSJH34XHVOV7XMi41HtzL8X2I=
|
github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
|
||||||
github.com/otiai10/gosseract v2.2.1+incompatible/go.mod h1:XrzWItCzCpFRZ35n3YtVTgq5bLAhFIkascoRo8G32QE=
|
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc=
|
||||||
github.com/otiai10/mint v1.3.0 h1:Ady6MKVezQwHBkGzLFbrsywyp09Ah7rkmfjV3Bcr5uc=
|
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934 h1:2lhSR8N3T6I30q096DT7/5AKEIcf1vvnnWAmS0wfnNY=
|
|
||||||
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ=
|
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ=
|
||||||
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770 h1:2uX8QRLkkxn2EpAQ6I3KhA79BkdRZfvugJUzJadiJwk=
|
github.com/robotn/xgb v0.10.0 h1:O3kFbIwtwZ3pgLbp1h5slCQ4OpY8BdwugJLrUe6GPIM=
|
||||||
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770/go.mod h1:svkDXUDQjUiWzLrA0OZgHc4lbOts3C+uRfP6/yjwYnU=
|
github.com/robotn/xgb v0.10.0/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ=
|
||||||
github.com/shirou/gopsutil/v3 v3.21.12 h1:VoGxEW2hpmz0Vt3wUvHIl9fquzYLNpVpgNNB7pGJimA=
|
github.com/robotn/xgbutil v0.10.0 h1:gvf7mGQqCWQ68aHRtCxgdewRk+/KAJui6l3MJQQRCKw=
|
||||||
github.com/shirou/gopsutil/v3 v3.21.12/go.mod h1:BToYZVTlSVlfazpDDYFnsVZLaoRG+g8ufT6fPQLdJzA=
|
github.com/robotn/xgbutil v0.10.0/go.mod h1:svkDXUDQjUiWzLrA0OZgHc4lbOts3C+uRfP6/yjwYnU=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/shirou/gopsutil/v4 v4.25.4 h1:cdtFO363VEOOFrUCjZRh4XVJkb548lyF0q0uTeMqYPw=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
github.com/shirou/gopsutil/v4 v4.25.4/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
|
github.com/tailscale/win v0.0.0-20250213223159-5992cb43ca35 h1:wAZbkTZkqDzWsqxPh2qkBd3KvFU7tcxV0BP0Rnhkxog=
|
||||||
github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
|
github.com/tailscale/win v0.0.0-20250213223159-5992cb43ca35/go.mod h1:aMd4yDHLjbOuYP6fMxj1d9ACDQlSWwYztcpybGHCQc8=
|
||||||
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
|
github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA=
|
||||||
github.com/vcaesar/gops v0.22.0 h1:aWHWxY3fvUuaJGph+LegYUSEU/874WJT7MInd8OUmP0=
|
github.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk=
|
||||||
github.com/vcaesar/gops v0.22.0/go.mod h1:GFNGo9xpCfjcfd/Hovi9RSrpd4FdaQt8V92TzpU22w4=
|
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||||
github.com/vcaesar/imgo v0.30.0 h1:ODQVX0EFJEh+WkKahCBtE0SqcDCIjl/kjiOplR0Ouh8=
|
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||||
github.com/vcaesar/imgo v0.30.0/go.mod h1:8TGnt5hjaMgwDByvMFIzUDSh5uSea4n1tAbSvnhvA6U=
|
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||||
github.com/vcaesar/keycode v0.10.0 h1:Qx5QE8ZXHyRyjoA2QOxBp25OKMKB+zxMVqm0FWGV0d4=
|
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
||||||
github.com/vcaesar/keycode v0.10.0/go.mod h1:JNlY7xbKsh+LAGfY2j4M3znVrGEm5W1R8s/Uv6BJcfQ=
|
github.com/vcaesar/gops v0.41.0 h1:FG748Jyw3FOuZnbzSgB+CQSx2e5LbLCPWV2JU1brFdc=
|
||||||
github.com/vcaesar/tt v0.20.0 h1:9t2Ycb9RNHcP0WgQgIaRKJBB+FrRdejuaL6uWIHuoBA=
|
github.com/vcaesar/gops v0.41.0/go.mod h1:/3048L7Rj7QjQKTSB+kKc7hDm63YhTWy5QJ10TCP37A=
|
||||||
github.com/vcaesar/tt v0.20.0/go.mod h1:GHPxQYhn+7OgKakRusH7KJ0M5MhywoeLb8Fcffs/Gtg=
|
github.com/vcaesar/imgo v0.41.0 h1:kNLYGrThXhB9Dd6IwFmfPnxq9P6yat2g7dpPjr7OWO8=
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
github.com/vcaesar/imgo v0.41.0/go.mod h1:/LGOge8etlzaVu/7l+UfhJxR6QqaoX5yeuzGIMfWb4I=
|
||||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/vcaesar/keycode v0.10.1 h1:0DesGmMAPWpYTCYddOFiCMKCDKgNnwiQa2QXindVUHw=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
github.com/vcaesar/keycode v0.10.1/go.mod h1:JNlY7xbKsh+LAGfY2j4M3znVrGEm5W1R8s/Uv6BJcfQ=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
github.com/vcaesar/screenshot v0.11.1 h1:GgPuN89XC4Yh38dLx4quPlSo3YiWWhwIria/j3LtrqU=
|
||||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
github.com/vcaesar/screenshot v0.11.1/go.mod h1:gJNwHBiP1v1v7i8TQ4yV1XJtcyn2I/OJL7OziVQkwjs=
|
||||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
|
github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4=
|
||||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
github.com/vcaesar/tt v0.20.1/go.mod h1:cH2+AwGAJm19Wa6xvEa+0r+sXDJBT0QgNQey6mwqLeU=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||||
|
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
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=
|
|
||||||
|
14
img.go
14
img.go
@ -34,8 +34,8 @@ func Read(path string) (image.Image, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save create a image file with the image.Image
|
// Save create a image file with the image.Image
|
||||||
func Save(img image.Image, path string) error {
|
func Save(img image.Image, path string, quality ...int) error {
|
||||||
return imgo.Save(path, img)
|
return imgo.Save(path, img, quality...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveImg save the image by []byte
|
// SaveImg save the image by []byte
|
||||||
@ -49,13 +49,13 @@ func SavePng(img image.Image, path string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SaveJpeg save the image by image.Image
|
// SaveJpeg save the image by image.Image
|
||||||
func SaveJpeg(img image.Image, path string) error {
|
func SaveJpeg(img image.Image, path string, quality ...int) error {
|
||||||
return imgo.SaveToJpeg(path, img)
|
return imgo.SaveToJpeg(path, img, quality...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToByteImg convert image.Image to []byte
|
// ToByteImg convert image.Image to []byte
|
||||||
func ToByteImg(img image.Image, fm ...string) []byte {
|
func ToByteImg(img image.Image, fm ...string) []byte {
|
||||||
return imgo.ToByteImg(img, fm...)
|
return imgo.ToByte(img, fm...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToStringImg convert image.Image to string
|
// ToStringImg convert image.Image to string
|
||||||
@ -122,7 +122,7 @@ func ImgToBitmap(m image.Image) (bit Bitmap) {
|
|||||||
// ToUint8p convert the []uint8 to uint8 pointer
|
// ToUint8p convert the []uint8 to uint8 pointer
|
||||||
func ToUint8p(dst []uint8) *uint8 {
|
func ToUint8p(dst []uint8) *uint8 {
|
||||||
src := make([]uint8, len(dst)+10)
|
src := make([]uint8, len(dst)+10)
|
||||||
for i := 0; i < len(dst)-4; i += 4 {
|
for i := 0; i <= len(dst)-4; i += 4 {
|
||||||
src[i+3] = dst[i+3]
|
src[i+3] = dst[i+3]
|
||||||
src[i] = dst[i+2]
|
src[i] = dst[i+2]
|
||||||
src[i+1] = dst[i+1]
|
src[i+1] = dst[i+1]
|
||||||
@ -151,7 +151,7 @@ func val(p *uint8, n int) uint8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func copyToVUint8A(dst []uint8, src *uint8) {
|
func copyToVUint8A(dst []uint8, src *uint8) {
|
||||||
for i := 0; i < len(dst)-4; i += 4 {
|
for i := 0; i <= len(dst)-4; i += 4 {
|
||||||
dst[i] = val(src, i+2)
|
dst[i] = val(src, i+2)
|
||||||
dst[i+1] = val(src, i+1)
|
dst[i+1] = val(src, i+1)
|
||||||
dst[i+2] = val(src, i)
|
dst[i+2] = val(src, i)
|
||||||
|
742
key.go
Normal file
742
key.go
Normal file
@ -0,0 +1,742 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
/*
|
||||||
|
// #include "key/keycode.h"
|
||||||
|
#include "key/keypress_c.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math/rand"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/go-vgo/robotgo/clipboard"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defining a bunch of constants.
|
||||||
|
const (
|
||||||
|
// KeyA define key "a"
|
||||||
|
KeyA = "a"
|
||||||
|
KeyB = "b"
|
||||||
|
KeyC = "c"
|
||||||
|
KeyD = "d"
|
||||||
|
KeyE = "e"
|
||||||
|
KeyF = "f"
|
||||||
|
KeyG = "g"
|
||||||
|
KeyH = "h"
|
||||||
|
KeyI = "i"
|
||||||
|
KeyJ = "j"
|
||||||
|
KeyK = "k"
|
||||||
|
KeyL = "l"
|
||||||
|
KeyM = "m"
|
||||||
|
KeyN = "n"
|
||||||
|
KeyO = "o"
|
||||||
|
KeyP = "p"
|
||||||
|
KeyQ = "q"
|
||||||
|
KeyR = "r"
|
||||||
|
KeyS = "s"
|
||||||
|
KeyT = "t"
|
||||||
|
KeyU = "u"
|
||||||
|
KeyV = "v"
|
||||||
|
KeyW = "w"
|
||||||
|
KeyX = "x"
|
||||||
|
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"
|
||||||
|
Key3 = "3"
|
||||||
|
Key4 = "4"
|
||||||
|
Key5 = "5"
|
||||||
|
Key6 = "6"
|
||||||
|
Key7 = "7"
|
||||||
|
Key8 = "8"
|
||||||
|
Key9 = "9"
|
||||||
|
|
||||||
|
// Backspace backspace key string
|
||||||
|
Backspace = "backspace"
|
||||||
|
Delete = "delete"
|
||||||
|
Enter = "enter"
|
||||||
|
Tab = "tab"
|
||||||
|
Esc = "esc"
|
||||||
|
Escape = "escape"
|
||||||
|
Up = "up" // Up arrow key
|
||||||
|
Down = "down" // Down arrow key
|
||||||
|
Right = "right" // Right arrow key
|
||||||
|
Left = "left" // Left arrow key
|
||||||
|
Home = "home"
|
||||||
|
End = "end"
|
||||||
|
Pageup = "pageup"
|
||||||
|
Pagedown = "pagedown"
|
||||||
|
|
||||||
|
F1 = "f1"
|
||||||
|
F2 = "f2"
|
||||||
|
F3 = "f3"
|
||||||
|
F4 = "f4"
|
||||||
|
F5 = "f5"
|
||||||
|
F6 = "f6"
|
||||||
|
F7 = "f7"
|
||||||
|
F8 = "f8"
|
||||||
|
F9 = "f9"
|
||||||
|
F10 = "f10"
|
||||||
|
F11 = "f11"
|
||||||
|
F12 = "f12"
|
||||||
|
F13 = "f13"
|
||||||
|
F14 = "f14"
|
||||||
|
F15 = "f15"
|
||||||
|
F16 = "f16"
|
||||||
|
F17 = "f17"
|
||||||
|
F18 = "f18"
|
||||||
|
F19 = "f19"
|
||||||
|
F20 = "f20"
|
||||||
|
F21 = "f21"
|
||||||
|
F22 = "f22"
|
||||||
|
F23 = "f23"
|
||||||
|
F24 = "f24"
|
||||||
|
|
||||||
|
Cmd = "cmd" // is the "win" key for windows
|
||||||
|
Lcmd = "lcmd" // left command
|
||||||
|
Rcmd = "rcmd" // right command
|
||||||
|
// "command"
|
||||||
|
Alt = "alt"
|
||||||
|
Lalt = "lalt" // left alt
|
||||||
|
Ralt = "ralt" // right alt
|
||||||
|
Ctrl = "ctrl"
|
||||||
|
Lctrl = "lctrl" // left ctrl
|
||||||
|
Rctrl = "rctrl" // right ctrl
|
||||||
|
Control = "control"
|
||||||
|
Shift = "shift"
|
||||||
|
Lshift = "lshift" // left shift
|
||||||
|
Rshift = "rshift" // right shift
|
||||||
|
// "right_shift"
|
||||||
|
Capslock = "capslock"
|
||||||
|
Space = "space"
|
||||||
|
Print = "print"
|
||||||
|
Printscreen = "printscreen" // No Mac support
|
||||||
|
Insert = "insert"
|
||||||
|
Menu = "menu" // Windows only
|
||||||
|
|
||||||
|
AudioMute = "audio_mute" // Mute the volume
|
||||||
|
AudioVolDown = "audio_vol_down" // Lower the volume
|
||||||
|
AudioVolUp = "audio_vol_up" // Increase the volume
|
||||||
|
AudioPlay = "audio_play"
|
||||||
|
AudioStop = "audio_stop"
|
||||||
|
AudioPause = "audio_pause"
|
||||||
|
AudioPrev = "audio_prev" // Previous Track
|
||||||
|
AudioNext = "audio_next" // Next Track
|
||||||
|
AudioRewind = "audio_rewind" // Linux only
|
||||||
|
AudioForward = "audio_forward" // Linux only
|
||||||
|
AudioRepeat = "audio_repeat" // Linux only
|
||||||
|
AudioRandom = "audio_random" // Linux only
|
||||||
|
|
||||||
|
Num0 = "num0" // numpad 0
|
||||||
|
Num1 = "num1"
|
||||||
|
Num2 = "num2"
|
||||||
|
Num3 = "num3"
|
||||||
|
Num4 = "num4"
|
||||||
|
Num5 = "num5"
|
||||||
|
Num6 = "num6"
|
||||||
|
Num7 = "num7"
|
||||||
|
Num8 = "num8"
|
||||||
|
Num9 = "num9"
|
||||||
|
NumLock = "num_lock"
|
||||||
|
|
||||||
|
NumDecimal = "num."
|
||||||
|
NumPlus = "num+"
|
||||||
|
NumMinus = "num-"
|
||||||
|
NumMul = "num*"
|
||||||
|
NumDiv = "num/"
|
||||||
|
NumClear = "num_clear"
|
||||||
|
NumEnter = "num_enter"
|
||||||
|
NumEqual = "num_equal"
|
||||||
|
|
||||||
|
LightsMonUp = "lights_mon_up" // Turn up monitor brightness No Windows support
|
||||||
|
LightsMonDown = "lights_mon_down" // Turn down monitor brightness No Windows support
|
||||||
|
LightsKbdToggle = "lights_kbd_toggle" // Toggle keyboard backlight on/off No Windows support
|
||||||
|
LightsKbdUp = "lights_kbd_up" // Turn up keyboard backlight brightness No Windows support
|
||||||
|
LightsKbdDown = "lights_kbd_down"
|
||||||
|
)
|
||||||
|
|
||||||
|
// keyNames define a map of key names to MMKeyCode
|
||||||
|
var keyNames = map[string]C.MMKeyCode{
|
||||||
|
"backspace": C.K_BACKSPACE,
|
||||||
|
"delete": C.K_DELETE,
|
||||||
|
"enter": C.K_RETURN,
|
||||||
|
"tab": C.K_TAB,
|
||||||
|
"esc": C.K_ESCAPE,
|
||||||
|
"escape": C.K_ESCAPE,
|
||||||
|
"up": C.K_UP,
|
||||||
|
"down": C.K_DOWN,
|
||||||
|
"right": C.K_RIGHT,
|
||||||
|
"left": C.K_LEFT,
|
||||||
|
"home": C.K_HOME,
|
||||||
|
"end": C.K_END,
|
||||||
|
"pageup": C.K_PAGEUP,
|
||||||
|
"pagedown": C.K_PAGEDOWN,
|
||||||
|
//
|
||||||
|
"f1": C.K_F1,
|
||||||
|
"f2": C.K_F2,
|
||||||
|
"f3": C.K_F3,
|
||||||
|
"f4": C.K_F4,
|
||||||
|
"f5": C.K_F5,
|
||||||
|
"f6": C.K_F6,
|
||||||
|
"f7": C.K_F7,
|
||||||
|
"f8": C.K_F8,
|
||||||
|
"f9": C.K_F9,
|
||||||
|
"f10": C.K_F10,
|
||||||
|
"f11": C.K_F11,
|
||||||
|
"f12": C.K_F12,
|
||||||
|
"f13": C.K_F13,
|
||||||
|
"f14": C.K_F14,
|
||||||
|
"f15": C.K_F15,
|
||||||
|
"f16": C.K_F16,
|
||||||
|
"f17": C.K_F17,
|
||||||
|
"f18": C.K_F18,
|
||||||
|
"f19": C.K_F19,
|
||||||
|
"f20": C.K_F20,
|
||||||
|
"f21": C.K_F21,
|
||||||
|
"f22": C.K_F22,
|
||||||
|
"f23": C.K_F23,
|
||||||
|
"f24": C.K_F24,
|
||||||
|
//
|
||||||
|
"cmd": C.K_META,
|
||||||
|
"lcmd": C.K_LMETA,
|
||||||
|
"rcmd": C.K_RMETA,
|
||||||
|
"command": C.K_META,
|
||||||
|
"alt": C.K_ALT,
|
||||||
|
"lalt": C.K_LALT,
|
||||||
|
"ralt": C.K_RALT,
|
||||||
|
"ctrl": C.K_CONTROL,
|
||||||
|
"lctrl": C.K_LCONTROL,
|
||||||
|
"rctrl": C.K_RCONTROL,
|
||||||
|
"control": C.K_CONTROL,
|
||||||
|
"shift": C.K_SHIFT,
|
||||||
|
"lshift": C.K_LSHIFT,
|
||||||
|
"rshift": C.K_RSHIFT,
|
||||||
|
"right_shift": C.K_RSHIFT,
|
||||||
|
"capslock": C.K_CAPSLOCK,
|
||||||
|
"space": C.K_SPACE,
|
||||||
|
"print": C.K_PRINTSCREEN,
|
||||||
|
"printscreen": C.K_PRINTSCREEN,
|
||||||
|
"insert": C.K_INSERT,
|
||||||
|
"menu": C.K_MENU,
|
||||||
|
|
||||||
|
"audio_mute": C.K_AUDIO_VOLUME_MUTE,
|
||||||
|
"audio_vol_down": C.K_AUDIO_VOLUME_DOWN,
|
||||||
|
"audio_vol_up": C.K_AUDIO_VOLUME_UP,
|
||||||
|
"audio_play": C.K_AUDIO_PLAY,
|
||||||
|
"audio_stop": C.K_AUDIO_STOP,
|
||||||
|
"audio_pause": C.K_AUDIO_PAUSE,
|
||||||
|
"audio_prev": C.K_AUDIO_PREV,
|
||||||
|
"audio_next": C.K_AUDIO_NEXT,
|
||||||
|
"audio_rewind": C.K_AUDIO_REWIND,
|
||||||
|
"audio_forward": C.K_AUDIO_FORWARD,
|
||||||
|
"audio_repeat": C.K_AUDIO_REPEAT,
|
||||||
|
"audio_random": C.K_AUDIO_RANDOM,
|
||||||
|
|
||||||
|
"num0": C.K_NUMPAD_0,
|
||||||
|
"num1": C.K_NUMPAD_1,
|
||||||
|
"num2": C.K_NUMPAD_2,
|
||||||
|
"num3": C.K_NUMPAD_3,
|
||||||
|
"num4": C.K_NUMPAD_4,
|
||||||
|
"num5": C.K_NUMPAD_5,
|
||||||
|
"num6": C.K_NUMPAD_6,
|
||||||
|
"num7": C.K_NUMPAD_7,
|
||||||
|
"num8": C.K_NUMPAD_8,
|
||||||
|
"num9": C.K_NUMPAD_9,
|
||||||
|
"num_lock": C.K_NUMPAD_LOCK,
|
||||||
|
|
||||||
|
// todo: removed
|
||||||
|
"numpad_0": C.K_NUMPAD_0,
|
||||||
|
"numpad_1": C.K_NUMPAD_1,
|
||||||
|
"numpad_2": C.K_NUMPAD_2,
|
||||||
|
"numpad_3": C.K_NUMPAD_3,
|
||||||
|
"numpad_4": C.K_NUMPAD_4,
|
||||||
|
"numpad_5": C.K_NUMPAD_5,
|
||||||
|
"numpad_6": C.K_NUMPAD_6,
|
||||||
|
"numpad_7": C.K_NUMPAD_7,
|
||||||
|
"numpad_8": C.K_NUMPAD_8,
|
||||||
|
"numpad_9": C.K_NUMPAD_9,
|
||||||
|
"numpad_lock": C.K_NUMPAD_LOCK,
|
||||||
|
|
||||||
|
"num.": C.K_NUMPAD_DECIMAL,
|
||||||
|
"num+": C.K_NUMPAD_PLUS,
|
||||||
|
"num-": C.K_NUMPAD_MINUS,
|
||||||
|
"num*": C.K_NUMPAD_MUL,
|
||||||
|
"num/": C.K_NUMPAD_DIV,
|
||||||
|
"num_clear": C.K_NUMPAD_CLEAR,
|
||||||
|
"num_enter": C.K_NUMPAD_ENTER,
|
||||||
|
"num_equal": C.K_NUMPAD_EQUAL,
|
||||||
|
|
||||||
|
"lights_mon_up": C.K_LIGHTS_MON_UP,
|
||||||
|
"lights_mon_down": C.K_LIGHTS_MON_DOWN,
|
||||||
|
"lights_kbd_toggle": C.K_LIGHTS_KBD_TOGGLE,
|
||||||
|
"lights_kbd_up": C.K_LIGHTS_KBD_UP,
|
||||||
|
"lights_kbd_down": C.K_LIGHTS_KBD_DOWN,
|
||||||
|
|
||||||
|
// { NULL: C.K_NOT_A_KEY }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.")
|
||||||
|
|
||||||
|
func checkKeyCodes(k string) (key C.MMKeyCode, err error) {
|
||||||
|
if k == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(k) == 1 {
|
||||||
|
val1 := C.CString(k)
|
||||||
|
defer C.free(unsafe.Pointer(val1))
|
||||||
|
|
||||||
|
key = C.keyCodeForChar(*val1)
|
||||||
|
if key == C.K_NOT_A_KEY {
|
||||||
|
err = keyErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := keyNames[k]; ok {
|
||||||
|
key = v
|
||||||
|
if key == C.K_NOT_A_KEY {
|
||||||
|
err = keyErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkKeyFlags(f string) (flags C.MMKeyFlags) {
|
||||||
|
m := map[string]C.MMKeyFlags{
|
||||||
|
"alt": C.MOD_ALT,
|
||||||
|
"ralt": C.MOD_ALT,
|
||||||
|
"lalt": C.MOD_ALT,
|
||||||
|
"cmd": C.MOD_META,
|
||||||
|
"rcmd": C.MOD_META,
|
||||||
|
"lcmd": C.MOD_META,
|
||||||
|
"ctrl": C.MOD_CONTROL,
|
||||||
|
"rctrl": C.MOD_CONTROL,
|
||||||
|
"lctrl": C.MOD_CONTROL,
|
||||||
|
"shift": C.MOD_SHIFT,
|
||||||
|
"rshift": C.MOD_SHIFT,
|
||||||
|
"lshift": C.MOD_SHIFT,
|
||||||
|
"none": C.MOD_NONE,
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := m[f]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFlagsFromValue(value []string) (flags C.MMKeyFlags) {
|
||||||
|
if len(value) <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(value); i++ {
|
||||||
|
var f C.MMKeyFlags = C.MOD_NONE
|
||||||
|
|
||||||
|
f = checkKeyFlags(value[i])
|
||||||
|
flags = (C.MMKeyFlags)(flags | f)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func keyTaps(k string, keyArr []string, pid int) error {
|
||||||
|
flags := getFlagsFromValue(keyArr)
|
||||||
|
key, err := checkKeyCodes(k)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tapKeyCode(key, flags, C.uintptr(pid))
|
||||||
|
MilliSleep(KeySleep)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getKeyDown(keyArr []string) (bool, []string) {
|
||||||
|
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:]
|
||||||
|
}
|
||||||
|
return down, keyArr
|
||||||
|
}
|
||||||
|
|
||||||
|
func keyTogglesB(k string, down bool, keyArr []string, pid int) error {
|
||||||
|
flags := getFlagsFromValue(keyArr)
|
||||||
|
key, err := checkKeyCodes(k)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
C.toggleKeyCode(key, C.bool(down), flags, C.uintptr(pid))
|
||||||
|
MilliSleep(KeySleep)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func keyToggles(k string, keyArr []string, pid int) error {
|
||||||
|
down, keyArr1 := getKeyDown(keyArr)
|
||||||
|
return keyTogglesB(k, down, keyArr1, pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
__ ___ ___________ ____ .______ ______ ___ .______ _______
|
||||||
|
| |/ / | ____\ \ / / | _ \ / __ \ / \ | _ \ | \
|
||||||
|
| ' / | |__ \ \/ / | |_) | | | | | / ^ \ | |_) | | .--. |
|
||||||
|
| < | __| \_ _/ | _ < | | | | / /_\ \ | / | | | |
|
||||||
|
| . \ | |____ | | | |_) | | `--' | / _____ \ | |\ \----.| '--' |
|
||||||
|
|__|\__\ |_______| |__| |______/ \______/ /__/ \__\ | _| `._____||_______/
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ToInterfaces convert []string to []interface{}
|
||||||
|
func ToInterfaces(fields []string) []interface{} {
|
||||||
|
res := make([]interface{}, 0, len(fields))
|
||||||
|
for _, s := range fields {
|
||||||
|
res = append(res, s)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToStrings convert []interface{} to []string
|
||||||
|
func ToStrings(fields []interface{}) []string {
|
||||||
|
res := make([]string, 0, len(fields))
|
||||||
|
for _, s := range fields {
|
||||||
|
res = append(res, s.(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 == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New(gstr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendShift(key string, len1 int, args ...interface{}) []interface{} {
|
||||||
|
if len(key) > 0 && unicode.IsUpper([]rune(key)[0]) {
|
||||||
|
args = append(args, "shift")
|
||||||
|
}
|
||||||
|
|
||||||
|
key = strings.ToLower(key)
|
||||||
|
if _, ok := Special[key]; ok {
|
||||||
|
key = Special[key]
|
||||||
|
if len(args) <= len1 {
|
||||||
|
args = append(args, "shift")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyTap taps the keyboard code;
|
||||||
|
//
|
||||||
|
// 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")
|
||||||
|
//
|
||||||
|
// arr := []string{"alt", "command"}
|
||||||
|
// robotgo.KeyTap("i", arr)
|
||||||
|
//
|
||||||
|
// robotgo.KeyTap("k", pid int)
|
||||||
|
func KeyTap(key string, args ...interface{}) error {
|
||||||
|
var keyArr []string
|
||||||
|
args = appendShift(key, 0, args...)
|
||||||
|
|
||||||
|
pid := 0
|
||||||
|
if len(args) > 0 {
|
||||||
|
if reflect.TypeOf(args[0]) == reflect.TypeOf(keyArr) {
|
||||||
|
keyArr = args[0].([]string)
|
||||||
|
} else {
|
||||||
|
if reflect.TypeOf(args[0]) == reflect.TypeOf(pid) {
|
||||||
|
pid = args[0].(int)
|
||||||
|
keyArr = ToStrings(args[1:])
|
||||||
|
} else {
|
||||||
|
keyArr = ToStrings(args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keyTaps(key, keyArr, pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getToggleArgs(args ...interface{}) (pid int, keyArr []string) {
|
||||||
|
if len(args) > 0 && reflect.TypeOf(args[0]) == reflect.TypeOf(pid) {
|
||||||
|
pid = args[0].(int)
|
||||||
|
keyArr = ToStrings(args[1:])
|
||||||
|
} else {
|
||||||
|
keyArr = ToStrings(args)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyToggle toggles the keyboard, if there not have args default is "down"
|
||||||
|
//
|
||||||
|
// See keys:
|
||||||
|
//
|
||||||
|
// 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")
|
||||||
|
// robotgo.KeyToggle("k", pid int)
|
||||||
|
func KeyToggle(key string, args ...interface{}) error {
|
||||||
|
args = appendShift(key, 1, args...)
|
||||||
|
pid, keyArr := getToggleArgs(args...)
|
||||||
|
return keyToggles(key, keyArr, pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyPress press key string
|
||||||
|
func KeyPress(key string, args ...interface{}) error {
|
||||||
|
err := KeyDown(key, args...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
MilliSleep(1 + rand.Intn(3))
|
||||||
|
return KeyUp(key, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyDown press down a key
|
||||||
|
func KeyDown(key string, args ...interface{}) error {
|
||||||
|
return KeyToggle(key, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyUp press up a key
|
||||||
|
func KeyUp(key string, args ...interface{}) error {
|
||||||
|
arr := []interface{}{"up"}
|
||||||
|
arr = append(arr, args...)
|
||||||
|
return KeyToggle(key, arr...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadAll read string from clipboard
|
||||||
|
func ReadAll() (string, error) {
|
||||||
|
return clipboard.ReadAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteAll write string to clipboard
|
||||||
|
func WriteAll(text string) error {
|
||||||
|
return clipboard.WriteAll(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CharCodeAt char code at utf-8
|
||||||
|
func CharCodeAt(s string, n int) rune {
|
||||||
|
i := 0
|
||||||
|
for _, r := range s {
|
||||||
|
if i == n {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnicodeType tap the uint32 unicode
|
||||||
|
func UnicodeType(str uint32, args ...int) {
|
||||||
|
cstr := C.uint(str)
|
||||||
|
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
|
||||||
|
func ToUC(text string) []string {
|
||||||
|
var uc []string
|
||||||
|
|
||||||
|
for _, r := range text {
|
||||||
|
textQ := strconv.QuoteToASCII(string(r))
|
||||||
|
textUnQ := textQ[1 : len(textQ)-1]
|
||||||
|
|
||||||
|
st := strings.Replace(textUnQ, "\\u", "U", -1)
|
||||||
|
if st == "\\\\" {
|
||||||
|
st = "\\"
|
||||||
|
}
|
||||||
|
if st == `\"` {
|
||||||
|
st = `"`
|
||||||
|
}
|
||||||
|
uc = append(uc, st)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uc
|
||||||
|
}
|
||||||
|
|
||||||
|
func inputUTF(str string) {
|
||||||
|
cstr := C.CString(str)
|
||||||
|
C.input_utf(cstr)
|
||||||
|
|
||||||
|
C.free(unsafe.Pointer(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeStr send a string (supported UTF-8)
|
||||||
|
//
|
||||||
|
// robotgo.TypeStr(string: "The string to send", int: pid, "milli_sleep time", "x11 option")
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// 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) > 1 {
|
||||||
|
tm = args[1]
|
||||||
|
}
|
||||||
|
if len(args) > 2 {
|
||||||
|
tm1 = args[2]
|
||||||
|
}
|
||||||
|
pid := 0
|
||||||
|
if len(args) > 0 {
|
||||||
|
pid = args[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
strUc := ToUC(str)
|
||||||
|
for i := 0; i < len(strUc); i++ {
|
||||||
|
ru := []rune(strUc[i])
|
||||||
|
if len(ru) <= 1 {
|
||||||
|
ustr := uint32(CharCodeAt(strUc[i], 0))
|
||||||
|
UnicodeType(ustr, pid)
|
||||||
|
} else {
|
||||||
|
inputUTF(strUc[i])
|
||||||
|
MilliSleep(tm1)
|
||||||
|
}
|
||||||
|
|
||||||
|
MilliSleep(tm)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len([]rune(str)); i++ {
|
||||||
|
ustr := uint32(CharCodeAt(str, i))
|
||||||
|
UnicodeType(ustr, pid)
|
||||||
|
// if len(args) > 0 {
|
||||||
|
MilliSleep(tm)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
MilliSleep(KeySleep)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
return KeyTap("v", "command")
|
||||||
|
}
|
||||||
|
|
||||||
|
return KeyTap("v", "control")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
v = d[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
KeySleep = v
|
||||||
|
MouseSleep = v
|
||||||
|
}
|
403
key/goKey.h
403
key/goKey.h
@ -1,403 +0,0 @@
|
|||||||
// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// https://github.com/go-vgo/robotgo/blob/master/LICENSE
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
#include "../base/types.h"
|
|
||||||
// #include "keycode.h"
|
|
||||||
// #include "keypress.h"
|
|
||||||
#include "keypress_c.h"
|
|
||||||
#include "keycode_c.h"
|
|
||||||
|
|
||||||
|
|
||||||
int keyboardDelay = 0;
|
|
||||||
|
|
||||||
struct KeyNames{
|
|
||||||
const char* name;
|
|
||||||
MMKeyCode key;
|
|
||||||
}key_names[] = {
|
|
||||||
{ "backspace", K_BACKSPACE },
|
|
||||||
{ "delete", K_DELETE },
|
|
||||||
{ "enter", K_RETURN },
|
|
||||||
{ "tab", K_TAB },
|
|
||||||
{ "esc", K_ESCAPE },
|
|
||||||
{ "escape", K_ESCAPE },
|
|
||||||
{ "up", K_UP },
|
|
||||||
{ "down", K_DOWN },
|
|
||||||
{ "right", K_RIGHT },
|
|
||||||
{ "left", K_LEFT },
|
|
||||||
{ "home", K_HOME },
|
|
||||||
{ "end", K_END },
|
|
||||||
{ "pageup", K_PAGEUP },
|
|
||||||
{ "pagedown", K_PAGEDOWN },
|
|
||||||
//
|
|
||||||
{ "f1", K_F1 },
|
|
||||||
{ "f2", K_F2 },
|
|
||||||
{ "f3", K_F3 },
|
|
||||||
{ "f4", K_F4 },
|
|
||||||
{ "f5", K_F5 },
|
|
||||||
{ "f6", K_F6 },
|
|
||||||
{ "f7", K_F7 },
|
|
||||||
{ "f8", K_F8 },
|
|
||||||
{ "f9", K_F9 },
|
|
||||||
{ "f10", K_F10 },
|
|
||||||
{ "f11", K_F11 },
|
|
||||||
{ "f12", K_F12 },
|
|
||||||
{ "f13", K_F13 },
|
|
||||||
{ "f14", K_F14 },
|
|
||||||
{ "f15", K_F15 },
|
|
||||||
{ "f16", K_F16 },
|
|
||||||
{ "f17", K_F17 },
|
|
||||||
{ "f18", K_F18 },
|
|
||||||
{ "f19", K_F19 },
|
|
||||||
{ "f20", K_F20 },
|
|
||||||
{ "f21", K_F21 },
|
|
||||||
{ "f22", K_F22 },
|
|
||||||
{ "f23", K_F23 },
|
|
||||||
{ "f24", K_F24 },
|
|
||||||
//
|
|
||||||
{ "cmd", K_META },
|
|
||||||
{ "lcmd", K_LMETA },
|
|
||||||
{ "rcmd", K_RMETA },
|
|
||||||
{ "command", K_META },
|
|
||||||
{ "alt", K_ALT },
|
|
||||||
{ "lalt", K_LALT },
|
|
||||||
{ "ralt", K_RALT },
|
|
||||||
{ "ctrl", K_CONTROL },
|
|
||||||
{ "lctrl", K_LCONTROL },
|
|
||||||
{ "rctrl", K_RCONTROL },
|
|
||||||
{ "control", K_CONTROL },
|
|
||||||
{ "shift", K_SHIFT },
|
|
||||||
{ "lshift", K_LSHIFT },
|
|
||||||
{ "rshift", K_RSHIFT },
|
|
||||||
{ "right_shift", K_RSHIFT },
|
|
||||||
{ "capslock", K_CAPSLOCK },
|
|
||||||
{ "space", K_SPACE },
|
|
||||||
{ "print", K_PRINTSCREEN },
|
|
||||||
{ "printscreen", K_PRINTSCREEN },
|
|
||||||
{ "insert", K_INSERT },
|
|
||||||
{ "menu", K_MENU },
|
|
||||||
|
|
||||||
{ "audio_mute", K_AUDIO_VOLUME_MUTE },
|
|
||||||
{ "audio_vol_down", K_AUDIO_VOLUME_DOWN },
|
|
||||||
{ "audio_vol_up", K_AUDIO_VOLUME_UP },
|
|
||||||
{ "audio_play", K_AUDIO_PLAY },
|
|
||||||
{ "audio_stop", K_AUDIO_STOP },
|
|
||||||
{ "audio_pause", K_AUDIO_PAUSE },
|
|
||||||
{ "audio_prev", K_AUDIO_PREV },
|
|
||||||
{ "audio_next", K_AUDIO_NEXT },
|
|
||||||
{ "audio_rewind", K_AUDIO_REWIND },
|
|
||||||
{ "audio_forward", K_AUDIO_FORWARD },
|
|
||||||
{ "audio_repeat", K_AUDIO_REPEAT },
|
|
||||||
{ "audio_random", K_AUDIO_RANDOM },
|
|
||||||
|
|
||||||
{ "num0", K_NUMPAD_0 },
|
|
||||||
{ "num1", K_NUMPAD_1 },
|
|
||||||
{ "num2", K_NUMPAD_2 },
|
|
||||||
{ "num3", K_NUMPAD_3 },
|
|
||||||
{ "num4", K_NUMPAD_4 },
|
|
||||||
{ "num5", K_NUMPAD_5 },
|
|
||||||
{ "num6", K_NUMPAD_6 },
|
|
||||||
{ "num7", K_NUMPAD_7 },
|
|
||||||
{ "num8", K_NUMPAD_8 },
|
|
||||||
{ "num9", K_NUMPAD_9 },
|
|
||||||
{ "num_lock", K_NUMPAD_LOCK },
|
|
||||||
|
|
||||||
// todo: removed
|
|
||||||
{ "numpad_0", K_NUMPAD_0 },
|
|
||||||
{ "numpad_1", K_NUMPAD_1 },
|
|
||||||
{ "numpad_2", K_NUMPAD_2 },
|
|
||||||
{ "numpad_3", K_NUMPAD_3 },
|
|
||||||
{ "numpad_4", K_NUMPAD_4 },
|
|
||||||
{ "numpad_5", K_NUMPAD_5 },
|
|
||||||
{ "numpad_6", K_NUMPAD_6 },
|
|
||||||
{ "numpad_7", K_NUMPAD_7 },
|
|
||||||
{ "numpad_8", K_NUMPAD_8 },
|
|
||||||
{ "numpad_9", K_NUMPAD_9 },
|
|
||||||
{ "numpad_lock", K_NUMPAD_LOCK },
|
|
||||||
|
|
||||||
{"num.", K_NUMPAD_DECIMAL },
|
|
||||||
{"num+", K_NUMPAD_PLUS },
|
|
||||||
{"num-", K_NUMPAD_MINUS },
|
|
||||||
{"num*", K_NUMPAD_MUL },
|
|
||||||
{"num/", K_NUMPAD_DIV },
|
|
||||||
{"num_clear", K_NUMPAD_CLEAR },
|
|
||||||
{"num_enter", K_NUMPAD_ENTER },
|
|
||||||
{"num_equal", K_NUMPAD_EQUAL },
|
|
||||||
|
|
||||||
{ "lights_mon_up", K_LIGHTS_MON_UP },
|
|
||||||
{ "lights_mon_down", K_LIGHTS_MON_DOWN },
|
|
||||||
{ "lights_kbd_toggle",K_LIGHTS_KBD_TOGGLE },
|
|
||||||
{ "lights_kbd_up", K_LIGHTS_KBD_UP },
|
|
||||||
{ "lights_kbd_down", K_LIGHTS_KBD_DOWN },
|
|
||||||
|
|
||||||
{ NULL, K_NOT_A_KEY } /* end marker */
|
|
||||||
};
|
|
||||||
|
|
||||||
int CheckKeyCodes(char* k, MMKeyCode *key){
|
|
||||||
if (!key) { return -1; }
|
|
||||||
|
|
||||||
if (strlen(k) == 1) {
|
|
||||||
*key = keyCodeForChar(*k);
|
|
||||||
if (*key == K_NOT_A_KEY) {
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*key = K_NOT_A_KEY;
|
|
||||||
|
|
||||||
struct KeyNames* kn = key_names;
|
|
||||||
while (kn->name) {
|
|
||||||
if (strcmp(k, kn->name) == 0){
|
|
||||||
*key = kn->key;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
kn++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*key == K_NOT_A_KEY) {
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CheckKeyFlags(char* f, MMKeyFlags* flags){
|
|
||||||
if (!flags) { return -1; }
|
|
||||||
|
|
||||||
if ( strcmp(f, "alt") == 0 || strcmp(f, "ralt") == 0 ||
|
|
||||||
strcmp(f, "lalt") == 0 ) {
|
|
||||||
*flags = MOD_ALT;
|
|
||||||
}
|
|
||||||
else if( strcmp(f, "command") == 0 || strcmp(f, "cmd") == 0 ||
|
|
||||||
strcmp(f, "rcmd") == 0 || strcmp(f, "lcmd") == 0 ) {
|
|
||||||
*flags = MOD_META;
|
|
||||||
}
|
|
||||||
else if( strcmp(f, "control") == 0 || strcmp(f, "ctrl") == 0 ||
|
|
||||||
strcmp(f, "rctrl") == 0 || strcmp(f, "lctrl") == 0 ) {
|
|
||||||
*flags = MOD_CONTROL;
|
|
||||||
}
|
|
||||||
else if( strcmp(f, "shift") == 0 || strcmp(f, "right_shift") == 0 ||
|
|
||||||
strcmp(f, "rshift") == 0 || strcmp(f, "lshift") == 0 ) {
|
|
||||||
*flags = MOD_SHIFT;
|
|
||||||
}
|
|
||||||
else if( strcmp(f, "none") == 0 ) {
|
|
||||||
*flags = (MMKeyFlags) MOD_NONE;
|
|
||||||
} else {
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetFlagsFromValue(char* value[], MMKeyFlags* flags, int num){
|
|
||||||
if (!flags) {return -1;}
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for ( i= 0; i <num; i++) {
|
|
||||||
MMKeyFlags f = MOD_NONE;
|
|
||||||
const int rv = CheckKeyFlags(value[i], &f);
|
|
||||||
if (rv) { return rv; }
|
|
||||||
|
|
||||||
*flags = (MMKeyFlags)(*flags | f);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
// return CheckKeyFlags(fstr, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it's not an array, it should be a single string value.
|
|
||||||
char* key_Taps(char *k, char* keyArr[], int num, int keyDelay){
|
|
||||||
MMKeyFlags flags = MOD_NONE;
|
|
||||||
// MMKeyFlags flags = 0;
|
|
||||||
MMKeyCode key;
|
|
||||||
|
|
||||||
switch(GetFlagsFromValue(keyArr, &flags, num)) {
|
|
||||||
// switch (CheckKeyFlags(akey, &flags)){
|
|
||||||
case -1:
|
|
||||||
return "Null pointer in key flag.";
|
|
||||||
break;
|
|
||||||
case -2:
|
|
||||||
return "Invalid key flag specified.";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(CheckKeyCodes(k, &key)) {
|
|
||||||
case -1:
|
|
||||||
return "Null pointer in key code.";
|
|
||||||
break;
|
|
||||||
case -2:
|
|
||||||
return "Invalid key code specified.";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
tapKeyCode(key, flags);
|
|
||||||
microsleep(keyDelay);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return "0";
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
char* key_tap(char *k, char *akey, char *keyT, int keyDelay){
|
|
||||||
MMKeyFlags flags = (MMKeyFlags) MOD_NONE;
|
|
||||||
// MMKeyFlags flags = 0;
|
|
||||||
MMKeyCode key;
|
|
||||||
|
|
||||||
// char *k;
|
|
||||||
// k = *kstr;
|
|
||||||
if (strcmp(akey, "null") != 0) {
|
|
||||||
if (strcmp(keyT, "null") == 0) {
|
|
||||||
switch (CheckKeyFlags(akey, &flags)) {
|
|
||||||
case -1:
|
|
||||||
return "Null pointer in key flag.";
|
|
||||||
break;
|
|
||||||
case -2:
|
|
||||||
return "Invalid key flag specified.";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
char* akeyArr[2] = {akey, keyT};
|
|
||||||
switch(GetFlagsFromValue(akeyArr, &flags, 2)) {
|
|
||||||
case -1:
|
|
||||||
return "Null pointer in key flag.";
|
|
||||||
break;
|
|
||||||
case -2:
|
|
||||||
return "Invalid key flag specified.";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(CheckKeyCodes(k, &key)) {
|
|
||||||
case -1:
|
|
||||||
return "Null pointer in key code.";
|
|
||||||
break;
|
|
||||||
case -2:
|
|
||||||
return "Invalid key code specified.";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
tapKeyCode(key, flags);
|
|
||||||
microsleep(keyDelay);
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
char* key_Toggles(char* k, char* keyArr[], int num) {
|
|
||||||
MMKeyFlags flags = (MMKeyFlags) MOD_NONE;
|
|
||||||
MMKeyCode key;
|
|
||||||
|
|
||||||
bool down;
|
|
||||||
char* d = keyArr[0];
|
|
||||||
if (d != 0) {
|
|
||||||
// char *d;
|
|
||||||
// d = *dstr;
|
|
||||||
if (strcmp(d, "down") == 0) {
|
|
||||||
down = true;
|
|
||||||
} else if (strcmp(d, "up") == 0) {
|
|
||||||
down = false;
|
|
||||||
} else {
|
|
||||||
return "Invalid key state specified.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (GetFlagsFromValue(keyArr, &flags, num)) {
|
|
||||||
case -1:
|
|
||||||
return "Null pointer in key flag.";
|
|
||||||
break;
|
|
||||||
case -2:
|
|
||||||
return "Invalid key flag specified.";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(CheckKeyCodes(k, &key)) {
|
|
||||||
case -1:
|
|
||||||
return "Null pointer in key code.";
|
|
||||||
break;
|
|
||||||
case -2:
|
|
||||||
return "Invalid key code specified.";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
toggleKeyCode(key, down, flags);
|
|
||||||
microsleep(keyboardDelay);
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
char* key_toggle(char* k, char* d, char* akey, char* keyT){
|
|
||||||
MMKeyFlags flags = (MMKeyFlags) MOD_NONE;
|
|
||||||
MMKeyCode key;
|
|
||||||
|
|
||||||
bool down;
|
|
||||||
// char *k;
|
|
||||||
// k = *kstr;
|
|
||||||
|
|
||||||
if (d != 0) {
|
|
||||||
// char *d;
|
|
||||||
// d = *dstr;
|
|
||||||
if (strcmp(d, "down") == 0) {
|
|
||||||
down = true;
|
|
||||||
} else if (strcmp(d, "up") == 0) {
|
|
||||||
down = false;
|
|
||||||
} else {
|
|
||||||
return "Invalid key state specified.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(akey, "null") != 0) {
|
|
||||||
if (strcmp(keyT, "null") == 0) {
|
|
||||||
switch (CheckKeyFlags(akey, &flags)) {
|
|
||||||
case -1:
|
|
||||||
return "Null pointer in key flag.";
|
|
||||||
break;
|
|
||||||
case -2:
|
|
||||||
return "Invalid key flag specified.";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
char* akeyArr[2] = {akey, keyT};
|
|
||||||
switch (GetFlagsFromValue(akeyArr, &flags, 2)) {
|
|
||||||
case -1:
|
|
||||||
return "Null pointer in key flag.";
|
|
||||||
break;
|
|
||||||
case -2:
|
|
||||||
return "Invalid key flag specified.";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(CheckKeyCodes(k, &key)) {
|
|
||||||
case -1:
|
|
||||||
return "Null pointer in key code.";
|
|
||||||
break;
|
|
||||||
case -2:
|
|
||||||
return "Invalid key code specified.";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
toggleKeyCode(key, down, flags);
|
|
||||||
microsleep(keyboardDelay);
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_string(char *str){
|
|
||||||
typeStringDelayed(str, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_string_delayed(char *str, size_t cpm){
|
|
||||||
typeStringDelayed(str, cpm);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_keyboard_delay(size_t val){
|
|
||||||
keyboardDelay = val;
|
|
||||||
}
|
|
11
key/key.go
Normal file
11
key/key.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// 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 key
|
4
key/key_windows.go
Normal file
4
key/key_windows.go
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package key
|
@ -4,11 +4,6 @@
|
|||||||
|
|
||||||
#include "../base/os.h"
|
#include "../base/os.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
|
|
||||||
#include <Carbon/Carbon.h> /* Really only need <HIToolbox/Events.h> */
|
#include <Carbon/Carbon.h> /* Really only need <HIToolbox/Events.h> */
|
||||||
@ -96,6 +91,13 @@ enum _MMKeyCode {
|
|||||||
K_NUMPAD_CLEAR = kVK_ANSI_KeypadClear,
|
K_NUMPAD_CLEAR = kVK_ANSI_KeypadClear,
|
||||||
K_NUMPAD_ENTER = kVK_ANSI_KeypadEnter,
|
K_NUMPAD_ENTER = kVK_ANSI_KeypadEnter,
|
||||||
K_NUMPAD_EQUAL = kVK_ANSI_KeypadEquals,
|
K_NUMPAD_EQUAL = kVK_ANSI_KeypadEquals,
|
||||||
|
K_NUMPAD_LB = kVK_ANSI_LeftBracket,
|
||||||
|
K_NUMPAD_RB = kVK_ANSI_RightBracket,
|
||||||
|
K_Backslash = kVK_ANSI_Backslash,
|
||||||
|
K_Semicolon = kVK_ANSI_Semicolon,
|
||||||
|
K_Quote = kVK_ANSI_Quote,
|
||||||
|
K_Slash = kVK_ANSI_Slash,
|
||||||
|
K_Grave = kVK_ANSI_Grave,
|
||||||
|
|
||||||
K_AUDIO_VOLUME_MUTE = 1007,
|
K_AUDIO_VOLUME_MUTE = 1007,
|
||||||
K_AUDIO_VOLUME_DOWN = 1001,
|
K_AUDIO_VOLUME_DOWN = 1001,
|
||||||
@ -177,7 +179,7 @@ enum _MMKeyCode {
|
|||||||
K_SHIFT = XK_Shift_L,
|
K_SHIFT = XK_Shift_L,
|
||||||
K_LSHIFT = XK_Shift_L,
|
K_LSHIFT = XK_Shift_L,
|
||||||
K_RSHIFT = XK_Shift_R,
|
K_RSHIFT = XK_Shift_R,
|
||||||
K_CAPSLOCK = XK_Shift_Lock,
|
K_CAPSLOCK = XK_Caps_Lock,
|
||||||
K_SPACE = XK_space,
|
K_SPACE = XK_space,
|
||||||
K_INSERT = XK_Insert,
|
K_INSERT = XK_Insert,
|
||||||
K_PRINTSCREEN = XK_Print,
|
K_PRINTSCREEN = XK_Print,
|
||||||
@ -204,6 +206,13 @@ enum _MMKeyCode {
|
|||||||
K_NUMPAD_CLEAR = K_NOT_A_KEY,
|
K_NUMPAD_CLEAR = K_NOT_A_KEY,
|
||||||
K_NUMPAD_ENTER = 96, // XK_KP_Enter
|
K_NUMPAD_ENTER = 96, // XK_KP_Enter
|
||||||
K_NUMPAD_EQUAL = XK_equal,
|
K_NUMPAD_EQUAL = XK_equal,
|
||||||
|
K_NUMPAD_LB = XK_bracketleft,
|
||||||
|
K_NUMPAD_RB = XK_bracketright,
|
||||||
|
K_Backslash = XK_backslash,
|
||||||
|
K_Semicolon = XK_semicolon,
|
||||||
|
K_Quote = XK_apostrophe,
|
||||||
|
K_Slash = XK_slash,
|
||||||
|
K_Grave = XK_grave,
|
||||||
|
|
||||||
K_AUDIO_VOLUME_MUTE = XF86XK_AudioMute,
|
K_AUDIO_VOLUME_MUTE = XF86XK_AudioMute,
|
||||||
K_AUDIO_VOLUME_DOWN = XF86XK_AudioLowerVolume,
|
K_AUDIO_VOLUME_DOWN = XF86XK_AudioLowerVolume,
|
||||||
@ -227,6 +236,53 @@ enum _MMKeyCode {
|
|||||||
|
|
||||||
typedef KeySym MMKeyCode;
|
typedef KeySym MMKeyCode;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structs to store key mappings not handled by XStringToKeysym() on some
|
||||||
|
* Linux systems.
|
||||||
|
*/
|
||||||
|
struct XSpecialCharacterMapping {
|
||||||
|
char name;
|
||||||
|
MMKeyCode code;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct XSpecialCharacterMapping XSpecialCharacterTable[] = {
|
||||||
|
{'~', XK_asciitilde},
|
||||||
|
{'_', XK_underscore},
|
||||||
|
{'[', XK_bracketleft},
|
||||||
|
{']', XK_bracketright},
|
||||||
|
{'!', XK_exclam},
|
||||||
|
{'#', XK_numbersign},
|
||||||
|
{'$', XK_dollar},
|
||||||
|
{'%', XK_percent},
|
||||||
|
{'&', XK_ampersand},
|
||||||
|
{'*', XK_asterisk},
|
||||||
|
{'+', XK_plus},
|
||||||
|
{',', XK_comma},
|
||||||
|
{'-', XK_minus},
|
||||||
|
{'.', XK_period},
|
||||||
|
{'?', XK_question},
|
||||||
|
{'<', XK_less},
|
||||||
|
{'>', XK_greater},
|
||||||
|
{'=', XK_equal},
|
||||||
|
{'@', XK_at},
|
||||||
|
{':', XK_colon},
|
||||||
|
{';', XK_semicolon},
|
||||||
|
{'{', XK_braceleft},
|
||||||
|
{'}', XK_braceright},
|
||||||
|
{'|', XK_bar},
|
||||||
|
{'^', XK_asciicircum},
|
||||||
|
{'(', XK_parenleft},
|
||||||
|
{')', XK_parenright},
|
||||||
|
{' ', XK_space},
|
||||||
|
{'/', XK_slash},
|
||||||
|
{'\\', XK_backslash},
|
||||||
|
{'`', XK_grave},
|
||||||
|
{'"', XK_quoteright},
|
||||||
|
{'\'', XK_quotedbl},
|
||||||
|
{'\t', XK_Tab},
|
||||||
|
{'\n', XK_Return}
|
||||||
|
};
|
||||||
|
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
|
|
||||||
enum _MMKeyCode {
|
enum _MMKeyCode {
|
||||||
@ -308,6 +364,13 @@ enum _MMKeyCode {
|
|||||||
K_NUMPAD_CLEAR = K_NOT_A_KEY,
|
K_NUMPAD_CLEAR = K_NOT_A_KEY,
|
||||||
K_NUMPAD_ENTER = VK_RETURN,
|
K_NUMPAD_ENTER = VK_RETURN,
|
||||||
K_NUMPAD_EQUAL = VK_OEM_PLUS,
|
K_NUMPAD_EQUAL = VK_OEM_PLUS,
|
||||||
|
K_NUMPAD_LB = VK_OEM_4,
|
||||||
|
K_NUMPAD_RB = VK_OEM_6,
|
||||||
|
K_Backslash = VK_OEM_5,
|
||||||
|
K_Semicolon = VK_OEM_1,
|
||||||
|
K_Quote = VK_OEM_7,
|
||||||
|
K_Slash = VK_OEM_2,
|
||||||
|
K_Grave = VK_OEM_3,
|
||||||
|
|
||||||
K_AUDIO_VOLUME_MUTE = VK_VOLUME_MUTE,
|
K_AUDIO_VOLUME_MUTE = VK_VOLUME_MUTE,
|
||||||
K_AUDIO_VOLUME_DOWN = VK_VOLUME_DOWN,
|
K_AUDIO_VOLUME_DOWN = VK_VOLUME_DOWN,
|
||||||
@ -338,7 +401,3 @@ typedef int MMKeyCode;
|
|||||||
MMKeyCode keyCodeForChar(const char c);
|
MMKeyCode keyCodeForChar(const char c);
|
||||||
|
|
||||||
#endif /* KEYCODE_H */
|
#endif /* KEYCODE_H */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
191
key/keycode_c.h
191
key/keycode_c.h
@ -1,74 +1,19 @@
|
|||||||
#include "keycode.h"
|
#include "keycode.h"
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include <Carbon/Carbon.h> /* For kVK_ constants, and TIS functions. */
|
||||||
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
/* Returns string representation of key, if it is printable.
|
||||||
#include <Carbon/Carbon.h> /* For kVK_ constants, and TIS functions. */
|
Ownership follows the Create Rule;
|
||||||
|
it is the caller's responsibility to release the returned object. */
|
||||||
/* Returns string representation of key, if it is printable.
|
CFStringRef createStringForKey(CGKeyCode keyCode);
|
||||||
* Ownership follows the Create Rule; that is, it is the caller's
|
|
||||||
* responsibility to release the returned object. */
|
|
||||||
CFStringRef createStringForKey(CGKeyCode keyCode);
|
|
||||||
|
|
||||||
MMKeyCode keyCodeForCharFallBack(const char c);
|
|
||||||
|
|
||||||
#elif defined(USE_X11)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Structs to store key mappings not handled by XStringToKeysym() on some
|
|
||||||
* Linux systems.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct XSpecialCharacterMapping {
|
|
||||||
char name;
|
|
||||||
MMKeyCode code;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct XSpecialCharacterMapping XSpecialCharacterTable[] = {
|
|
||||||
{'~', XK_asciitilde},
|
|
||||||
{'_', XK_underscore},
|
|
||||||
{'[', XK_bracketleft},
|
|
||||||
{']', XK_bracketright},
|
|
||||||
{'!', XK_exclam},
|
|
||||||
{'#', XK_numbersign},
|
|
||||||
{'$', XK_dollar},
|
|
||||||
{'%', XK_percent},
|
|
||||||
{'&', XK_ampersand},
|
|
||||||
{'*', XK_asterisk},
|
|
||||||
{'+', XK_plus},
|
|
||||||
{',', XK_comma},
|
|
||||||
{'-', XK_minus},
|
|
||||||
{'.', XK_period},
|
|
||||||
{'?', XK_question},
|
|
||||||
{'<', XK_less},
|
|
||||||
{'>', XK_greater},
|
|
||||||
{'=', XK_equal},
|
|
||||||
{'@', XK_at},
|
|
||||||
{':', XK_colon},
|
|
||||||
{';', XK_semicolon},
|
|
||||||
{'{', XK_braceleft},
|
|
||||||
{'}', XK_braceright},
|
|
||||||
{'|', XK_bar},
|
|
||||||
{'^', XK_asciicircum},
|
|
||||||
{'(', XK_parenleft},
|
|
||||||
{')', XK_parenright},
|
|
||||||
{' ', XK_space},
|
|
||||||
{'/', XK_slash},
|
|
||||||
{'\\', XK_backslash},
|
|
||||||
{'`', XK_grave},
|
|
||||||
{'"', XK_quoteright},
|
|
||||||
{'\'', XK_quotedbl},
|
|
||||||
// {'\'', XK_quoteright},
|
|
||||||
{'\t', XK_Tab},
|
|
||||||
{'\n', XK_Return}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MMKeyCode keyCodeForChar(const char c){
|
MMKeyCode keyCodeForChar(const char c) {
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
/* OS X does not appear to have a built-in function for this, so instead we
|
/* OS X does not appear to have a built-in function for this,
|
||||||
* have to write our own. */
|
so instead it to write our own. */
|
||||||
static CFMutableDictionaryRef charToCodeDict = NULL;
|
static CFMutableDictionaryRef charToCodeDict = NULL;
|
||||||
CGKeyCode code;
|
CGKeyCode code;
|
||||||
UniChar character = c;
|
UniChar character = c;
|
||||||
@ -77,11 +22,9 @@ MMKeyCode keyCodeForChar(const char c){
|
|||||||
/* Generate table of keycodes and characters. */
|
/* Generate table of keycodes and characters. */
|
||||||
if (charToCodeDict == NULL) {
|
if (charToCodeDict == NULL) {
|
||||||
size_t i;
|
size_t i;
|
||||||
charToCodeDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
|
charToCodeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 128,
|
||||||
128,
|
&kCFCopyStringDictionaryKeyCallBacks, NULL);
|
||||||
&kCFCopyStringDictionaryKeyCallBacks,
|
if (charToCodeDict == NULL) { return K_NOT_A_KEY; }
|
||||||
NULL);
|
|
||||||
if (charToCodeDict == NULL) return K_NOT_A_KEY;
|
|
||||||
|
|
||||||
/* Loop through every keycode (0 - 127) to find its current mapping. */
|
/* Loop through every keycode (0 - 127) to find its current mapping. */
|
||||||
for (i = 0; i < 128; ++i) {
|
for (i = 0; i < 128; ++i) {
|
||||||
@ -94,20 +37,13 @@ MMKeyCode keyCodeForChar(const char c){
|
|||||||
}
|
}
|
||||||
|
|
||||||
charStr = CFStringCreateWithCharacters(kCFAllocatorDefault, &character, 1);
|
charStr = CFStringCreateWithCharacters(kCFAllocatorDefault, &character, 1);
|
||||||
|
|
||||||
/* Our values may be NULL (0), so we need to use this function. */
|
/* Our values may be NULL (0), so we need to use this function. */
|
||||||
if (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr,
|
if (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr, (const void **)&code)) {
|
||||||
(const void **)&code)) {
|
|
||||||
code = UINT16_MAX; /* Error */
|
code = UINT16_MAX; /* Error */
|
||||||
}
|
}
|
||||||
|
|
||||||
CFRelease(charStr);
|
CFRelease(charStr);
|
||||||
|
|
||||||
// TISGetInputSourceProperty may return nil so we need fallback
|
// TISGetInputSourceProperty may return nil so we need fallback
|
||||||
if (code == UINT16_MAX) {
|
|
||||||
code = keyCodeForCharFallBack(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (code == UINT16_MAX) {
|
if (code == UINT16_MAX) {
|
||||||
return K_NOT_A_KEY;
|
return K_NOT_A_KEY;
|
||||||
}
|
}
|
||||||
@ -122,20 +58,16 @@ MMKeyCode keyCodeForChar(const char c){
|
|||||||
|
|
||||||
return code;
|
return code;
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
MMKeyCode code;
|
|
||||||
|
|
||||||
char buf[2];
|
char buf[2];
|
||||||
buf[0] = c;
|
buf[0] = c;
|
||||||
buf[1] = '\0';
|
buf[1] = '\0';
|
||||||
|
|
||||||
code = XStringToKeysym(buf);
|
MMKeyCode code = XStringToKeysym(buf);
|
||||||
if (code == NoSymbol) {
|
if (code == NoSymbol) {
|
||||||
/* Some special keys are apparently not handled properly by
|
/* Some special keys are apparently not handled properly */
|
||||||
* XStringToKeysym() on some systems, so search for them instead in our
|
|
||||||
* mapping table. */
|
|
||||||
struct XSpecialCharacterMapping* xs = XSpecialCharacterTable;
|
struct XSpecialCharacterMapping* xs = XSpecialCharacterTable;
|
||||||
while (xs->name) {
|
while (xs->name) {
|
||||||
if (c == xs->name ) {
|
if (c == xs->name) {
|
||||||
code = xs->code;
|
code = xs->code;
|
||||||
//
|
//
|
||||||
break;
|
break;
|
||||||
@ -148,86 +80,33 @@ MMKeyCode keyCodeForChar(const char c){
|
|||||||
return K_NOT_A_KEY;
|
return K_NOT_A_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// x11 key bug
|
||||||
|
if (c == 60) {
|
||||||
|
code = 44;
|
||||||
|
}
|
||||||
return code;
|
return code;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
|
CFStringRef createStringForKey(CGKeyCode keyCode){
|
||||||
|
// TISInputSourceRef currentKeyboard = TISCopyCurrentASCIICapableKeyboardInputSource();
|
||||||
|
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardLayoutInputSource();
|
||||||
|
CFDataRef layoutData = (CFDataRef) TISGetInputSourceProperty(
|
||||||
|
currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
|
||||||
|
|
||||||
CFStringRef createStringForKey(CGKeyCode keyCode){
|
if (layoutData == nil) { return 0; }
|
||||||
TISInputSourceRef currentKeyboard = TISCopyCurrentASCIICapableKeyboardInputSource();
|
|
||||||
CFDataRef layoutData =
|
|
||||||
(CFDataRef)TISGetInputSourceProperty(currentKeyboard,
|
|
||||||
kTISPropertyUnicodeKeyLayoutData);
|
|
||||||
|
|
||||||
if (layoutData == nil) { return 0; }
|
const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *) CFDataGetBytePtr(layoutData);
|
||||||
|
UInt32 keysDown = 0;
|
||||||
|
UniChar chars[4];
|
||||||
|
UniCharCount realLength;
|
||||||
|
|
||||||
const UCKeyboardLayout *keyboardLayout =
|
UCKeyTranslate(keyboardLayout, keyCode, kUCKeyActionDisplay, 0, LMGetKbdType(),
|
||||||
(const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
|
kUCKeyTranslateNoDeadKeysBit, &keysDown,
|
||||||
|
sizeof(chars) / sizeof(chars[0]), &realLength, chars);
|
||||||
|
CFRelease(currentKeyboard);
|
||||||
|
|
||||||
UInt32 keysDown = 0;
|
return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1);
|
||||||
UniChar chars[4];
|
|
||||||
UniCharCount realLength;
|
|
||||||
|
|
||||||
UCKeyTranslate(keyboardLayout,
|
|
||||||
keyCode,
|
|
||||||
kUCKeyActionDisplay,
|
|
||||||
0,
|
|
||||||
LMGetKbdType(),
|
|
||||||
kUCKeyTranslateNoDeadKeysBit,
|
|
||||||
&keysDown,
|
|
||||||
sizeof(chars) / sizeof(chars[0]),
|
|
||||||
&realLength,
|
|
||||||
chars);
|
|
||||||
CFRelease(currentKeyboard);
|
|
||||||
|
|
||||||
return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
MMKeyCode keyCodeForCharFallBack(const char c) {
|
|
||||||
switch (c) {
|
|
||||||
case 'A': return kVK_ANSI_A;
|
|
||||||
case 'B': return kVK_ANSI_B;
|
|
||||||
case 'C': return kVK_ANSI_C;
|
|
||||||
case 'D': return kVK_ANSI_D;
|
|
||||||
case 'E': return kVK_ANSI_E;
|
|
||||||
case 'F': return kVK_ANSI_F;
|
|
||||||
case 'G': return kVK_ANSI_G;
|
|
||||||
case 'H': return kVK_ANSI_H;
|
|
||||||
case 'I': return kVK_ANSI_I;
|
|
||||||
case 'J': return kVK_ANSI_J;
|
|
||||||
case 'K': return kVK_ANSI_K;
|
|
||||||
case 'L': return kVK_ANSI_L;
|
|
||||||
case 'M': return kVK_ANSI_M;
|
|
||||||
case 'N': return kVK_ANSI_N;
|
|
||||||
case 'O': return kVK_ANSI_O;
|
|
||||||
case 'P': return kVK_ANSI_P;
|
|
||||||
case 'Q': return kVK_ANSI_Q;
|
|
||||||
case 'R': return kVK_ANSI_R;
|
|
||||||
case 'S': return kVK_ANSI_S;
|
|
||||||
case 'T': return kVK_ANSI_T;
|
|
||||||
case 'U': return kVK_ANSI_U;
|
|
||||||
case 'V': return kVK_ANSI_V;
|
|
||||||
case 'W': return kVK_ANSI_W;
|
|
||||||
case 'X': return kVK_ANSI_X;
|
|
||||||
case 'Y': return kVK_ANSI_Y;
|
|
||||||
case 'Z': return kVK_ANSI_Z;
|
|
||||||
|
|
||||||
|
|
||||||
case '0': return kVK_ANSI_0;
|
|
||||||
case '1': return kVK_ANSI_1;
|
|
||||||
case '2': return kVK_ANSI_2;
|
|
||||||
case '3': return kVK_ANSI_3;
|
|
||||||
case '4': return kVK_ANSI_4;
|
|
||||||
case '5': return kVK_ANSI_5;
|
|
||||||
case '6': return kVK_ANSI_6;
|
|
||||||
case '7': return kVK_ANSI_7;
|
|
||||||
case '8': return kVK_ANSI_8;
|
|
||||||
case '9': return kVK_ANSI_9;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return K_NOT_A_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,22 +2,14 @@
|
|||||||
#ifndef KEYPRESS_H
|
#ifndef KEYPRESS_H
|
||||||
#define KEYPRESS_H
|
#define KEYPRESS_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include "../base/os.h"
|
#include "../base/os.h"
|
||||||
|
#include "../base/types.h"
|
||||||
|
|
||||||
#include "keycode.h"
|
#include "keycode.h"
|
||||||
|
#include <stdbool.h>
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#include "../base/ms_stdbool.h"
|
|
||||||
#else
|
|
||||||
#include <stdbool.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MOD_NONE = 0,
|
MOD_NONE = 0,
|
||||||
MOD_META = kCGEventFlagMaskCommand,
|
MOD_META = kCGEventFlagMaskCommand,
|
||||||
@ -25,9 +17,7 @@ extern "C"
|
|||||||
MOD_CONTROL = kCGEventFlagMaskControl,
|
MOD_CONTROL = kCGEventFlagMaskControl,
|
||||||
MOD_SHIFT = kCGEventFlagMaskShift
|
MOD_SHIFT = kCGEventFlagMaskShift
|
||||||
} MMKeyFlags;
|
} MMKeyFlags;
|
||||||
|
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
|
|
||||||
enum _MMKeyFlags {
|
enum _MMKeyFlags {
|
||||||
MOD_NONE = 0,
|
MOD_NONE = 0,
|
||||||
MOD_META = Mod4Mask,
|
MOD_META = Mod4Mask,
|
||||||
@ -35,11 +25,8 @@ extern "C"
|
|||||||
MOD_CONTROL = ControlMask,
|
MOD_CONTROL = ControlMask,
|
||||||
MOD_SHIFT = ShiftMask
|
MOD_SHIFT = ShiftMask
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef unsigned int MMKeyFlags;
|
typedef unsigned int MMKeyFlags;
|
||||||
|
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
|
|
||||||
enum _MMKeyFlags {
|
enum _MMKeyFlags {
|
||||||
MOD_NONE = 0,
|
MOD_NONE = 0,
|
||||||
/* These are already defined by the Win32 API */
|
/* These are already defined by the Win32 API */
|
||||||
@ -48,44 +35,12 @@ extern "C"
|
|||||||
MOD_SHIFT = 0, */
|
MOD_SHIFT = 0, */
|
||||||
MOD_META = MOD_WIN
|
MOD_META = MOD_WIN
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef unsigned int MMKeyFlags;
|
typedef unsigned int MMKeyFlags;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(IS_WINDOWS)
|
#if defined(IS_WINDOWS)
|
||||||
/* Send win32 key event for given key. */
|
/* Send win32 key event for given key. */
|
||||||
void win32KeyEvent(int key, MMKeyFlags flags);
|
void win32KeyEvent(int key, MMKeyFlags flags, uintptr pid, int8_t isPid);
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Toggles the given key down or up. */
|
|
||||||
void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags);
|
|
||||||
|
|
||||||
/* Toggles the key down and then up. */
|
|
||||||
void tapKeyCode(MMKeyCode code, MMKeyFlags flags);
|
|
||||||
|
|
||||||
/* Toggles the key corresponding to the given UTF character up or down. */
|
|
||||||
void toggleKey(char c, const bool down, MMKeyFlags flags);
|
|
||||||
void tapKey(char c, MMKeyFlags flags);
|
|
||||||
|
|
||||||
/* Sends a UTF-8 string without modifiers. */
|
|
||||||
void typeString(const char *str);
|
|
||||||
/* Sends a Unicode character without modifiers. */
|
|
||||||
void unicodeType(const unsigned value);
|
|
||||||
|
|
||||||
/* Macro to convert WPM to CPM integers.
|
|
||||||
* (the average English word length is 5.1 characters.) */
|
|
||||||
#define WPM_TO_CPM(WPM) (unsigned)(5.1 * WPM)
|
|
||||||
|
|
||||||
/* Sends UTF-8 string without modifiers and
|
|
||||||
* with partially random delays between each letter.
|
|
||||||
* Note that deadbeef_srand() must be called before this function
|
|
||||||
* if you actually want randomness.
|
|
||||||
* */
|
|
||||||
void typeStringDelayed(const char *str, const unsigned cpm);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* KEYPRESS_H */
|
#endif /* KEYPRESS_H */
|
||||||
|
463
key/keypress_c.h
463
key/keypress_c.h
@ -1,9 +1,19 @@
|
|||||||
#include "keypress.h"
|
// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
|
||||||
// #include "../base/deadbeef_rand_c.h"
|
// file at the top-level directory of this distribution and at
|
||||||
|
// https://github.com/go-vgo/robotgo/blob/master/LICENSE
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#include "../base/deadbeef_rand_c.h"
|
||||||
#include "../base/microsleep.h"
|
#include "../base/microsleep.h"
|
||||||
|
#include "keypress.h"
|
||||||
|
#include "keycode_c.h"
|
||||||
|
|
||||||
#include <ctype.h> /* For isupper() */
|
#include <ctype.h> /* For isupper() */
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
#include <ApplicationServices/ApplicationServices.h>
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
#import <IOKit/hidsystem/IOHIDLib.h>
|
#import <IOKit/hidsystem/IOHIDLib.h>
|
||||||
@ -15,115 +25,147 @@
|
|||||||
|
|
||||||
/* Convenience wrappers around ugly APIs. */
|
/* Convenience wrappers around ugly APIs. */
|
||||||
#if defined(IS_WINDOWS)
|
#if defined(IS_WINDOWS)
|
||||||
#define WIN32_KEY_EVENT_WAIT(key, flags) \
|
HWND GetHwndByPid(DWORD dwProcessId);
|
||||||
(win32KeyEvent(key, flags), Sleep(DEADBEEF_RANDRANGE(0, 1)))
|
|
||||||
|
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)
|
#elif defined(USE_X11)
|
||||||
#define X_KEY_EVENT(display, key, is_press) \
|
Display *XGetMainDisplay(void);
|
||||||
(XTestFakeKeyEvent(display, \
|
|
||||||
XKeysymToKeycode(display, key), \
|
void X_KEY_EVENT(Display *display, MMKeyCode key, bool is_press) {
|
||||||
is_press, CurrentTime), \
|
XTestFakeKeyEvent(display, XKeysymToKeycode(display, key), is_press, CurrentTime);
|
||||||
XSync(display, false))
|
XSync(display, false);
|
||||||
#define X_KEY_EVENT_WAIT(display, key, is_press) \
|
}
|
||||||
(X_KEY_EVENT(display, key, is_press), \
|
|
||||||
microsleep(DEADBEEF_UNIFORM(0.0, 0.5)))
|
void X_KEY_EVENT_WAIT(Display *display, MMKeyCode key, bool is_press) {
|
||||||
|
X_KEY_EVENT(display, key, is_press);
|
||||||
|
microsleep(DEADBEEF_UNIFORM(0.0, 0.5));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
static io_connect_t _getAuxiliaryKeyDriver(void){
|
int SendTo(uintptr pid, CGEventRef event) {
|
||||||
static mach_port_t sEventDrvrRef = 0;
|
if (pid != 0) {
|
||||||
mach_port_t masterPort, service, iter;
|
CGEventPostToPid(pid, event);
|
||||||
kern_return_t kr;
|
} else {
|
||||||
|
CGEventPost(kCGHIDEventTap, event);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFRelease(event);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the scan code for keyup */
|
static io_connect_t _getAuxiliaryKeyDriver(void) {
|
||||||
// if ( flags & KEYEVENTF_KEYUP ) {
|
static mach_port_t sEventDrvrRef = 0;
|
||||||
// scan |= 0x80;
|
mach_port_t masterPort, service, iter;
|
||||||
// }
|
kern_return_t kr;
|
||||||
|
|
||||||
// keybd_event(key, scan, flags, 0);
|
if (!sEventDrvrRef) {
|
||||||
|
kr = IOMasterPort(bootstrap_port, &masterPort);
|
||||||
INPUT keyInput;
|
assert(KERN_SUCCESS == kr);
|
||||||
|
kr = IOServiceGetMatchingServices(masterPort, IOServiceMatching(kIOHIDSystemClass), &iter);
|
||||||
|
assert(KERN_SUCCESS == kr);
|
||||||
|
|
||||||
keyInput.type = INPUT_KEYBOARD;
|
service = IOIteratorNext(iter);
|
||||||
keyInput.ki.wVk = key;
|
assert(service);
|
||||||
keyInput.ki.wScan = scan;
|
|
||||||
keyInput.ki.dwFlags = flags;
|
kr = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &sEventDrvrRef);
|
||||||
keyInput.ki.time = 0;
|
assert(KERN_SUCCESS == kr);
|
||||||
keyInput.ki.dwExtraInfo = 0;
|
|
||||||
SendInput(1, &keyInput, sizeof(keyInput));
|
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
|
#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)
|
#if defined(IS_MACOSX)
|
||||||
/* The media keys all have 1000 added to them to help us detect them. */
|
/* The media keys all have 1000 added to them to help us detect them. */
|
||||||
if (code >= 1000) {
|
if (code >= 1000) {
|
||||||
code = code - 1000; /* Get the real keycode. */
|
code = code - 1000; /* Get the real keycode. */
|
||||||
NXEventData event;
|
NXEventData event;
|
||||||
kern_return_t kr;
|
kern_return_t kr;
|
||||||
|
|
||||||
IOGPoint loc = { 0, 0 };
|
IOGPoint loc = { 0, 0 };
|
||||||
@ -133,49 +175,51 @@ void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags){
|
|||||||
event.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
|
event.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
|
||||||
event.compound.misc.L[0] = evtInfo;
|
event.compound.misc.L[0] = evtInfo;
|
||||||
|
|
||||||
kr = IOHIDPostEvent( _getAuxiliaryKeyDriver(),
|
kr = IOHIDPostEvent(_getAuxiliaryKeyDriver(),
|
||||||
NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE );
|
NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE);
|
||||||
assert( KERN_SUCCESS == kr );
|
assert(KERN_SUCCESS == kr);
|
||||||
} else {
|
} else {
|
||||||
CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL,
|
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||||
(CGKeyCode)code, down);
|
CGEventRef keyEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)code, down);
|
||||||
assert(keyEvent != NULL);
|
assert(keyEvent != NULL);
|
||||||
|
|
||||||
CGEventSetType(keyEvent, down ? kCGEventKeyDown : kCGEventKeyUp);
|
CGEventSetType(keyEvent, down ? kCGEventKeyDown : kCGEventKeyUp);
|
||||||
// CGEventSetFlags(keyEvent, flags);
|
if (flags != 0) {
|
||||||
CGEventSetFlags(keyEvent, (int) flags);
|
CGEventSetFlags(keyEvent, (CGEventFlags) flags);
|
||||||
CGEventPost(kCGSessionEventTap, keyEvent);
|
}
|
||||||
CFRelease(keyEvent);
|
|
||||||
|
SendTo(pid, keyEvent);
|
||||||
|
CFRelease(source);
|
||||||
}
|
}
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
const DWORD dwFlags = down ? 0 : KEYEVENTF_KEYUP;
|
const DWORD dwFlags = down ? 0 : KEYEVENTF_KEYUP;
|
||||||
|
|
||||||
/* Parse modifier keys. */
|
/* Parse modifier keys. */
|
||||||
if (flags & MOD_META) WIN32_KEY_EVENT_WAIT(K_META, dwFlags);
|
if (flags & MOD_META) { WIN32_KEY_EVENT_WAIT(K_META, dwFlags, pid); }
|
||||||
if (flags & MOD_ALT) WIN32_KEY_EVENT_WAIT(K_ALT, dwFlags);
|
if (flags & MOD_ALT) { WIN32_KEY_EVENT_WAIT(K_ALT, dwFlags, pid); }
|
||||||
if (flags & MOD_CONTROL) WIN32_KEY_EVENT_WAIT(K_CONTROL, dwFlags);
|
if (flags & MOD_CONTROL) { WIN32_KEY_EVENT_WAIT(K_CONTROL, dwFlags, pid); }
|
||||||
if (flags & MOD_SHIFT) WIN32_KEY_EVENT_WAIT(K_SHIFT, dwFlags);
|
if (flags & MOD_SHIFT) { WIN32_KEY_EVENT_WAIT(K_SHIFT, dwFlags, pid); }
|
||||||
|
|
||||||
win32KeyEvent(code, dwFlags);
|
win32KeyEvent(code, dwFlags, pid, 0);
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
Display *display = XGetMainDisplay();
|
Display *display = XGetMainDisplay();
|
||||||
const Bool is_press = down ? True : False; /* Just to be safe. */
|
const Bool is_press = down ? True : False; /* Just to be safe. */
|
||||||
|
|
||||||
/* Parse modifier keys. */
|
/* Parse modifier keys. */
|
||||||
if (flags & MOD_META) X_KEY_EVENT_WAIT(display, K_META, is_press);
|
if (flags & MOD_META) { X_KEY_EVENT_WAIT(display, K_META, is_press); }
|
||||||
if (flags & MOD_ALT) X_KEY_EVENT_WAIT(display, K_ALT, is_press);
|
if (flags & MOD_ALT) { X_KEY_EVENT_WAIT(display, K_ALT, is_press); }
|
||||||
if (flags & MOD_CONTROL) X_KEY_EVENT_WAIT(display, K_CONTROL, is_press);
|
if (flags & MOD_CONTROL) { X_KEY_EVENT_WAIT(display, K_CONTROL, is_press); }
|
||||||
if (flags & MOD_SHIFT) X_KEY_EVENT_WAIT(display, K_SHIFT, is_press);
|
if (flags & MOD_SHIFT) { X_KEY_EVENT_WAIT(display, K_SHIFT, is_press); }
|
||||||
|
|
||||||
X_KEY_EVENT(display, code, is_press);
|
X_KEY_EVENT(display, code, is_press);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void tapKeyCode(MMKeyCode code, MMKeyFlags flags){
|
// void tapKeyCode(MMKeyCode code, MMKeyFlags flags){
|
||||||
toggleKeyCode(code, true, flags);
|
// toggleKeyCode(code, true, flags);
|
||||||
microsleep(5.0);
|
// microsleep(5.0);
|
||||||
toggleKeyCode(code, false, flags);
|
// toggleKeyCode(code, false, flags);
|
||||||
}
|
// }
|
||||||
|
|
||||||
#if defined(USE_X11)
|
#if defined(USE_X11)
|
||||||
bool toUpper(char c) {
|
bool toUpper(char c) {
|
||||||
@ -194,14 +238,9 @@ void tapKeyCode(MMKeyCode code, MMKeyFlags flags){
|
|||||||
}
|
}
|
||||||
#endif
|
#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);
|
MMKeyCode keyCode = keyCodeForChar(c);
|
||||||
|
|
||||||
//Prevent unused variable warning for Mac and Linux.
|
|
||||||
#if defined(IS_WINDOWS)
|
|
||||||
int modifiers;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(USE_X11)
|
#if defined(USE_X11)
|
||||||
if (toUpper(c) && !(flags & MOD_SHIFT)) {
|
if (toUpper(c) && !(flags & MOD_SHIFT)) {
|
||||||
flags |= MOD_SHIFT; /* Not sure if this is safe for all layouts. */
|
flags |= MOD_SHIFT; /* Not sure if this is safe for all layouts. */
|
||||||
@ -213,87 +252,62 @@ void toggleKey(char c, const bool down, MMKeyFlags flags){
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(IS_WINDOWS)
|
#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 & 1) != 0) { flags |= MOD_SHIFT; } // Uptdate flags from keycode modifiers.
|
||||||
if ((modifiers & 4) != 0) flags |= MOD_ALT;
|
if ((modifiers & 2) != 0) { flags |= MOD_CONTROL; }
|
||||||
|
if ((modifiers & 4) != 0) { flags |= MOD_ALT; }
|
||||||
keyCode = keyCode & 0xff; // Mask out modifiers.
|
keyCode = keyCode & 0xff; // Mask out modifiers.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
toggleKeyCode(keyCode, down, flags);
|
toggleKeyCode(keyCode, down, flags, pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tapKey(char c, MMKeyFlags flags){
|
// void tapKey(char c, MMKeyFlags flags){
|
||||||
toggleKey(c, true, flags);
|
// toggleKey(c, true, flags);
|
||||||
microsleep(5.0);
|
// microsleep(5.0);
|
||||||
toggleKey(c, false, flags);
|
// toggleKey(c, false, flags);
|
||||||
}
|
// }
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
void toggleUnicode(UniChar ch, const bool down){
|
void toggleUnicode(UniChar ch, const bool down, uintptr pid) {
|
||||||
/* This function relies on the convenient
|
/* This function relies on the convenient CGEventKeyboardSetUnicodeString(),
|
||||||
* CGEventKeyboardSetUnicodeString(), which allows us to not have to
|
convert characters to a keycode, but does not support adding modifier flags.
|
||||||
* convert characters to a keycode, but does not support adding modifier
|
It is only used in typeString().
|
||||||
* flags. It is therefore only used in typeStringDelayed()
|
-- if you need modifier keys, use the above functions instead. */
|
||||||
* -- if you need modifier keys, use the above functions instead. */
|
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||||
CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, 0, down);
|
CGEventRef keyEvent = CGEventCreateKeyboardEvent(source, 0, down);
|
||||||
if (keyEvent == NULL) {
|
if (keyEvent == NULL) {
|
||||||
fputs("Could not create keyboard event.\n", stderr);
|
fputs("Could not create keyboard event.\n", stderr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGEventKeyboardSetUnicodeString(keyEvent, 1, &ch);
|
CGEventKeyboardSetUnicodeString(keyEvent, 1, &ch);
|
||||||
|
|
||||||
CGEventPost(kCGSessionEventTap, keyEvent);
|
SendTo(pid, keyEvent);
|
||||||
CFRelease(keyEvent);
|
CFRelease(source);
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(USE_X11)
|
|
||||||
#define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE)
|
|
||||||
|
|
||||||
int input_utf(const char *utf) {
|
|
||||||
Display *dpy;
|
|
||||||
dpy = XOpenDisplay(NULL);
|
|
||||||
|
|
||||||
KeySym sym = XStringToKeysym(utf);
|
|
||||||
// KeySym sym = XKeycodeToKeysym(dpy, utf);
|
|
||||||
|
|
||||||
int min, max, numcodes;
|
|
||||||
XDisplayKeycodes(dpy, &min, &max);
|
|
||||||
KeySym *keysym;
|
|
||||||
keysym = XGetKeyboardMapping(dpy, min, max-min+1, &numcodes);
|
|
||||||
keysym[(max-min-1)*numcodes] = sym;
|
|
||||||
XChangeKeyboardMapping(dpy, min, numcodes, keysym, (max-min));
|
|
||||||
XFree(keysym);
|
|
||||||
XFlush(dpy);
|
|
||||||
|
|
||||||
KeyCode code = XKeysymToKeycode(dpy, sym);
|
|
||||||
|
|
||||||
XTestFakeKeyEvent(dpy, code, True, 1);
|
|
||||||
XTestFakeKeyEvent(dpy, code, False, 1);
|
|
||||||
|
|
||||||
XFlush(dpy);
|
|
||||||
XCloseDisplay(dpy);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if !defined(USE_X11)
|
|
||||||
int input_utf(const char *utf){
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
#define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE, 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// unicode type
|
// unicode type
|
||||||
void unicodeType(const unsigned value){
|
void unicodeType(const unsigned value, uintptr pid, int8_t isPid) {
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
UniChar ch = (UniChar)value; // Convert to unsigned char
|
UniChar ch = (UniChar)value; // Convert to unsigned char
|
||||||
|
|
||||||
toggleUnicode(ch, true);
|
toggleUnicode(ch, true, pid);
|
||||||
microsleep(5.0);
|
microsleep(5.0);
|
||||||
toggleUnicode(ch, false);
|
toggleUnicode(ch, false, pid);
|
||||||
#elif defined(IS_WINDOWS)
|
#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];
|
INPUT input[2];
|
||||||
memset(input, 0, sizeof(input));
|
memset(input, 0, sizeof(input));
|
||||||
|
|
||||||
@ -315,50 +329,31 @@ void unicodeType(const unsigned value){
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: removed
|
#if defined(USE_X11)
|
||||||
void typeStringDelayed(const char *str, const unsigned cpm){
|
int input_utf(const char *utf) {
|
||||||
|
Display *dpy = XOpenDisplay(NULL);
|
||||||
/* Characters per second */
|
KeySym sym = XStringToKeysym(utf);
|
||||||
const double cps = (double)cpm / 60.0;
|
// KeySym sym = XKeycodeToKeysym(dpy, utf);
|
||||||
|
|
||||||
/* Average milli-seconds per character */
|
int min, max, numcodes;
|
||||||
const double mspc = (cps == 0.0) ? 0.0 : 1000.0 / cps;
|
XDisplayKeycodes(dpy, &min, &max);
|
||||||
|
KeySym *keysym;
|
||||||
|
keysym = XGetKeyboardMapping(dpy, min, max-min+1, &numcodes);
|
||||||
|
keysym[(max-min-1)*numcodes] = sym;
|
||||||
|
XChangeKeyboardMapping(dpy, min, numcodes, keysym, (max-min));
|
||||||
|
XFree(keysym);
|
||||||
|
XFlush(dpy);
|
||||||
|
|
||||||
unsigned long n;
|
KeyCode code = XKeysymToKeycode(dpy, sym);
|
||||||
unsigned short c;
|
XTestFakeKeyEvent(dpy, code, True, 1);
|
||||||
unsigned short c1;
|
XTestFakeKeyEvent(dpy, code, False, 1);
|
||||||
unsigned short c2;
|
|
||||||
unsigned short c3;
|
|
||||||
|
|
||||||
while (*str != '\0') {
|
XFlush(dpy);
|
||||||
c = *str++;
|
XCloseDisplay(dpy);
|
||||||
|
return 0;
|
||||||
// warning, the following utf8 decoder
|
|
||||||
// doesn't perform validation
|
|
||||||
if (c <= 0x7F) {
|
|
||||||
// 0xxxxxxx one byte
|
|
||||||
n = c;
|
|
||||||
} else if ((c & 0xE0) == 0xC0) {
|
|
||||||
// 110xxxxx two bytes
|
|
||||||
c1 = (*str++) & 0x3F;
|
|
||||||
n = ((c & 0x1F) << 6) | c1;
|
|
||||||
} else if ((c & 0xF0) == 0xE0) {
|
|
||||||
// 1110xxxx three bytes
|
|
||||||
c1 = (*str++) & 0x3F;
|
|
||||||
c2 = (*str++) & 0x3F;
|
|
||||||
n = ((c & 0x0F) << 12) | (c1 << 6) | c2;
|
|
||||||
} else if ((c & 0xF8) == 0xF0) {
|
|
||||||
// 11110xxx four bytes
|
|
||||||
c1 = (*str++) & 0x3F;
|
|
||||||
c2 = (*str++) & 0x3F;
|
|
||||||
c3 = (*str++) & 0x3F;
|
|
||||||
n = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3;
|
|
||||||
}
|
|
||||||
|
|
||||||
unicodeType(n);
|
|
||||||
|
|
||||||
if (mspc > 0) {
|
|
||||||
microsleep(mspc + (DEADBEEF_UNIFORM(0.0, 0.5)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
#else
|
||||||
|
int input_utf(const char *utf){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
11
keycode.go
11
keycode.go
@ -19,6 +19,17 @@ type uMap map[string]uint16
|
|||||||
// MouseMap robotgo hook mouse's code map
|
// MouseMap robotgo hook mouse's code map
|
||||||
var MouseMap = keycode.MouseMap
|
var MouseMap = keycode.MouseMap
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Mleft mouse left button
|
||||||
|
Mleft = "left"
|
||||||
|
Mright = "right"
|
||||||
|
Center = "center"
|
||||||
|
WheelDown = "wheelDown"
|
||||||
|
WheelUp = "wheelUp"
|
||||||
|
WheelLeft = "wheelLeft"
|
||||||
|
WheelRight = "wheelRight"
|
||||||
|
)
|
||||||
|
|
||||||
// Keycode robotgo hook key's code map
|
// Keycode robotgo hook key's code map
|
||||||
var Keycode = keycode.Keycode
|
var Keycode = keycode.Keycode
|
||||||
|
|
||||||
|
106
mouse/goMouse.h
106
mouse/goMouse.h
@ -1,106 +0,0 @@
|
|||||||
// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// https://github.com/go-vgo/robotgo/blob/master/LICENSE
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
#include "../base/types.h"
|
|
||||||
#include "mouse_c.h"
|
|
||||||
|
|
||||||
// Global delays.
|
|
||||||
int mouseDelay = 0;
|
|
||||||
|
|
||||||
int move_mouse(int32_t x, int32_t y){
|
|
||||||
MMPointInt32 point;
|
|
||||||
point = MMPointInt32Make(x, y);
|
|
||||||
moveMouse(point);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int drag_mouse(int32_t x, int32_t y, MMMouseButton button){
|
|
||||||
MMPointInt32 point;
|
|
||||||
point = MMPointInt32Make(x, y);
|
|
||||||
dragMouse(point, button);
|
|
||||||
microsleep(mouseDelay);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool move_mouse_smooth(int32_t x, int32_t y, double lowSpeed,
|
|
||||||
double highSpeed, int msDelay){
|
|
||||||
MMPointInt32 point;
|
|
||||||
point = MMPointInt32Make(x, y);
|
|
||||||
|
|
||||||
bool cbool = smoothlyMoveMouse(point, lowSpeed, highSpeed);
|
|
||||||
microsleep(msDelay);
|
|
||||||
|
|
||||||
return cbool;
|
|
||||||
}
|
|
||||||
|
|
||||||
MMPointInt32 get_mouse_pos(){
|
|
||||||
MMPointInt32 pos = getMousePos();
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mouse_click(MMMouseButton button, bool doubleC){
|
|
||||||
if (!doubleC) {
|
|
||||||
clickMouse(button);
|
|
||||||
} else {
|
|
||||||
doubleClick(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
microsleep(mouseDelay);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mouse_toggle(char* d, MMMouseButton button){
|
|
||||||
bool down = false;
|
|
||||||
if (strcmp(d, "down") == 0) {
|
|
||||||
down = true;
|
|
||||||
} else if (strcmp(d, "up") == 0) {
|
|
||||||
down = false;
|
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleMouse(down, button);
|
|
||||||
microsleep(mouseDelay);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int set_mouse_delay(size_t val){
|
|
||||||
mouseDelay = val;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int scroll(int x, int y, int msDelay){
|
|
||||||
scrollMouseXY(x, y);
|
|
||||||
microsleep(msDelay);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int scroll_mouse(size_t scrollMagnitude, char *s){
|
|
||||||
MMMouseWheelDirection scrollDirection;
|
|
||||||
|
|
||||||
if (strcmp(s, "up") == 0) {
|
|
||||||
scrollDirection = DIRECTION_UP;
|
|
||||||
} else if (strcmp(s, "down") == 0) {
|
|
||||||
scrollDirection = DIRECTION_DOWN;
|
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollMouse(scrollMagnitude, scrollDirection);
|
|
||||||
microsleep(mouseDelay);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
11
mouse/mouse.go
Normal file
11
mouse/mouse.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// 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 mouse
|
@ -4,24 +4,10 @@
|
|||||||
|
|
||||||
#include "../base/os.h"
|
#include "../base/os.h"
|
||||||
#include "../base/types.h"
|
#include "../base/types.h"
|
||||||
|
#include <stdbool.h>
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#include "../base/ms_stdbool.h"
|
|
||||||
#else
|
|
||||||
#include <stdbool.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
// #ifdefined(__cplusplus)||defined(c_plusplus)
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
|
|
||||||
// #include </System/Library/Frameworks/ApplicationServices.framework/Headers/ApplicationServices.h>
|
|
||||||
#include <ApplicationServices/ApplicationServices.h>
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
// #include </System/Library/Frameworks/ApplicationServices.framework/Versions/A/Headers/ApplicationServices.h>
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LEFT_BUTTON = kCGMouseButtonLeft,
|
LEFT_BUTTON = kCGMouseButtonLeft,
|
||||||
@ -32,9 +18,7 @@ extern "C"
|
|||||||
WheelLeft = 6,
|
WheelLeft = 6,
|
||||||
WheelRight = 7,
|
WheelRight = 7,
|
||||||
} MMMouseButton;
|
} MMMouseButton;
|
||||||
|
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
|
|
||||||
enum _MMMouseButton {
|
enum _MMMouseButton {
|
||||||
LEFT_BUTTON = 1,
|
LEFT_BUTTON = 1,
|
||||||
CENTER_BUTTON = 2,
|
CENTER_BUTTON = 2,
|
||||||
@ -45,9 +29,7 @@ extern "C"
|
|||||||
WheelRight = 7,
|
WheelRight = 7,
|
||||||
};
|
};
|
||||||
typedef unsigned int MMMouseButton;
|
typedef unsigned int MMMouseButton;
|
||||||
|
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
|
|
||||||
enum _MMMouseButton {
|
enum _MMMouseButton {
|
||||||
LEFT_BUTTON = 1,
|
LEFT_BUTTON = 1,
|
||||||
CENTER_BUTTON = 2,
|
CENTER_BUTTON = 2,
|
||||||
@ -58,62 +40,8 @@ extern "C"
|
|||||||
WheelRight = 7,
|
WheelRight = 7,
|
||||||
};
|
};
|
||||||
typedef unsigned int MMMouseButton;
|
typedef unsigned int MMMouseButton;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error "No mouse button constants set for platform"
|
#error "No mouse button constants set for platform"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MMMouseButtonIsValid(button) \
|
|
||||||
(button == LEFT_BUTTON || button == RIGHT_BUTTON || \
|
|
||||||
button == CENTER_BUTTON || button == WheelDown || \
|
|
||||||
button == WheelUp || button == WheelLeft || \
|
|
||||||
button == WheelRight)
|
|
||||||
|
|
||||||
enum __MMMouseWheelDirection {
|
|
||||||
DIRECTION_DOWN = -1,
|
|
||||||
DIRECTION_UP = 1
|
|
||||||
};
|
|
||||||
typedef int MMMouseWheelDirection;
|
|
||||||
|
|
||||||
/* Immediately moves the mouse to the given point on-screen.
|
|
||||||
* It is up to the caller to ensure that this point is within the
|
|
||||||
* screen boundaries. */
|
|
||||||
void moveMouse(MMPointInt32 point);
|
|
||||||
|
|
||||||
/* Like moveMouse, moves the mouse to the given point on-screen, but marks
|
|
||||||
* the event as the mouse being dragged on platforms where it is supported.
|
|
||||||
* It is up to the caller to ensure that this point is within the screen
|
|
||||||
* boundaries. */
|
|
||||||
void dragMouse(MMPointInt32 point, const MMMouseButton button);
|
|
||||||
|
|
||||||
/* Smoothly moves the mouse from the current position to the given point.
|
|
||||||
* deadbeef_srand() should be called before using this function.
|
|
||||||
*
|
|
||||||
* Returns false if unsuccessful (i.e. a point was hit that is outside of the
|
|
||||||
* screen boundaries), or true if successful. */
|
|
||||||
bool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed);
|
|
||||||
// bool smoothlyMoveMouse(MMPoint point);
|
|
||||||
|
|
||||||
/* Returns the coordinates of the mouse on the current screen. */
|
|
||||||
MMPointInt32 getMousePos(void);
|
|
||||||
|
|
||||||
/* Holds down or releases the mouse with the given button in the current
|
|
||||||
* position. */
|
|
||||||
void toggleMouse(bool down, MMMouseButton button);
|
|
||||||
|
|
||||||
/* Clicks the mouse with the given button in the current position. */
|
|
||||||
void clickMouse(MMMouseButton button);
|
|
||||||
|
|
||||||
/* Double clicks the mouse with the given button. */
|
|
||||||
void doubleClick(MMMouseButton button);
|
|
||||||
|
|
||||||
/* Scrolls the mouse in the stated direction.
|
|
||||||
* TODO: Add a smoothly scroll mouse next. */
|
|
||||||
void scrollMouse(int scrollMagnitude, MMMouseWheelDirection scrollDirection);
|
|
||||||
|
|
||||||
//#ifdefined(__cplusplus)||defined(c_plusplus)
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* MOUSE_H */
|
#endif /* MOUSE_H */
|
327
mouse/mouse_c.h
327
mouse/mouse_c.h
@ -1,12 +1,8 @@
|
|||||||
#include "mouse.h"
|
#include "mouse.h"
|
||||||
// #include "../screen/screen.h"
|
#include "../base/deadbeef_rand.h"
|
||||||
// #include "../screen/screen_c.h"
|
|
||||||
#include "../base/deadbeef_rand_c.h"
|
|
||||||
// #include "../deadbeef_rand.h"
|
|
||||||
#include "../base/microsleep.h"
|
#include "../base/microsleep.h"
|
||||||
|
|
||||||
#include <math.h> /* For floor() */
|
#include <math.h> /* For floor() */
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
// #include </System/Library/Frameworks/ApplicationServices.framework/Headers/ApplicationServices.h>
|
// #include </System/Library/Frameworks/ApplicationServices.framework/Headers/ApplicationServices.h>
|
||||||
#include <ApplicationServices/ApplicationServices.h>
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
@ -15,136 +11,115 @@
|
|||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/extensions/XTest.h>
|
#include <X11/extensions/XTest.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
// #include "../base/xdisplay_c.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(M_SQRT2)
|
|
||||||
#define M_SQRT2 1.4142135623730950488016887 /* Fix for MSVC. */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Some convenience macros for converting our enums to the system API types. */
|
/* Some convenience macros for converting our enums to the system API types. */
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
|
CGEventType MMMouseDownToCGEventType(MMMouseButton button) {
|
||||||
|
if (button == LEFT_BUTTON) {
|
||||||
|
return kCGEventLeftMouseDown;
|
||||||
|
}
|
||||||
|
if (button == RIGHT_BUTTON) {
|
||||||
|
return kCGEventRightMouseDown;
|
||||||
|
}
|
||||||
|
return kCGEventOtherMouseDown;
|
||||||
|
}
|
||||||
|
|
||||||
#define MMMouseToCGEventType(down, button) \
|
CGEventType MMMouseUpToCGEventType(MMMouseButton button) {
|
||||||
(down ? MMMouseDownToCGEventType(button) : MMMouseUpToCGEventType(button))
|
if (button == LEFT_BUTTON) { return kCGEventLeftMouseUp; }
|
||||||
|
if (button == RIGHT_BUTTON) { return kCGEventRightMouseUp; }
|
||||||
|
return kCGEventOtherMouseUp;
|
||||||
|
}
|
||||||
|
|
||||||
#define MMMouseDownToCGEventType(button) \
|
CGEventType MMMouseDragToCGEventType(MMMouseButton button) {
|
||||||
((button) == (LEFT_BUTTON) ? kCGEventLeftMouseDown \
|
if (button == LEFT_BUTTON) { return kCGEventLeftMouseDragged; }
|
||||||
: ((button) == RIGHT_BUTTON ? kCGEventRightMouseDown \
|
if (button == RIGHT_BUTTON) { return kCGEventRightMouseDragged; }
|
||||||
: kCGEventOtherMouseDown))
|
return kCGEventOtherMouseDragged;
|
||||||
|
}
|
||||||
|
|
||||||
#define MMMouseUpToCGEventType(button) \
|
CGEventType MMMouseToCGEventType(bool down, MMMouseButton button) {
|
||||||
((button) == LEFT_BUTTON ? kCGEventLeftMouseUp \
|
if (down) { return MMMouseDownToCGEventType(button); }
|
||||||
: ((button) == RIGHT_BUTTON ? kCGEventRightMouseUp \
|
return MMMouseUpToCGEventType(button);
|
||||||
: kCGEventOtherMouseUp))
|
}
|
||||||
|
|
||||||
#define MMMouseDragToCGEventType(button) \
|
|
||||||
((button) == LEFT_BUTTON ? kCGEventLeftMouseDragged \
|
|
||||||
: ((button) == RIGHT_BUTTON ? kCGEventRightMouseDragged \
|
|
||||||
: kCGEventOtherMouseDragged))
|
|
||||||
|
|
||||||
#elif defined(IS_WINDOWS)
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
#define MMMouseToMEventF(down, button) \
|
DWORD MMMouseDownToMEventF(MMMouseButton button) {
|
||||||
(down ? MMMouseDownToMEventF(button) : MMMouseUpToMEventF(button))
|
if (button == LEFT_BUTTON) { return MOUSEEVENTF_LEFTDOWN; }
|
||||||
|
if (button == RIGHT_BUTTON) { return MOUSEEVENTF_RIGHTDOWN; }
|
||||||
#define MMMouseUpToMEventF(button) \
|
return MOUSEEVENTF_MIDDLEDOWN;
|
||||||
((button) == LEFT_BUTTON ? MOUSEEVENTF_LEFTUP \
|
}
|
||||||
: ((button) == RIGHT_BUTTON ? MOUSEEVENTF_RIGHTUP \
|
|
||||||
: MOUSEEVENTF_MIDDLEUP))
|
|
||||||
|
|
||||||
#define MMMouseDownToMEventF(button) \
|
|
||||||
((button) == LEFT_BUTTON ? MOUSEEVENTF_LEFTDOWN \
|
|
||||||
: ((button) == RIGHT_BUTTON ? MOUSEEVENTF_RIGHTDOWN \
|
|
||||||
: MOUSEEVENTF_MIDDLEDOWN))
|
|
||||||
|
|
||||||
|
DWORD MMMouseToMEventF(bool down, MMMouseButton button) {
|
||||||
|
if (down) { return MMMouseDownToMEventF(button); }
|
||||||
|
return MMMouseUpToMEventF(button);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
/**
|
/* Calculate the delta for a mouse move and add them to the event. */
|
||||||
* Calculate the delta for a mouse move and add them to the event.
|
void calculateDeltas(CGEventRef *event, MMPointInt32 point) {
|
||||||
* @param event The mouse move event (by ref).
|
/* The next few lines are a workaround for games not detecting mouse moves. */
|
||||||
* @param point The new mouse x and y.
|
CGEventRef get = CGEventCreate(NULL);
|
||||||
*/
|
CGPoint mouse = CGEventGetLocation(get);
|
||||||
void calculateDeltas(CGEventRef *event, MMPointInt32 point){
|
|
||||||
/**
|
|
||||||
* The next few lines are a workaround for games not detecting mouse moves.
|
|
||||||
* See this issue for more information:
|
|
||||||
* https://github.com/go-vgo/robotgo/issues/159
|
|
||||||
*/
|
|
||||||
CGEventRef get = CGEventCreate(NULL);
|
|
||||||
CGPoint mouse = CGEventGetLocation(get);
|
|
||||||
|
|
||||||
// Calculate the deltas.
|
// Calculate the deltas.
|
||||||
int64_t deltaX = point.x - mouse.x;
|
int64_t deltaX = point.x - mouse.x;
|
||||||
int64_t deltaY = point.y - mouse.y;
|
int64_t deltaY = point.y - mouse.y;
|
||||||
|
|
||||||
CGEventSetIntegerValueField(*event, kCGMouseEventDeltaX, deltaX);
|
CGEventSetIntegerValueField(*event, kCGMouseEventDeltaX, deltaX);
|
||||||
CGEventSetIntegerValueField(*event, kCGMouseEventDeltaY, deltaY);
|
CGEventSetIntegerValueField(*event, kCGMouseEventDeltaY, deltaY);
|
||||||
|
|
||||||
CFRelease(get);
|
CFRelease(get);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Move the mouse to a specific point. */
|
||||||
/**
|
|
||||||
* Move the mouse to a specific point.
|
|
||||||
* @param point The coordinates to move the mouse to (x, y).
|
|
||||||
*/
|
|
||||||
void moveMouse(MMPointInt32 point){
|
void moveMouse(MMPointInt32 point){
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
CGEventRef move = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved,
|
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||||
|
CGEventRef move = CGEventCreateMouseEvent(source, kCGEventMouseMoved,
|
||||||
CGPointFromMMPointInt32(point), kCGMouseButtonLeft);
|
CGPointFromMMPointInt32(point), kCGMouseButtonLeft);
|
||||||
|
|
||||||
calculateDeltas(&move, point);
|
calculateDeltas(&move, point);
|
||||||
|
|
||||||
CGEventPost(kCGSessionEventTap, move);
|
CGEventPost(kCGHIDEventTap, move);
|
||||||
CFRelease(move);
|
CFRelease(move);
|
||||||
|
CFRelease(source);
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
Display *display = XGetMainDisplay();
|
Display *display = XGetMainDisplay();
|
||||||
XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, point.x, point.y);
|
XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, point.x, point.y);
|
||||||
|
|
||||||
XSync(display, false);
|
XSync(display, false);
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
// Mouse motion is now done using SendInput with MOUSEINPUT.
|
SetCursorPos(point.x, point.y);
|
||||||
// We use Absolute mouse positioning
|
|
||||||
#define MOUSE_COORD_TO_ABS(coord, width_or_height) ( \
|
|
||||||
((65536 * coord) / width_or_height) + (coord < 0 ? -1 : 1))
|
|
||||||
|
|
||||||
MMRectInt32 rect = getScreenRect(-1);
|
|
||||||
int32_t x = MOUSE_COORD_TO_ABS(point.x - rect.origin.x, rect.size.w);
|
|
||||||
int32_t y = MOUSE_COORD_TO_ABS(point.y - rect.origin.y, rect.size.h);
|
|
||||||
|
|
||||||
INPUT mouseInput;
|
|
||||||
mouseInput.type = INPUT_MOUSE;
|
|
||||||
mouseInput.mi.dx = x;
|
|
||||||
mouseInput.mi.dy = y;
|
|
||||||
mouseInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK;
|
|
||||||
mouseInput.mi.time = 0; // System will provide the timestamp
|
|
||||||
|
|
||||||
mouseInput.mi.dwExtraInfo = 0;
|
|
||||||
mouseInput.mi.mouseData = 0;
|
|
||||||
SendInput(1, &mouseInput, sizeof(mouseInput));
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void dragMouse(MMPointInt32 point, const MMMouseButton button){
|
void dragMouse(MMPointInt32 point, const MMMouseButton button){
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
const CGEventType dragType = MMMouseDragToCGEventType(button);
|
const CGEventType dragType = MMMouseDragToCGEventType(button);
|
||||||
CGEventRef drag = CGEventCreateMouseEvent(NULL, dragType,
|
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||||
CGPointFromMMPoint(point), (CGMouseButton)button);
|
CGEventRef drag = CGEventCreateMouseEvent(source, dragType,
|
||||||
|
CGPointFromMMPointInt32(point), (CGMouseButton)button);
|
||||||
|
|
||||||
calculateDeltas(&drag, point);
|
calculateDeltas(&drag, point);
|
||||||
|
|
||||||
CGEventPost(kCGSessionEventTap, drag);
|
CGEventPost(kCGHIDEventTap, drag);
|
||||||
CFRelease(drag);
|
CFRelease(drag);
|
||||||
|
CFRelease(source);
|
||||||
#else
|
#else
|
||||||
moveMouse(point);
|
moveMouse(point);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
MMPointInt32 getMousePos(){
|
MMPointInt32 location() {
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
CGEventRef event = CGEventCreate(NULL);
|
CGEventRef event = CGEventCreate(NULL);
|
||||||
CGPoint point = CGEventGetLocation(event);
|
CGPoint point = CGEventGetLocation(event);
|
||||||
@ -152,38 +127,34 @@ MMPointInt32 getMousePos(){
|
|||||||
|
|
||||||
return MMPointInt32FromCGPoint(point);
|
return MMPointInt32FromCGPoint(point);
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
int x, y; /* This is all we care about. Seriously. */
|
int x, y; /* This is all we care about. Seriously. */
|
||||||
Window garb1, garb2; /* Why you can't specify NULL as a parameter */
|
Window garb1, garb2; /* Why you can't specify NULL as a parameter */
|
||||||
int garb_x, garb_y; /* is beyond me. */
|
int garb_x, garb_y; /* is beyond me. */
|
||||||
unsigned int more_garbage;
|
unsigned int more_garbage;
|
||||||
|
|
||||||
Display *display = XGetMainDisplay();
|
Display *display = XGetMainDisplay();
|
||||||
XQueryPointer(display, XDefaultRootWindow(display), &garb1, &garb2,
|
XQueryPointer(display, XDefaultRootWindow(display), &garb1, &garb2, &x, &y,
|
||||||
&x, &y, &garb_x, &garb_y, &more_garbage);
|
&garb_x, &garb_y, &more_garbage);
|
||||||
|
|
||||||
return MMPointInt32Make(x, y);
|
return MMPointInt32Make(x, y);
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
POINT point;
|
POINT point;
|
||||||
GetCursorPos(&point);
|
GetCursorPos(&point);
|
||||||
|
|
||||||
return MMPointInt32FromPOINT(point);
|
return MMPointInt32FromPOINT(point);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* Press down a button, or release it. */
|
||||||
* Press down a button, or release it.
|
void toggleMouse(bool down, MMMouseButton button) {
|
||||||
* @param down True for down, false for up.
|
|
||||||
* @param button The button to press down or release.
|
|
||||||
*/
|
|
||||||
void toggleMouse(bool down, MMMouseButton button){
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
const CGPoint currentPos = CGPointFromMMPoint(getMousePos());
|
const CGPoint currentPos = CGPointFromMMPointInt32(location());
|
||||||
const CGEventType mouseType = MMMouseToCGEventType(down, button);
|
const CGEventType mouseType = MMMouseToCGEventType(down, button);
|
||||||
CGEventRef event = CGEventCreateMouseEvent(NULL,
|
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||||
mouseType, currentPos, (CGMouseButton)button);
|
CGEventRef event = CGEventCreateMouseEvent(source, mouseType, currentPos, (CGMouseButton)button);
|
||||||
|
|
||||||
CGEventPost(kCGSessionEventTap, event);
|
CGEventPost(kCGHIDEventTap, event);
|
||||||
CFRelease(event);
|
CFRelease(event);
|
||||||
|
CFRelease(source);
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
Display *display = XGetMainDisplay();
|
Display *display = XGetMainDisplay();
|
||||||
XTestFakeButtonEvent(display, button, down ? True : False, CurrentTime);
|
XTestFakeButtonEvent(display, button, down ? True : False, CurrentTime);
|
||||||
@ -209,142 +180,58 @@ void clickMouse(MMMouseButton button){
|
|||||||
toggleMouse(false, button);
|
toggleMouse(false, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* Special function for sending double clicks, needed for MacOS. */
|
||||||
* Special function for sending double clicks, needed for Mac OS X.
|
|
||||||
* @param button Button to click.
|
|
||||||
*/
|
|
||||||
void doubleClick(MMMouseButton button){
|
void doubleClick(MMMouseButton button){
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
|
|
||||||
/* Double click for Mac. */
|
/* Double click for Mac. */
|
||||||
const CGPoint currentPos = CGPointFromMMPoint(getMousePos());
|
const CGPoint currentPos = CGPointFromMMPointInt32(location());
|
||||||
const CGEventType mouseTypeDown = MMMouseToCGEventType(true, button);
|
const CGEventType mouseTypeDown = MMMouseToCGEventType(true, button);
|
||||||
const CGEventType mouseTypeUP = MMMouseToCGEventType(false, button);
|
const CGEventType mouseTypeUP = MMMouseToCGEventType(false, button);
|
||||||
|
|
||||||
CGEventRef event = CGEventCreateMouseEvent(
|
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||||
NULL, mouseTypeDown, currentPos, kCGMouseButtonLeft);
|
CGEventRef event = CGEventCreateMouseEvent(source, mouseTypeDown, currentPos, kCGMouseButtonLeft);
|
||||||
|
|
||||||
/* Set event to double click. */
|
/* Set event to double click. */
|
||||||
CGEventSetIntegerValueField(event, kCGMouseEventClickState, 2);
|
CGEventSetIntegerValueField(event, kCGMouseEventClickState, 2);
|
||||||
|
|
||||||
CGEventPost(kCGHIDEventTap, event);
|
CGEventPost(kCGHIDEventTap, event);
|
||||||
|
|
||||||
CGEventSetType(event, mouseTypeUP);
|
CGEventSetType(event, mouseTypeUP);
|
||||||
CGEventPost(kCGHIDEventTap, event);
|
CGEventPost(kCGHIDEventTap, event);
|
||||||
|
|
||||||
CFRelease(event);
|
CFRelease(event);
|
||||||
|
CFRelease(source);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* Double click for everything else. */
|
/* Double click for everything else. */
|
||||||
clickMouse(button);
|
clickMouse(button);
|
||||||
microsleep(200);
|
microsleep(200);
|
||||||
clickMouse(button);
|
clickMouse(button);
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function used to scroll the screen in the required direction.
|
|
||||||
* This uses the magnitude to scroll the required amount in the direction.
|
|
||||||
* TODO Requires further fine tuning based on the requirements.
|
|
||||||
*/
|
|
||||||
void scrollMouse(int scrollMagnitude, MMMouseWheelDirection scrollDirection){
|
|
||||||
#if defined(IS_WINDOWS)
|
|
||||||
// Fix for #97 https://github.com/go-vgo/robotgo/issues/97,
|
|
||||||
// C89 needs variables declared on top of functions (mouseScrollInput)
|
|
||||||
INPUT mouseScrollInput;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Direction should only be considered based on the scrollDirection. This
|
|
||||||
* Should not interfere. */
|
|
||||||
int cleanScrollMagnitude = abs(scrollMagnitude);
|
|
||||||
if (!(scrollDirection == DIRECTION_UP || scrollDirection == DIRECTION_DOWN)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set up the OS specific solution */
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
|
|
||||||
CGWheelCount wheel = 1;
|
|
||||||
CGEventRef event;
|
|
||||||
|
|
||||||
/* Make scroll magnitude negative if we're scrolling down. */
|
|
||||||
cleanScrollMagnitude = cleanScrollMagnitude * scrollDirection;
|
|
||||||
|
|
||||||
event = CGEventCreateScrollWheelEvent(NULL,
|
|
||||||
kCGScrollEventUnitLine, wheel, cleanScrollMagnitude, 0);
|
|
||||||
|
|
||||||
CGEventPost(kCGHIDEventTap, event);
|
|
||||||
|
|
||||||
#elif defined(USE_X11)
|
|
||||||
|
|
||||||
int x;
|
|
||||||
int dir = 4; /* Button 4 is up, 5 is down. */
|
|
||||||
Display *display = XGetMainDisplay();
|
|
||||||
|
|
||||||
if (scrollDirection == DIRECTION_DOWN) {
|
|
||||||
dir = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (x = 0; x < cleanScrollMagnitude; x++) {
|
|
||||||
XTestFakeButtonEvent(display, dir, 1, CurrentTime);
|
|
||||||
XTestFakeButtonEvent(display, dir, 0, CurrentTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
XSync(display, false);
|
|
||||||
|
|
||||||
#elif defined(IS_WINDOWS)
|
|
||||||
|
|
||||||
mouseScrollInput.type = INPUT_MOUSE;
|
|
||||||
mouseScrollInput.mi.dx = 0;
|
|
||||||
mouseScrollInput.mi.dy = 0;
|
|
||||||
mouseScrollInput.mi.dwFlags = MOUSEEVENTF_WHEEL;
|
|
||||||
mouseScrollInput.mi.time = 0;
|
|
||||||
mouseScrollInput.mi.dwExtraInfo = 0;
|
|
||||||
mouseScrollInput.mi.mouseData = WHEEL_DELTA * scrollDirection * cleanScrollMagnitude;
|
|
||||||
|
|
||||||
SendInput(1, &mouseScrollInput, sizeof(mouseScrollInput));
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Function used to scroll the screen in the required direction. */
|
||||||
void scrollMouseXY(int x, int y) {
|
void scrollMouseXY(int x, int y) {
|
||||||
#if defined(IS_WINDOWS)
|
#if defined(IS_WINDOWS)
|
||||||
// Fix for #97,
|
// Fix for #97, C89 needs variables declared on top of functions (mouseScrollInput)
|
||||||
// C89 needs variables declared on top of functions (mouseScrollInput)
|
|
||||||
INPUT mouseScrollInputH;
|
INPUT mouseScrollInputH;
|
||||||
INPUT mouseScrollInputV;
|
INPUT mouseScrollInputV;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Direction should only be considered based on the scrollDirection. This
|
#if defined(IS_MACOSX)
|
||||||
* Should not interfere. */
|
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||||
|
CGEventRef event = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitPixel, 2, y, x);
|
||||||
/* Set up the OS specific solution */
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
|
|
||||||
CGEventRef event;
|
|
||||||
|
|
||||||
event = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 2, y, x);
|
|
||||||
CGEventPost(kCGHIDEventTap, event);
|
CGEventPost(kCGHIDEventTap, event);
|
||||||
|
|
||||||
CFRelease(event);
|
CFRelease(event);
|
||||||
|
CFRelease(source);
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
|
|
||||||
int ydir = 4; /* Button 4 is up, 5 is down. */
|
int ydir = 4; /* Button 4 is up, 5 is down. */
|
||||||
int xdir = 6;
|
int xdir = 6;
|
||||||
Display *display = XGetMainDisplay();
|
Display *display = XGetMainDisplay();
|
||||||
|
|
||||||
if (y < 0) {
|
if (y < 0) { ydir = 5; }
|
||||||
ydir = 5;
|
if (x < 0) { xdir = 7; }
|
||||||
}
|
|
||||||
if (x < 0) {
|
|
||||||
xdir = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
int xi;
|
int xi; int yi;
|
||||||
int yi;
|
|
||||||
for (xi = 0; xi < abs(x); xi++) {
|
for (xi = 0; xi < abs(x); xi++) {
|
||||||
XTestFakeButtonEvent(display, xdir, 1, CurrentTime);
|
XTestFakeButtonEvent(display, xdir, 1, CurrentTime);
|
||||||
XTestFakeButtonEvent(display, xdir, 0, CurrentTime);
|
XTestFakeButtonEvent(display, xdir, 0, CurrentTime);
|
||||||
@ -355,9 +242,7 @@ void scrollMouseXY(int x, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
XSync(display, false);
|
XSync(display, false);
|
||||||
|
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
|
|
||||||
mouseScrollInputH.type = INPUT_MOUSE;
|
mouseScrollInputH.type = INPUT_MOUSE;
|
||||||
mouseScrollInputH.mi.dx = 0;
|
mouseScrollInputH.mi.dx = 0;
|
||||||
mouseScrollInputH.mi.dy = 0;
|
mouseScrollInputH.mi.dy = 0;
|
||||||
@ -379,16 +264,11 @@ void scrollMouseXY(int x, int y) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* A crude, fast hypot() approximation to get around the fact that hypot() is not a standard ANSI C function. */
|
||||||
* A crude, fast hypot() approximation to get around the fact that hypot() is
|
#if !defined(M_SQRT2)
|
||||||
* not a standard ANSI C function.
|
#define M_SQRT2 1.4142135623730950488016887 /* Fix for MSVC. */
|
||||||
*
|
#endif
|
||||||
* It is not particularly accurate but that does not matter for our use case.
|
|
||||||
*
|
|
||||||
* Taken from this StackOverflow answer:
|
|
||||||
* http://stackoverflow.com/questions/3506404/fast-hypotenuse-algorithm-for-embedded-processor#3507882
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static double crude_hypot(double x, double y){
|
static double crude_hypot(double x, double y){
|
||||||
double big = fabs(x); /* max(|x|, |y|) */
|
double big = fabs(x); /* max(|x|, |y|) */
|
||||||
double small = fabs(y); /* min(|x|, |y|) */
|
double small = fabs(y); /* min(|x|, |y|) */
|
||||||
@ -403,15 +283,12 @@ static double crude_hypot(double x, double y){
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed){
|
bool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed){
|
||||||
MMPointInt32 pos = getMousePos();
|
MMPointInt32 pos = location();
|
||||||
MMSizeInt32 screenSize = getMainDisplaySize();
|
// MMSizeInt32 screenSize = getMainDisplaySize();
|
||||||
double velo_x = 0.0, velo_y = 0.0;
|
double velo_x = 0.0, velo_y = 0.0;
|
||||||
double distance;
|
double distance;
|
||||||
|
|
||||||
while ((distance =
|
while ((distance =crude_hypot((double)pos.x - endPoint.x, (double)pos.y - endPoint.y)) > 1.0) {
|
||||||
crude_hypot((double)pos.x - endPoint.x, (double)pos.y - endPoint.y)
|
|
||||||
) > 1.0) {
|
|
||||||
|
|
||||||
double gravity = DEADBEEF_UNIFORM(5.0, 500.0);
|
double gravity = DEADBEEF_UNIFORM(5.0, 500.0);
|
||||||
// double gravity = DEADBEEF_UNIFORM(lowSpeed, highSpeed);
|
// double gravity = DEADBEEF_UNIFORM(lowSpeed, highSpeed);
|
||||||
double veloDistance;
|
double veloDistance;
|
||||||
@ -426,12 +303,10 @@ bool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed)
|
|||||||
pos.x += floor(velo_x + 0.5);
|
pos.x += floor(velo_x + 0.5);
|
||||||
pos.y += floor(velo_y + 0.5);
|
pos.y += floor(velo_y + 0.5);
|
||||||
|
|
||||||
/* Make sure we are in the screen boundaries!
|
/* Make sure we are in the screen boundaries! (Strange things will happen if we are not.) */
|
||||||
* (Strange things will happen if we are not.) */
|
// if (pos.x >= screenSize.w || pos.y >= screenSize.h) {
|
||||||
if (pos.x >= screenSize.w || pos.y >= screenSize.h) {
|
// return false;
|
||||||
return false;
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
moveMouse(pos);
|
moveMouse(pos);
|
||||||
|
|
||||||
/* Wait 1 - 3 milliseconds. */
|
/* Wait 1 - 3 milliseconds. */
|
||||||
|
4
mouse/mouse_darwin.go
Normal file
4
mouse/mouse_darwin.go
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//go:build darwin
|
||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package mouse
|
4
mouse/mouse_windows.go
Normal file
4
mouse/mouse_windows.go
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package mouse
|
4
mouse/mouse_x11.go
Normal file
4
mouse/mouse_x11.go
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//go:build !darwin && !windows
|
||||||
|
// +build !darwin,!windows
|
||||||
|
|
||||||
|
package mouse
|
14
ps.go
14
ps.go
@ -14,17 +14,17 @@ import ps "github.com/vcaesar/gops"
|
|||||||
|
|
||||||
// Nps process struct
|
// Nps process struct
|
||||||
type Nps struct {
|
type Nps struct {
|
||||||
Pid int32
|
Pid int
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pids get the all process id
|
// Pids get the all process id
|
||||||
func Pids() ([]int32, error) {
|
func Pids() ([]int, error) {
|
||||||
return ps.Pids()
|
return ps.Pids()
|
||||||
}
|
}
|
||||||
|
|
||||||
// PidExists determine whether the process exists
|
// PidExists determine whether the process exists
|
||||||
func PidExists(pid int32) (bool, error) {
|
func PidExists(pid int) (bool, error) {
|
||||||
return ps.PidExists(pid)
|
return ps.PidExists(pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ func Process() ([]Nps, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindName find the process name by the process id
|
// FindName find the process name by the process id
|
||||||
func FindName(pid int32) (string, error) {
|
func FindName(pid int) (string, error) {
|
||||||
return ps.FindName(pid)
|
return ps.FindName(pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,12 +57,12 @@ func FindNames() ([]string, error) {
|
|||||||
// FindIds finds the all processes named with a subset
|
// FindIds finds the all processes named with a subset
|
||||||
// of "name" (case insensitive),
|
// of "name" (case insensitive),
|
||||||
// return matched IDs.
|
// return matched IDs.
|
||||||
func FindIds(name string) ([]int32, error) {
|
func FindIds(name string) ([]int, error) {
|
||||||
return ps.FindIds(name)
|
return ps.FindIds(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindPath find the process path by the process pid
|
// FindPath find the process path by the process pid
|
||||||
func FindPath(pid int32) (string, error) {
|
func FindPath(pid int) (string, error) {
|
||||||
return ps.FindPath(pid)
|
return ps.FindPath(pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +72,6 @@ func Run(path string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Kill kill the process by PID
|
// Kill kill the process by PID
|
||||||
func Kill(pid int32) error {
|
func Kill(pid int) error {
|
||||||
return ps.Kill(pid)
|
return ps.Kill(pid)
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,9 @@ func TestGetScreenSize(t *testing.T) {
|
|||||||
|
|
||||||
rect := robotgo.GetScreenRect()
|
rect := robotgo.GetScreenRect()
|
||||||
fmt.Println("Get screen rect: ", rect)
|
fmt.Println("Get screen rect: ", rect)
|
||||||
|
|
||||||
|
x, y = robotgo.Location()
|
||||||
|
fmt.Println("Get location: ", x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSysScale(t *testing.T) {
|
func TestGetSysScale(t *testing.T) {
|
||||||
@ -40,5 +43,13 @@ func TestGetSysScale(t *testing.T) {
|
|||||||
log.Println("SysScale: ", s)
|
log.Println("SysScale: ", s)
|
||||||
|
|
||||||
f := robotgo.ScaleF()
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
909
robotgo.go
909
robotgo.go
File diff suppressed because it is too large
Load Diff
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
|
||||||
|
}
|
24
robotgo_mac.go
Normal file
24
robotgo_mac.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build darwin
|
||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package robotgo
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <CoreGraphics/CoreGraphics.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// GetMainId get the main display id
|
||||||
|
func GetMainId() int {
|
||||||
|
return int(C.CGMainDisplayID())
|
||||||
|
}
|
@ -14,40 +14,51 @@
|
|||||||
package robotgo
|
package robotgo
|
||||||
|
|
||||||
// GetBounds get the window bounds
|
// GetBounds get the window bounds
|
||||||
func GetBounds(pid int32, args ...int) (int, int, int, int) {
|
func GetBounds(pid int, args ...int) (int, int, int, int) {
|
||||||
var hwnd int
|
var isPid int
|
||||||
if len(args) > 0 {
|
if len(args) > 0 || NotPid {
|
||||||
hwnd = args[0]
|
isPid = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return internalGetBounds(pid, hwnd)
|
return internalGetBounds(pid, isPid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetClient get the window client bounds
|
||||||
|
func GetClient(pid int, args ...int) (int, int, int, int) {
|
||||||
|
var isPid int
|
||||||
|
if len(args) > 0 || NotPid {
|
||||||
|
isPid = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return internalGetClient(pid, isPid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// internalGetTitle get the window title
|
// internalGetTitle get the window title
|
||||||
func internalGetTitle(pid int32, args ...int32) string {
|
func internalGetTitle(pid int, args ...int) string {
|
||||||
var isHwnd int32
|
var isPid int
|
||||||
if len(args) > 0 {
|
if len(args) > 0 || NotPid {
|
||||||
isHwnd = args[0]
|
isPid = 1
|
||||||
}
|
}
|
||||||
gtitle := cgetTitle(pid, isHwnd)
|
gtitle := cgetTitle(pid, isPid)
|
||||||
|
|
||||||
return gtitle
|
return gtitle
|
||||||
}
|
}
|
||||||
|
|
||||||
// ActivePID active the window by PID,
|
// ActivePid active the window by PID,
|
||||||
//
|
//
|
||||||
// If args[0] > 0 on the Windows platform via a window handle to active
|
// If args[0] > 0 on the Windows platform via a window handle to active
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
|
//
|
||||||
// ids, _ := robotgo.FindIds()
|
// ids, _ := robotgo.FindIds()
|
||||||
// robotgo.ActivePID(ids[0])
|
// robotgo.ActivePid(ids[0])
|
||||||
func ActivePID(pid int32, args ...int) error {
|
func ActivePid(pid int, args ...int) error {
|
||||||
var hwnd int
|
var isPid int
|
||||||
if len(args) > 0 {
|
if len(args) > 0 || NotPid {
|
||||||
hwnd = args[0]
|
isPid = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
internalActive(pid, hwnd)
|
internalActive(pid, isPid)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +72,7 @@ func DisplaysNum() int {
|
|||||||
// If cancel button is not given, only the default button is displayed
|
// If cancel button is not given, only the default button is displayed
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
|
//
|
||||||
// robotgo.Alert("hi", "window", "ok", "cancel")
|
// robotgo.Alert("hi", "window", "ok", "cancel")
|
||||||
func Alert(title, msg string, args ...string) bool {
|
func Alert(title, msg string, args ...string) bool {
|
||||||
return showAlert(title, msg, args...)
|
return showAlert(title, msg, args...)
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
package robotgo
|
package robotgo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/otiai10/gosseract"
|
"github.com/otiai10/gosseract/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetText get the image text by tesseract ocr
|
// GetText get the image text by tesseract ocr
|
||||||
|
@ -42,7 +42,7 @@ func TestSize(t *testing.T) {
|
|||||||
func TestMoveMouse(t *testing.T) {
|
func TestMoveMouse(t *testing.T) {
|
||||||
Move(20, 20)
|
Move(20, 20)
|
||||||
MilliSleep(50)
|
MilliSleep(50)
|
||||||
x, y := GetMousePos()
|
x, y := Location()
|
||||||
|
|
||||||
tt.Equal(t, 20, x)
|
tt.Equal(t, 20, x)
|
||||||
tt.Equal(t, 20, y)
|
tt.Equal(t, 20, y)
|
||||||
@ -51,7 +51,7 @@ func TestMoveMouse(t *testing.T) {
|
|||||||
func TestMoveMouseSmooth(t *testing.T) {
|
func TestMoveMouseSmooth(t *testing.T) {
|
||||||
b := MoveSmooth(100, 100)
|
b := MoveSmooth(100, 100)
|
||||||
MilliSleep(50)
|
MilliSleep(50)
|
||||||
x, y := GetMousePos()
|
x, y := Location()
|
||||||
|
|
||||||
tt.True(t, b)
|
tt.True(t, b)
|
||||||
tt.Equal(t, 100, x)
|
tt.Equal(t, 100, x)
|
||||||
@ -59,16 +59,18 @@ func TestMoveMouseSmooth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDragMouse(t *testing.T) {
|
func TestDragMouse(t *testing.T) {
|
||||||
DragMouse(500, 500)
|
DragSmooth(500, 500)
|
||||||
MilliSleep(50)
|
MilliSleep(50)
|
||||||
x, y := GetMousePos()
|
x, y := Location()
|
||||||
|
|
||||||
tt.Equal(t, 500, x)
|
tt.Equal(t, 500, x)
|
||||||
tt.Equal(t, 500, y)
|
tt.Equal(t, 500, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestScrollMouse(t *testing.T) {
|
func TestScrollMouse(t *testing.T) {
|
||||||
// ScrollMouse(120, "up")
|
ScrollDir(120, "up")
|
||||||
|
ScrollDir(100, "right")
|
||||||
|
|
||||||
Scroll(0, 120)
|
Scroll(0, 120)
|
||||||
MilliSleep(100)
|
MilliSleep(100)
|
||||||
|
|
||||||
@ -83,7 +85,7 @@ func TestMoveRelative(t *testing.T) {
|
|||||||
MoveRelative(10, -10)
|
MoveRelative(10, -10)
|
||||||
MilliSleep(50)
|
MilliSleep(50)
|
||||||
|
|
||||||
x, y := GetMousePos()
|
x, y := Location()
|
||||||
tt.Equal(t, 210, x)
|
tt.Equal(t, 210, x)
|
||||||
tt.Equal(t, 190, y)
|
tt.Equal(t, 190, y)
|
||||||
}
|
}
|
||||||
@ -95,28 +97,42 @@ func TestMoveSmoothRelative(t *testing.T) {
|
|||||||
MoveSmoothRelative(10, -10)
|
MoveSmoothRelative(10, -10)
|
||||||
MilliSleep(50)
|
MilliSleep(50)
|
||||||
|
|
||||||
x, y := GetMousePos()
|
x, y := Location()
|
||||||
tt.Equal(t, 210, x)
|
tt.Equal(t, 210, x)
|
||||||
tt.Equal(t, 190, y)
|
tt.Equal(t, 190, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMouseToggle(t *testing.T) {
|
func TestMouseToggle(t *testing.T) {
|
||||||
e := Toggle("right")
|
e := Toggle("right")
|
||||||
tt.Zero(t, e)
|
tt.Nil(t, e)
|
||||||
|
|
||||||
e = Toggle("right", "up")
|
e = Toggle("right", "up")
|
||||||
tt.Zero(t, e)
|
tt.Nil(t, e)
|
||||||
|
|
||||||
|
e = MouseDown("left")
|
||||||
|
tt.Nil(t, e)
|
||||||
|
|
||||||
|
e = MouseUp("left")
|
||||||
|
tt.Nil(t, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKey(t *testing.T) {
|
func TestKey(t *testing.T) {
|
||||||
e := KeyTap("v", "cmd")
|
e := KeyTap("v", "cmd")
|
||||||
tt.Empty(t, e)
|
tt.Nil(t, e)
|
||||||
|
|
||||||
e = KeyTap("enter")
|
e = KeyTap("enter")
|
||||||
tt.Empty(t, e)
|
tt.Nil(t, e)
|
||||||
|
|
||||||
e = KeyToggle("v", "up")
|
e = KeyToggle("v", "up")
|
||||||
tt.Empty(t, e)
|
tt.Nil(t, e)
|
||||||
|
|
||||||
|
e = KeyDown("a")
|
||||||
|
tt.Nil(t, e)
|
||||||
|
e = KeyUp("a")
|
||||||
|
tt.Nil(t, e)
|
||||||
|
|
||||||
|
e = KeyPress("b")
|
||||||
|
tt.Nil(t, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClip(t *testing.T) {
|
func TestClip(t *testing.T) {
|
||||||
@ -133,7 +149,7 @@ func TestTypeStr(t *testing.T) {
|
|||||||
tt.Equal(t, 115, c)
|
tt.Equal(t, 115, c)
|
||||||
|
|
||||||
e := PasteStr("s")
|
e := PasteStr("s")
|
||||||
tt.Empty(t, e)
|
tt.Nil(t, e)
|
||||||
|
|
||||||
s1 := "abc\\\\cd/s@世界"
|
s1 := "abc\\\\cd/s@世界"
|
||||||
uc := ToUC(s1)
|
uc := ToUC(s1)
|
||||||
@ -149,12 +165,37 @@ func TestKeyCode(t *testing.T) {
|
|||||||
|
|
||||||
s := Special["+"]
|
s := Special["+"]
|
||||||
tt.Equal(t, "=", s)
|
tt.Equal(t, "=", s)
|
||||||
|
|
||||||
|
tt.Equal(t, "0", Key0)
|
||||||
|
tt.Equal(t, "a", KeyA)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestImage(t *testing.T) {
|
||||||
|
bit := CaptureScreen()
|
||||||
|
defer FreeBitmap(bit)
|
||||||
|
tt.NotNil(t, bit)
|
||||||
|
|
||||||
|
img := ToImage(bit)
|
||||||
|
err := SavePng(img, "robot_test.png")
|
||||||
|
tt.Nil(t, err)
|
||||||
|
|
||||||
|
img1, err := CaptureImg(10, 10, 20, 20)
|
||||||
|
tt.Nil(t, err)
|
||||||
|
e := Save(img1, "robot_img.jpeg", 50)
|
||||||
|
tt.Nil(t, e)
|
||||||
|
|
||||||
|
tt.Equal(t, 20, Width(img1))
|
||||||
|
tt.Equal(t, 20, Height(img1))
|
||||||
|
|
||||||
|
bit1 := ImgToBitmap(img1)
|
||||||
|
tt.Equal(t, bit1.Width, Width(img1))
|
||||||
|
tt.Equal(t, bit1.Height, Height(img1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPs(t *testing.T) {
|
func TestPs(t *testing.T) {
|
||||||
id, err := Pids()
|
id, err := Pids()
|
||||||
tt.Not(t, "[]", id)
|
tt.Not(t, "[]", id)
|
||||||
tt.IsType(t, "[]int32", id)
|
tt.IsType(t, "[]int", id)
|
||||||
tt.Nil(t, err)
|
tt.Nil(t, err)
|
||||||
|
|
||||||
ps, e := Process()
|
ps, e := Process()
|
||||||
@ -177,9 +218,14 @@ func TestPs(t *testing.T) {
|
|||||||
|
|
||||||
id, err = FindIds(n1[0])
|
id, err = FindIds(n1[0])
|
||||||
tt.Not(t, "[]", id)
|
tt.Not(t, "[]", id)
|
||||||
tt.IsType(t, "[]int32", id)
|
tt.IsType(t, "[]int", id)
|
||||||
tt.Nil(t, err)
|
tt.Nil(t, err)
|
||||||
|
|
||||||
|
if len(id) > 0 {
|
||||||
|
e := KeyTap("v", id[0], "cmd")
|
||||||
|
tt.Nil(t, e)
|
||||||
|
}
|
||||||
|
|
||||||
// n, e = FindPath(id[0])
|
// n, e = FindPath(id[0])
|
||||||
// tt.NotEmpty(t, n)
|
// tt.NotEmpty(t, n)
|
||||||
// tt.Nil(t, e)
|
// tt.Nil(t, e)
|
||||||
@ -192,6 +238,6 @@ func TestPs(t *testing.T) {
|
|||||||
// log.Println("tap...")
|
// log.Println("tap...")
|
||||||
// }()
|
// }()
|
||||||
|
|
||||||
// i := ShowAlert("t", "msg")
|
// i := Alert("t", "msg")
|
||||||
// tt.Zero(t, i)
|
// tt.True(t, i)
|
||||||
// }
|
// }
|
||||||
|
@ -17,7 +17,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/lxn/win"
|
// "github.com/lxn/win"
|
||||||
|
"github.com/tailscale/win"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FindWindow find window hwnd by name
|
// FindWindow find window hwnd by name
|
||||||
@ -52,20 +53,48 @@ func SetFocus(hwnd win.HWND) win.HWND {
|
|||||||
return win.SetFocus(hwnd)
|
return win.SetFocus(hwnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScaleF get the system scale val
|
// 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()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMainId get the main display id
|
||||||
|
func GetMainId() int {
|
||||||
|
return int(GetMain())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScaleF get the system scale value
|
||||||
|
// if "displayId == -2" this function will get the desktop scale value
|
||||||
func ScaleF(displayId ...int) (f float64) {
|
func ScaleF(displayId ...int) (f float64) {
|
||||||
if len(displayId) > 0 && displayId[0] != -1 {
|
if len(displayId) > 0 && displayId[0] != -1 {
|
||||||
dpi := GetDPI(win.HWND(displayId[0]))
|
if displayId[0] >= 0 {
|
||||||
f = float64(dpi) / 96.0
|
dpi := GetDPI(win.HWND(displayId[0]))
|
||||||
|
f = float64(dpi) / 96.0
|
||||||
|
}
|
||||||
|
|
||||||
|
if displayId[0] == -2 {
|
||||||
|
f = float64(GetDPI(GetDesktopWindow())) / 96.0
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
f = float64(GetMainDPI()) / 96.0
|
f = float64(GetMainDPI()) / 96.0
|
||||||
}
|
}
|
||||||
|
|
||||||
if f == 0.0 {
|
if f == 0.0 {
|
||||||
f = 1.0
|
f = 1.0
|
||||||
}
|
}
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDesktopWindow get the desktop window hwnd id
|
||||||
|
func GetDesktopWindow() win.HWND {
|
||||||
|
return win.GetDesktopWindow()
|
||||||
|
}
|
||||||
|
|
||||||
// GetMainDPI get the display dpi
|
// GetMainDPI get the display dpi
|
||||||
func GetMainDPI() int {
|
func GetMainDPI() int {
|
||||||
return int(GetDPI(GetHWND()))
|
return int(GetDPI(GetHWND()))
|
||||||
|
104
robotgo_x11.go
104
robotgo_x11.go
@ -15,7 +15,6 @@ package robotgo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/robotn/xgb"
|
"github.com/robotn/xgb"
|
||||||
@ -28,64 +27,81 @@ import (
|
|||||||
var xu *xgbutil.XUtil
|
var xu *xgbutil.XUtil
|
||||||
|
|
||||||
// GetBounds get the window bounds
|
// GetBounds get the window bounds
|
||||||
func GetBounds(pid int32, args ...int) (int, int, int, int) {
|
func GetBounds(pid int, args ...int) (int, int, int, int) {
|
||||||
var hwnd int
|
var isPid int
|
||||||
if len(args) > 0 {
|
if len(args) > 0 || NotPid {
|
||||||
hwnd = args[0]
|
isPid = 1
|
||||||
return internalGetBounds(pid, hwnd)
|
return internalGetBounds(pid, isPid)
|
||||||
}
|
}
|
||||||
|
|
||||||
xid, err := GetXId(xu, pid)
|
xid, err := GetXid(xu, pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Get Xid from Pid errors is: ", err)
|
log.Println("Get Xid from Pid errors is: ", err)
|
||||||
return 0, 0, 0, 0
|
return 0, 0, 0, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return internalGetBounds(int32(xid), hwnd)
|
return internalGetBounds(int(xid), isPid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetClient get the window client bounds
|
||||||
|
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)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Get Xid from Pid errors is: ", err)
|
||||||
|
return 0, 0, 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return internalGetClient(int(xid), isPid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// internalGetTitle get the window title
|
// internalGetTitle get the window title
|
||||||
func internalGetTitle(pid int32, args ...int32) string {
|
func internalGetTitle(pid int, args ...int) string {
|
||||||
var hwnd int32
|
var isPid int
|
||||||
if len(args) > 0 {
|
if len(args) > 0 || NotPid {
|
||||||
hwnd = args[0]
|
isPid = 1
|
||||||
return cgetTitle(pid, hwnd)
|
return cgetTitle(pid, isPid)
|
||||||
}
|
}
|
||||||
|
|
||||||
xid, err := GetXId(xu, pid)
|
xid, err := GetXid(xu, pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Get Xid from Pid errors is: ", err)
|
log.Println("Get Xid from Pid errors is: ", err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return cgetTitle(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
|
// If args[0] > 0 on the unix platform via a xid to active
|
||||||
func ActivePIDC(pid int32, args ...int) error {
|
func ActivePidC(pid int, args ...int) error {
|
||||||
var hwnd int
|
var isPid int
|
||||||
if len(args) > 0 {
|
if len(args) > 0 || NotPid {
|
||||||
hwnd = args[0]
|
isPid = 1
|
||||||
internalActive(pid, hwnd)
|
internalActive(pid, isPid)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
xid, err := GetXId(xu, pid)
|
xid, err := GetXid(xu, pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Get Xid from Pid errors is: ", err)
|
log.Println("Get Xid from Pid errors is: ", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
internalActive(int32(xid), hwnd)
|
internalActive(int(xid), isPid)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ActivePID active the window by PID,
|
// ActivePid active the window by Pid,
|
||||||
//
|
//
|
||||||
// If args[0] > 0 on the Windows platform via a window handle to active,
|
// If args[0] > 0 on the Windows platform via a window handle to active,
|
||||||
// If args[0] > 0 on the unix platform via a xid to active
|
// If args[0] > 0 on the unix platform via a xid to active
|
||||||
func ActivePID(pid int32, args ...int) error {
|
func ActivePid(pid int, args ...int) error {
|
||||||
if xu == nil {
|
if xu == nil {
|
||||||
var err error
|
var err error
|
||||||
xu, err = xgbutil.NewConn()
|
xu, err = xgbutil.NewConn()
|
||||||
@ -117,8 +133,8 @@ func ActivePID(pid int32, args ...int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetXId get the xid return window and error
|
// GetXid get the xid return window and error
|
||||||
func GetXId(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
|
func GetXid(xu *xgbutil.XUtil, pid int) (xproto.Window, error) {
|
||||||
if xu == nil {
|
if xu == nil {
|
||||||
var err error
|
var err error
|
||||||
xu, err = xgbutil.NewConn()
|
xu, err = xgbutil.NewConn()
|
||||||
@ -132,8 +148,8 @@ func GetXId(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
|
|||||||
return xid, err
|
return xid, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetXidFromPid get the xide from pid
|
// GetXidFromPid get the xid from pid
|
||||||
func GetXidFromPid(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
|
func GetXidFromPid(xu *xgbutil.XUtil, pid int) (xproto.Window, error) {
|
||||||
windows, err := ewmh.ClientListGet(xu)
|
windows, err := ewmh.ClientListGet(xu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
@ -174,19 +190,45 @@ func DisplaysNum() int {
|
|||||||
return int(reply.Number)
|
return int(reply.Number)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMainId get the main display id
|
||||||
|
func GetMainId() int {
|
||||||
|
conn, err := xgb.NewConn()
|
||||||
|
if err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
setup := xproto.Setup(conn)
|
||||||
|
defaultScreen := setup.DefaultScreen(conn)
|
||||||
|
id := -1
|
||||||
|
for i, screen := range setup.Roots {
|
||||||
|
if defaultScreen.Root == screen.Root {
|
||||||
|
id = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
// Alert show a alert window
|
// Alert show a alert window
|
||||||
// Displays alert with the attributes.
|
// Displays alert with the attributes.
|
||||||
// If cancel button is not given, only the default button is displayed
|
// If cancel button is not given, only the default button is displayed
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
|
//
|
||||||
// robotgo.Alert("hi", "window", "ok", "cancel")
|
// robotgo.Alert("hi", "window", "ok", "cancel")
|
||||||
func Alert(title, msg string, args ...string) bool {
|
func Alert(title, msg string, args ...string) bool {
|
||||||
defaultBtn, cancelBtn := alertArgs(args...)
|
defaultBtn, cancelBtn := alertArgs(args...)
|
||||||
c := `xmessage -center ` + msg +
|
c := `xmessage -center ` + msg +
|
||||||
` -title ` + title + ` -buttons ` + defaultBtn + ":0," + cancelBtn + ":1" + ` -default Ok`
|
` -title ` + title + ` -buttons ` + defaultBtn + ":0,"
|
||||||
|
if cancelBtn != "" {
|
||||||
|
c += cancelBtn + ":1"
|
||||||
|
}
|
||||||
|
c += ` -default ` + defaultBtn
|
||||||
|
c += ` -geometry 400x200`
|
||||||
|
|
||||||
out, err := Run(c)
|
out, err := Run(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Alert: ", err, ". ", string(out))
|
// fmt.Println("Alert: ", err, ". ", string(out))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,16 +9,13 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#include "../base/types.h"
|
#include "../base/types.h"
|
||||||
|
#include "../base/pubs.h"
|
||||||
#include "../base/rgb.h"
|
#include "../base/rgb.h"
|
||||||
#include "../base/win32.h"
|
|
||||||
#include "screengrab_c.h"
|
#include "screengrab_c.h"
|
||||||
#include "screen_c.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
// #include "../MMBitmap_c.h"
|
|
||||||
|
|
||||||
void padHex(MMRGBHex color, char* hex) {
|
void padHex(MMRGBHex color, char* hex) {
|
||||||
// Length needs to be 7 because snprintf includes a terminating null.
|
// Length needs to be 7 because snprintf includes a terminating null.
|
||||||
// Use %06x to pad hex value with leading 0s.
|
|
||||||
snprintf(hex, 7, "%06x", color);
|
snprintf(hex, 7, "%06x", color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +26,6 @@ char* pad_hex(MMRGBHex color) {
|
|||||||
|
|
||||||
char* str = (char*)calloc(100, sizeof(char*));
|
char* str = (char*)calloc(100, sizeof(char*));
|
||||||
if (str) { strcpy(str, hex); }
|
if (str) { strcpy(str, hex); }
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,32 +50,17 @@ MMRGBHex get_px_color(int32_t x, int32_t y, int32_t display_id) {
|
|||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1), display_id);
|
bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1), display_id, 0);
|
||||||
// bitmap = MMRectMake(x, y, 1, 1);
|
|
||||||
|
|
||||||
color = MMRGBHexAtPoint(bitmap, 0, 0);
|
color = MMRGBHexAtPoint(bitmap, 0, 0);
|
||||||
destroyMMBitmap(bitmap);
|
destroyMMBitmap(bitmap);
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* get_pixel_color(int32_t x, int32_t y, int32_t display_id) {
|
|
||||||
MMRGBHex color = get_px_color(x, y, display_id);
|
|
||||||
|
|
||||||
char* s = pad_hex(color);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
MMSizeInt32 get_screen_size() {
|
|
||||||
// Get display size.
|
|
||||||
MMSizeInt32 displaySize = getMainDisplaySize();
|
|
||||||
return displaySize;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* set_XDisplay_name(char* name) {
|
char* set_XDisplay_name(char* name) {
|
||||||
#if defined(USE_X11)
|
#if defined(USE_X11)
|
||||||
setXDisplay(name);
|
setXDisplay(name);
|
||||||
return "success";
|
return "";
|
||||||
#else
|
#else
|
||||||
return "SetXDisplayName is only supported on Linux";
|
return "SetXDisplayName is only supported on Linux";
|
||||||
#endif
|
#endif
|
||||||
@ -88,8 +69,8 @@ char* set_XDisplay_name(char* name) {
|
|||||||
char* get_XDisplay_name() {
|
char* get_XDisplay_name() {
|
||||||
#if defined(USE_X11)
|
#if defined(USE_X11)
|
||||||
const char* display = getXDisplay();
|
const char* display = getXDisplay();
|
||||||
|
|
||||||
char* sd = (char*)calloc(100, sizeof(char*));
|
char* sd = (char*)calloc(100, sizeof(char*));
|
||||||
|
|
||||||
if (sd) { strcpy(sd, display); }
|
if (sd) { strcpy(sd, display); }
|
||||||
return sd;
|
return sd;
|
||||||
#else
|
#else
|
||||||
@ -97,6 +78,14 @@ char* get_XDisplay_name() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void close_main_display() {
|
||||||
|
#if defined(USE_X11)
|
||||||
|
XCloseMainDisplay();
|
||||||
|
#else
|
||||||
|
//
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t get_num_displays() {
|
uint32_t get_num_displays() {
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
@ -115,6 +104,14 @@ uint32_t get_num_displays() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uintptr get_hwnd_by_pid(uintptr pid) {
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
HWND hwnd = GetHwndByPid(pid);
|
||||||
|
return (uintptr)hwnd;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void bitmap_dealloc(MMBitmapRef bitmap) {
|
void bitmap_dealloc(MMBitmapRef bitmap) {
|
||||||
if (bitmap != NULL) {
|
if (bitmap != NULL) {
|
||||||
@ -124,9 +121,8 @@ void bitmap_dealloc(MMBitmapRef bitmap) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// capture_screen capture screen
|
// capture_screen capture screen
|
||||||
MMBitmapRef capture_screen(int32_t x, int32_t y, int32_t w, int32_t h, int32_t display_id) {
|
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);
|
MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, w, h), display_id, isPid);
|
||||||
// printf("%s\n", bitmap);
|
|
||||||
return bitmap;
|
return bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
screen/screen.go
Normal file
1
screen/screen.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package screen
|
@ -1,29 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef SCREEN_H
|
|
||||||
#define SCREEN_H
|
|
||||||
|
|
||||||
#include "../base/types.h"
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#include "../base/ms_stdbool.h"
|
|
||||||
#else
|
|
||||||
#include <stdbool.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Returns the size of the main display. */
|
|
||||||
MMSizeInt32 getMainDisplaySize(void);
|
|
||||||
|
|
||||||
/* Convenience function that returns whether the given point is in the bounds
|
|
||||||
* of the main screen. */
|
|
||||||
bool pointVisibleOnMainDisplay(MMPointInt32 point);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* SCREEN_H */
|
|
@ -1,14 +1,74 @@
|
|||||||
#include "screen.h"
|
|
||||||
//#include "../base/os.h"
|
//#include "../base/os.h"
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
#include <ApplicationServices/ApplicationServices.h>
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xresource.h>
|
||||||
// #include "../base/xdisplay_c.h"
|
// #include "../base/xdisplay_c.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MMSizeInt32 getMainDisplaySize(void){
|
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)
|
#if defined(IS_MACOSX)
|
||||||
CGDirectDisplayID displayID = CGMainDisplayID();
|
CGDirectDisplayID displayID = CGMainDisplayID();
|
||||||
CGRect displayRect = CGDisplayBounds(displayID);
|
CGRect displayRect = CGDisplayBounds(displayID);
|
||||||
@ -23,15 +83,9 @@ MMSizeInt32 getMainDisplaySize(void){
|
|||||||
(int32_t)DisplayWidth(display, screen),
|
(int32_t)DisplayWidth(display, screen),
|
||||||
(int32_t)DisplayHeight(display, screen));
|
(int32_t)DisplayHeight(display, screen));
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
if (GetSystemMetrics(SM_CMONITORS) == 1) {
|
return MMSizeInt32Make(
|
||||||
return MMSizeInt32Make(
|
|
||||||
(int32_t)GetSystemMetrics(SM_CXSCREEN),
|
(int32_t)GetSystemMetrics(SM_CXSCREEN),
|
||||||
(int32_t)GetSystemMetrics(SM_CYSCREEN));
|
(int32_t)GetSystemMetrics(SM_CYSCREEN));
|
||||||
} else {
|
|
||||||
return MMSizeInt32Make(
|
|
||||||
(int32_t)GetSystemMetrics(SM_CXVIRTUALSCREEN),
|
|
||||||
(int32_t)GetSystemMetrics(SM_CYVIRTUALSCREEN));
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,12 +107,12 @@ MMRectInt32 getScreenRect(int32_t display_id) {
|
|||||||
const int screen = DefaultScreen(display);
|
const int screen = DefaultScreen(display);
|
||||||
|
|
||||||
return MMRectInt32Make(
|
return MMRectInt32Make(
|
||||||
(int32_t)0,
|
(int32_t)0, (int32_t)0,
|
||||||
(int32_t)0,
|
|
||||||
(int32_t)DisplayWidth(display, screen),
|
(int32_t)DisplayWidth(display, screen),
|
||||||
(int32_t)DisplayHeight(display, screen));
|
(int32_t)DisplayHeight(display, screen));
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
if (GetSystemMetrics(SM_CMONITORS) == 1) {
|
if (GetSystemMetrics(SM_CMONITORS) == 1
|
||||||
|
|| display_id == -1 || display_id == 0) {
|
||||||
return MMRectInt32Make(
|
return MMRectInt32Make(
|
||||||
(int32_t)0,
|
(int32_t)0,
|
||||||
(int32_t)0,
|
(int32_t)0,
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef SCREENGRAB_H
|
|
||||||
#define SCREENGRAB_H
|
|
||||||
|
|
||||||
#include "../base/types.h"
|
|
||||||
// #include "../base/MMBitmap_c.h"
|
|
||||||
#include "../base/bitmap_free_c.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Returns a raw bitmap of screengrab of the display (to be destroyed()'d by
|
|
||||||
* caller), or NULL on error. */
|
|
||||||
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* SCREENGRAB_H */
|
|
@ -1,49 +1,101 @@
|
|||||||
#include "screengrab.h"
|
#include "../base/bitmap_free_c.h"
|
||||||
// #include "../base/bmp_io_c.h"
|
|
||||||
#include "../base/endian.h"
|
|
||||||
#include <stdlib.h> /* malloc() */
|
#include <stdlib.h> /* malloc() */
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
#include <OpenGL/OpenGL.h>
|
#include <OpenGL/OpenGL.h>
|
||||||
#include <OpenGL/gl.h>
|
#include <OpenGL/gl.h>
|
||||||
#include <ApplicationServices/ApplicationServices.h>
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
|
#include <ScreenCaptureKit/ScreenCaptureKit.h>
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
#include "../base/xdisplay_c.h"
|
#include "../base/xdisplay_c.h"
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
// #include "windows.h"
|
|
||||||
// #include <wingdi.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#endif
|
#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)
|
#if defined(IS_MACOSX)
|
||||||
MMBitmapRef bitmap = NULL;
|
MMBitmapRef bitmap = NULL;
|
||||||
uint8_t *buffer = NULL;
|
uint8_t *buffer = NULL;
|
||||||
size_t bufferSize = 0;
|
size_t bufferSize = 0;
|
||||||
|
|
||||||
CGDirectDisplayID displayID = (CGDirectDisplayID) display_id;
|
CGDirectDisplayID displayID = (CGDirectDisplayID) display_id;
|
||||||
if (displayID == -1) {
|
if (displayID == -1 || displayID == 0) {
|
||||||
displayID = CGMainDisplayID();
|
displayID = CGMainDisplayID();
|
||||||
}
|
}
|
||||||
|
|
||||||
CGImageRef image = CGDisplayCreateImageForRect(displayID,
|
MMPointInt32 o = rect.origin; MMSizeInt32 s = rect.size;
|
||||||
CGRectMake(rect.origin.x, rect.origin.y, rect.size.w, rect.size.h));
|
#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; }
|
if (!image) { return NULL; }
|
||||||
|
|
||||||
CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image));
|
CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image));
|
||||||
if (!imageData) { return NULL; }
|
if (!imageData) { return NULL; }
|
||||||
|
|
||||||
bufferSize = CFDataGetLength(imageData);
|
bufferSize = CFDataGetLength(imageData);
|
||||||
buffer = malloc(bufferSize);
|
buffer = malloc(bufferSize);
|
||||||
|
|
||||||
CFDataGetBytes(imageData, CFRangeMake(0, bufferSize), buffer);
|
CFDataGetBytes(imageData, CFRangeMake(0, bufferSize), buffer);
|
||||||
|
|
||||||
bitmap = createMMBitmap_c(buffer,
|
bitmap = createMMBitmap_c(buffer,
|
||||||
CGImageGetWidth(image), CGImageGetHeight(image),
|
CGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBytesPerRow(image),
|
||||||
CGImageGetBytesPerRow(image), CGImageGetBitsPerPixel(image),
|
CGImageGetBitsPerPixel(image), CGImageGetBitsPerPixel(image) / 8);
|
||||||
CGImageGetBitsPerPixel(image) / 8);
|
|
||||||
|
|
||||||
CFRelease(imageData);
|
CFRelease(imageData);
|
||||||
CGImageRelease(image);
|
CGImageRelease(image);
|
||||||
@ -58,16 +110,16 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id)
|
|||||||
display = XGetMainDisplay();
|
display = XGetMainDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
XImage *image = XGetImage(display, XDefaultRootWindow(display),
|
MMPointInt32 o = rect.origin; MMSizeInt32 s = rect.size;
|
||||||
(int)rect.origin.x, (int)rect.origin.y,
|
XImage *image = XGetImage(display, XDefaultRootWindow(display),
|
||||||
(unsigned int)rect.size.w, (unsigned int)rect.size.h,
|
(int)o.x, (int)o.y, (unsigned int)s.w, (unsigned int)s.h,
|
||||||
AllPlanes, ZPixmap);
|
AllPlanes, ZPixmap);
|
||||||
XCloseDisplay(display);
|
XCloseDisplay(display);
|
||||||
if (image == NULL) { return NULL; }
|
if (image == NULL) { return NULL; }
|
||||||
|
|
||||||
bitmap = createMMBitmap_c((uint8_t *)image->data,
|
bitmap = createMMBitmap_c((uint8_t *)image->data,
|
||||||
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);
|
(uint8_t)image->bits_per_pixel, (uint8_t)image->bits_per_pixel / 8);
|
||||||
image->data = NULL; /* Steal ownership of bitmap data so we don't have to copy it. */
|
image->data = NULL; /* Steal ownership of bitmap data so we don't have to copy it. */
|
||||||
XDestroyImage(image);
|
XDestroyImage(image);
|
||||||
|
|
||||||
@ -79,46 +131,52 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id)
|
|||||||
HBITMAP dib;
|
HBITMAP dib;
|
||||||
BITMAPINFO bi;
|
BITMAPINFO bi;
|
||||||
|
|
||||||
|
int32_t x = rect.origin.x, y = rect.origin.y;
|
||||||
|
int32_t w = rect.size.w, h = rect.size.h;
|
||||||
|
|
||||||
/* Initialize bitmap info. */
|
/* Initialize bitmap info. */
|
||||||
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
|
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
|
||||||
bi.bmiHeader.biWidth = (long)rect.size.w;
|
bi.bmiHeader.biWidth = (long) w;
|
||||||
bi.bmiHeader.biHeight = -(long)rect.size.h; /* Non-cartesian, please */
|
bi.bmiHeader.biHeight = -(long) h; /* Non-cartesian, please */
|
||||||
bi.bmiHeader.biPlanes = 1;
|
bi.bmiHeader.biPlanes = 1;
|
||||||
bi.bmiHeader.biBitCount = 32;
|
bi.bmiHeader.biBitCount = 32;
|
||||||
bi.bmiHeader.biCompression = BI_RGB;
|
bi.bmiHeader.biCompression = BI_RGB;
|
||||||
bi.bmiHeader.biSizeImage = (DWORD)(4 * rect.size.w * rect.size.h);
|
bi.bmiHeader.biSizeImage = (DWORD)(4 * w * h);
|
||||||
bi.bmiHeader.biXPelsPerMeter = 0;
|
bi.bmiHeader.biXPelsPerMeter = 0;
|
||||||
bi.bmiHeader.biYPelsPerMeter = 0;
|
bi.bmiHeader.biYPelsPerMeter = 0;
|
||||||
bi.bmiHeader.biClrUsed = 0;
|
bi.bmiHeader.biClrUsed = 0;
|
||||||
bi.bmiHeader.biClrImportant = 0;
|
bi.bmiHeader.biClrImportant = 0;
|
||||||
|
|
||||||
if (display_id == -1) {
|
HWND hwnd;
|
||||||
screen = GetDC(NULL); /* Get entire screen */
|
if (display_id == -1 || isPid == 0) {
|
||||||
|
// screen = GetDC(NULL); /* Get entire screen */
|
||||||
|
hwnd = GetDesktopWindow();
|
||||||
} else {
|
} else {
|
||||||
screen = GetDC((HWND) (uintptr) display_id);
|
hwnd = (HWND) (uintptr) display_id;
|
||||||
}
|
}
|
||||||
|
screen = GetDC(hwnd);
|
||||||
|
|
||||||
if (screen == NULL) { return NULL; }
|
if (screen == NULL) { return NULL; }
|
||||||
|
|
||||||
|
// Todo: Use DXGI
|
||||||
|
screenMem = CreateCompatibleDC(screen);
|
||||||
/* Get screen data in display device context. */
|
/* Get screen data in display device context. */
|
||||||
dib = CreateDIBSection(screen, &bi, DIB_RGB_COLORS, &data, NULL, 0);
|
dib = CreateDIBSection(screen, &bi, DIB_RGB_COLORS, &data, NULL, 0);
|
||||||
|
|
||||||
/* Copy the data into a bitmap struct. */
|
/* Copy the data into a bitmap struct. */
|
||||||
if ((screenMem = CreateCompatibleDC(screen)) == NULL ||
|
BOOL b = (screenMem == NULL) ||
|
||||||
SelectObject(screenMem, dib) == NULL ||
|
SelectObject(screenMem, dib) == NULL ||
|
||||||
!BitBlt(screenMem, (int)0, (int)0, (int)rect.size.w, (int)rect.size.h,
|
!BitBlt(screenMem, (int)0, (int)0, (int)w, (int)h, screen, x, y, SRCCOPY);
|
||||||
screen, rect.origin.x, rect.origin.y, SRCCOPY)
|
if (b) {
|
||||||
) {
|
|
||||||
|
|
||||||
/* Error copying data. */
|
/* Error copying data. */
|
||||||
ReleaseDC(NULL, screen);
|
ReleaseDC(hwnd, screen);
|
||||||
DeleteObject(dib);
|
DeleteObject(dib);
|
||||||
if (screenMem != NULL) { DeleteDC(screenMem); }
|
if (screenMem != NULL) { DeleteDC(screenMem); }
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap = createMMBitmap_c(NULL, rect.size.w, rect.size.h, 4 * rect.size.w,
|
bitmap = createMMBitmap_c(NULL, w, h, 4 * w, (uint8_t)bi.bmiHeader.biBitCount, 4);
|
||||||
(uint8_t)bi.bmiHeader.biBitCount, 4);
|
|
||||||
|
|
||||||
/* Copy the data to our pixel buffer. */
|
/* Copy the data to our pixel buffer. */
|
||||||
if (bitmap != NULL) {
|
if (bitmap != NULL) {
|
||||||
@ -126,7 +184,7 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id)
|
|||||||
memcpy(bitmap->imageBuffer, data, bitmap->bytewidth * bitmap->height);
|
memcpy(bitmap->imageBuffer, data, bitmap->bytewidth * bitmap->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseDC(NULL, screen);
|
ReleaseDC(hwnd, screen);
|
||||||
DeleteObject(dib);
|
DeleteObject(dib);
|
||||||
DeleteDC(screenMem);
|
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
|
@ -1,14 +1,13 @@
|
|||||||
// #include "os.h"
|
// #include "os.h"
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
#define CFStringCreateWithUTF8String(string) \
|
CFStringRef CFStringCreateWithUTF8String(const char *title) {
|
||||||
((string) == NULL ? NULL : CFStringCreateWithCString(NULL, \
|
if (title == NULL) { return NULL; }
|
||||||
string, \
|
return CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
|
||||||
kCFStringEncodingUTF8))
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int showAlert(const char *title, const char *msg,
|
int showAlert(const char *title, const char *msg,
|
||||||
@ -19,6 +18,7 @@ int showAlert(const char *title, const char *msg,
|
|||||||
CFStringRef defaultButtonTitle = CFStringCreateWithUTF8String(defaultButton);
|
CFStringRef defaultButtonTitle = CFStringCreateWithUTF8String(defaultButton);
|
||||||
CFStringRef cancelButtonTitle = CFStringCreateWithUTF8String(cancelButton);
|
CFStringRef cancelButtonTitle = CFStringCreateWithUTF8String(cancelButton);
|
||||||
CFOptionFlags responseFlags;
|
CFOptionFlags responseFlags;
|
||||||
|
|
||||||
SInt32 err = CFUserNotificationDisplayAlert(
|
SInt32 err = CFUserNotificationDisplayAlert(
|
||||||
0.0, kCFUserNotificationNoteAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage,
|
0.0, kCFUserNotificationNoteAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage,
|
||||||
defaultButtonTitle, cancelButtonTitle, NULL, &responseFlags);
|
defaultButtonTitle, cancelButtonTitle, NULL, &responseFlags);
|
||||||
@ -33,10 +33,9 @@ int showAlert(const char *title, const char *msg,
|
|||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
/* TODO: Display custom buttons instead of the pre-defined "OK"
|
/* TODO: Display custom buttons instead of the pre-defined "OK" and "Cancel". */
|
||||||
* and "Cancel". */
|
|
||||||
int response = MessageBox(NULL, msg, title,
|
int response = MessageBox(NULL, msg, title,
|
||||||
(cancelButton == NULL) ? MB_OK : MB_OKCANCEL);
|
(cancelButton == NULL) ? MB_OK : MB_OKCANCEL );
|
||||||
return (response == IDOK) ? 0 : 1;
|
return (response == IDOK) ? 0 : 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -12,53 +12,23 @@
|
|||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "win_sys.h"
|
#include "win_sys.h"
|
||||||
|
|
||||||
int show_alert(const char *title, const char *msg,
|
void min_window(uintptr pid, bool state, int8_t isPid){
|
||||||
const char *defaultButton, const char *cancelButton){
|
|
||||||
|
|
||||||
int alert = showAlert(title, msg, defaultButton, cancelButton);
|
|
||||||
return alert;
|
|
||||||
}
|
|
||||||
|
|
||||||
intptr scale_x(){
|
|
||||||
return scaleX();
|
|
||||||
}
|
|
||||||
|
|
||||||
intptr scale_y(){
|
|
||||||
return scaleY();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_valid(){
|
|
||||||
bool abool = IsValid();
|
|
||||||
return abool;
|
|
||||||
}
|
|
||||||
|
|
||||||
// int find_window(char* name){
|
|
||||||
// int z = findwindow(name);
|
|
||||||
// return z;
|
|
||||||
// }
|
|
||||||
|
|
||||||
void min_window(uintptr pid, bool state, uintptr isHwnd){
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
// return 0;
|
// return 0;
|
||||||
AXUIElementRef axID = AXUIElementCreateApplication(pid);
|
AXUIElementRef axID = AXUIElementCreateApplication(pid);
|
||||||
|
AXUIElementSetAttributeValue(axID, kAXMinimizedAttribute,
|
||||||
AXUIElementSetAttributeValue(axID, kAXMinimizedAttribute,
|
state ? kCFBooleanTrue : kCFBooleanFalse);
|
||||||
state ? kCFBooleanTrue : kCFBooleanFalse);
|
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
// Ignore X errors
|
// Ignore X errors
|
||||||
XDismissErrors();
|
XDismissErrors();
|
||||||
// SetState((Window)pid, STATE_MINIMIZE, state);
|
// SetState((Window)pid, STATE_MINIMIZE, state);
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
if (isHwnd == 0) {
|
HWND hwnd = getHwnd(pid, isPid);
|
||||||
HWND hwnd = GetHwndByPId(pid);
|
win_min(hwnd, state);
|
||||||
win_min(hwnd, state);
|
|
||||||
} else {
|
|
||||||
win_min((HWND)pid, state);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void max_window(uintptr pid, bool state, uintptr isHwnd){
|
void max_window(uintptr pid, bool state, int8_t isPid){
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
// return 0;
|
// return 0;
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
@ -66,26 +36,13 @@ void max_window(uintptr pid, bool state, uintptr isHwnd){
|
|||||||
// SetState((Window)pid, STATE_MINIMIZE, false);
|
// SetState((Window)pid, STATE_MINIMIZE, false);
|
||||||
// SetState((Window)pid, STATE_MAXIMIZE, state);
|
// SetState((Window)pid, STATE_MAXIMIZE, state);
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
if (isHwnd == 0) {
|
HWND hwnd = getHwnd(pid, isPid);
|
||||||
HWND hwnd = GetHwndByPId(pid);
|
win_max(hwnd, state);
|
||||||
win_max(hwnd, state);
|
|
||||||
} else {
|
|
||||||
win_max((HWND)pid, state);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_window(uintptr pid, uintptr isHwnd){
|
|
||||||
close_window_by_PId(pid, isHwnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool set_handle(uintptr handle){
|
|
||||||
bool hwnd = setHandle(handle);
|
|
||||||
return hwnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr get_handle(){
|
uintptr get_handle(){
|
||||||
MData mData = GetActive();
|
MData mData = get_active();
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
return (uintptr)mData.CgID;
|
return (uintptr)mData.CgID;
|
||||||
@ -96,32 +53,17 @@ uintptr get_handle(){
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr bget_handle(){
|
uintptr b_get_handle() {
|
||||||
uintptr hwnd = getHandle();
|
#if defined(IS_MACOSX)
|
||||||
return hwnd;
|
return (uintptr)pub_mData.CgID;
|
||||||
|
#elif defined(USE_X11)
|
||||||
|
return (uintptr)pub_mData.XWin;
|
||||||
|
#elif defined(IS_WINDOWS)
|
||||||
|
return (uintptr)pub_mData.HWnd;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_active(const MData win){
|
void active_PID(uintptr pid, int8_t isPid){
|
||||||
SetActive(win);
|
MData win = set_handle_pid(pid, isPid);
|
||||||
}
|
set_active(win);
|
||||||
|
|
||||||
void active_PID(uintptr pid, uintptr isHwnd){
|
|
||||||
MData win = set_handle_pid(pid, isHwnd);
|
|
||||||
SetActive(win);
|
|
||||||
}
|
|
||||||
|
|
||||||
MData get_active(){
|
|
||||||
MData mdata = GetActive();
|
|
||||||
return mdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* get_title(uintptr pid, uintptr isHwnd){
|
|
||||||
char* title = get_title_by_pid(pid, isHwnd);
|
|
||||||
// printf("title::::%s\n", title );
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t get_PID(void){
|
|
||||||
int pid = WGetPID();
|
|
||||||
return pid;
|
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ struct _MData{
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _MData MData;
|
typedef struct _MData MData;
|
||||||
MData mData;
|
MData pub_mData;
|
||||||
|
|
||||||
struct _Bounds {
|
struct _Bounds {
|
||||||
int32_t X; // Top left X coordinate
|
int32_t X; // Top left X coordinate
|
||||||
@ -46,7 +46,6 @@ typedef struct _Bounds Bounds;
|
|||||||
static AXUIElementRef GetUIElement(CGWindowID win){
|
static AXUIElementRef GetUIElement(CGWindowID win){
|
||||||
intptr pid = 0;
|
intptr pid = 0;
|
||||||
// double_t pid = 0;
|
// double_t pid = 0;
|
||||||
|
|
||||||
// Create array storing window
|
// Create array storing window
|
||||||
CGWindowID window[1] = { win };
|
CGWindowID window[1] = { win };
|
||||||
CFArrayRef wlist = CFArrayCreate(NULL, (const void**)window, 1, NULL);
|
CFArrayRef wlist = CFArrayCreate(NULL, (const void**)window, 1, NULL);
|
||||||
@ -59,7 +58,6 @@ typedef struct _Bounds Bounds;
|
|||||||
if (info != NULL && CFArrayGetCount(info) > 0) {
|
if (info != NULL && CFArrayGetCount(info) > 0) {
|
||||||
// Retrieve description from info array
|
// Retrieve description from info array
|
||||||
CFDictionaryRef desc = (CFDictionaryRef)CFArrayGetValueAtIndex(info, 0);
|
CFDictionaryRef desc = (CFDictionaryRef)CFArrayGetValueAtIndex(info, 0);
|
||||||
|
|
||||||
// Get window PID
|
// Get window PID
|
||||||
CFNumberRef data = (CFNumberRef) CFDictionaryGetValue(desc, kCGWindowOwnerPID);
|
CFNumberRef data = (CFNumberRef) CFDictionaryGetValue(desc, kCGWindowOwnerPID);
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
@ -193,6 +191,7 @@ typedef struct _Bounds Bounds;
|
|||||||
if (items != NULL) {
|
if (items != NULL) {
|
||||||
*items = (uint32_t) nItems;
|
*items = (uint32_t) nItems;
|
||||||
}
|
}
|
||||||
|
XCloseDisplay(rDisplay);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,7 +268,8 @@ typedef struct _Bounds Bounds;
|
|||||||
|
|
||||||
|
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
//
|
HWND getHwnd(uintptr pid, int8_t isPid);
|
||||||
|
|
||||||
void win_min(HWND hwnd, bool state){
|
void win_min(HWND hwnd, bool state){
|
||||||
if (state) {
|
if (state) {
|
||||||
ShowWindow(hwnd, SW_MINIMIZE);
|
ShowWindow(hwnd, SW_MINIMIZE);
|
||||||
|
129
window/win_sys.h
129
window/win_sys.h
@ -8,90 +8,16 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// #include "../base/os.h"
|
// #if defined(USE_X11)
|
||||||
#if defined(USE_X11)
|
// #include <X11/Xresource.h>
|
||||||
// #include <X11/Xlib.h>
|
// #endif
|
||||||
// #include <X11/Xatom.h>
|
|
||||||
#include <X11/Xresource.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Bounds get_client(uintptr pid, uintptr isHwnd);
|
Bounds get_client(uintptr pid, int8_t isPid);
|
||||||
intptr scaleX();
|
|
||||||
|
|
||||||
double sys_scale(int32_t display_id) {
|
Bounds get_bounds(uintptr pid, int8_t isPid){
|
||||||
#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
|
|
||||||
}
|
|
||||||
|
|
||||||
intptr scaleY(){
|
|
||||||
#if defined(IS_MACOSX)
|
|
||||||
return 0;
|
|
||||||
#elif defined(USE_X11)
|
|
||||||
return 0;
|
|
||||||
#elif defined(IS_WINDOWS)
|
|
||||||
HDC desktopDc = GetDC(NULL);
|
|
||||||
intptr verticalDPI = GetDeviceCaps(desktopDc, LOGPIXELSY);
|
|
||||||
return verticalDPI;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
Bounds get_bounds(uintptr pid, uintptr isHwnd){
|
|
||||||
// Check if the window is valid
|
// Check if the window is valid
|
||||||
Bounds bounds;
|
Bounds bounds;
|
||||||
if (!IsValid()) { return bounds; }
|
if (!is_valid()) { return bounds; }
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
// Bounds bounds;
|
// Bounds bounds;
|
||||||
@ -100,22 +26,20 @@ Bounds get_bounds(uintptr pid, uintptr isHwnd){
|
|||||||
AXUIElementRef AxID = AXUIElementCreateApplication(pid);
|
AXUIElementRef AxID = AXUIElementCreateApplication(pid);
|
||||||
|
|
||||||
// Determine the current point of the window
|
// Determine the current point of the window
|
||||||
if (AXUIElementCopyAttributeValue(
|
if (AXUIElementCopyAttributeValue(AxID, kAXPositionAttribute, (CFTypeRef*) &axp)
|
||||||
AxID, kAXPositionAttribute, (CFTypeRef*) &axp)
|
|
||||||
!= kAXErrorSuccess || axp == NULL){
|
!= kAXErrorSuccess || axp == NULL){
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the current size of the window
|
// Determine the current size of the window
|
||||||
if (AXUIElementCopyAttributeValue(
|
if (AXUIElementCopyAttributeValue(AxID, kAXSizeAttribute, (CFTypeRef*) &axs)
|
||||||
AxID, kAXSizeAttribute, (CFTypeRef*) &axs)
|
|
||||||
!= kAXErrorSuccess || axs == NULL){
|
!= kAXErrorSuccess || axs == NULL){
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGPoint p; CGSize s;
|
CGPoint p; CGSize s;
|
||||||
// Attempt to convert both values into atomic types
|
// Attempt to convert both values into atomic types
|
||||||
if (AXValueGetValue(axp, kAXValueCGPointType, &p) &&
|
if (AXValueGetValue(axp, kAXValueCGPointType, &p) &&
|
||||||
AXValueGetValue(axs, kAXValueCGSizeType, &s)){
|
AXValueGetValue(axs, kAXValueCGSizeType, &s)){
|
||||||
bounds.X = p.x;
|
bounds.X = p.x;
|
||||||
bounds.Y = p.y;
|
bounds.Y = p.y;
|
||||||
@ -135,7 +59,7 @@ Bounds get_bounds(uintptr pid, uintptr isHwnd){
|
|||||||
MData win;
|
MData win;
|
||||||
win.XWin = (Window)pid;
|
win.XWin = (Window)pid;
|
||||||
|
|
||||||
Bounds client = get_client(pid, isHwnd);
|
Bounds client = get_client(pid, isPid);
|
||||||
Bounds frame = GetFrame(win);
|
Bounds frame = GetFrame(win);
|
||||||
|
|
||||||
bounds.X = client.X - frame.X;
|
bounds.X = client.X - frame.X;
|
||||||
@ -145,12 +69,7 @@ Bounds get_bounds(uintptr pid, uintptr isHwnd){
|
|||||||
|
|
||||||
return bounds;
|
return bounds;
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
HWND hwnd;
|
HWND hwnd = getHwnd(pid, isPid);
|
||||||
if (isHwnd == 0) {
|
|
||||||
hwnd= GetHwndByPId(pid);
|
|
||||||
} else {
|
|
||||||
hwnd = (HWND)pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
RECT rect = { 0 };
|
RECT rect = { 0 };
|
||||||
GetWindowRect(hwnd, &rect);
|
GetWindowRect(hwnd, &rect);
|
||||||
@ -164,13 +83,13 @@ Bounds get_bounds(uintptr pid, uintptr isHwnd){
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Bounds get_client(uintptr pid, uintptr isHwnd) {
|
Bounds get_client(uintptr pid, int8_t isPid) {
|
||||||
// Check if the window is valid
|
// Check if the window is valid
|
||||||
Bounds bounds;
|
Bounds bounds;
|
||||||
if (!IsValid()) { return bounds; }
|
if (!is_valid()) { return bounds; }
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
return get_bounds(pid, isHwnd);
|
return get_bounds(pid, isPid);
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
Display *rDisplay = XOpenDisplay(NULL);
|
Display *rDisplay = XOpenDisplay(NULL);
|
||||||
|
|
||||||
@ -186,8 +105,7 @@ Bounds get_client(uintptr pid, uintptr isHwnd) {
|
|||||||
int32_t x = 0, y = 0;
|
int32_t x = 0, y = 0;
|
||||||
|
|
||||||
// Check if the window is the root
|
// Check if the window is the root
|
||||||
XQueryTree(rDisplay, win.XWin,
|
XQueryTree(rDisplay, win.XWin, &root, &parent, &children, &count);
|
||||||
&root, &parent, &children, &count);
|
|
||||||
if (children) { XFree(children); }
|
if (children) { XFree(children); }
|
||||||
|
|
||||||
// Retrieve window attributes
|
// Retrieve window attributes
|
||||||
@ -195,12 +113,9 @@ Bounds get_client(uintptr pid, uintptr isHwnd) {
|
|||||||
XGetWindowAttributes(rDisplay, win.XWin, &attr);
|
XGetWindowAttributes(rDisplay, win.XWin, &attr);
|
||||||
|
|
||||||
// Coordinates must be translated
|
// Coordinates must be translated
|
||||||
if (parent != attr.root){
|
if (parent != attr.root) {
|
||||||
XTranslateCoordinates(rDisplay, win.XWin, attr.root, attr.x,
|
XTranslateCoordinates(rDisplay, win.XWin, attr.root, attr.x, attr.y, &x, &y, &parent);
|
||||||
attr.y, &x, &y, &parent);
|
} else {
|
||||||
}
|
|
||||||
// Coordinates can be left alone
|
|
||||||
else {
|
|
||||||
x = attr.x;
|
x = attr.x;
|
||||||
y = attr.y;
|
y = attr.y;
|
||||||
}
|
}
|
||||||
@ -214,13 +129,7 @@ Bounds get_client(uintptr pid, uintptr isHwnd) {
|
|||||||
|
|
||||||
return bounds;
|
return bounds;
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
HWND hwnd;
|
HWND hwnd = getHwnd(pid, isPid);
|
||||||
if (isHwnd == 0) {
|
|
||||||
hwnd= GetHwndByPId(pid);
|
|
||||||
} else {
|
|
||||||
hwnd = (HWND)pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RECT rect = { 0 };
|
RECT rect = { 0 };
|
||||||
GetClientRect(hwnd, &rect);
|
GetClientRect(hwnd, &rect);
|
||||||
|
1
window/window.go
Normal file
1
window/window.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package window
|
212
window/window.h
212
window/window.h
@ -8,14 +8,14 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// #include "../base/os.h"
|
|
||||||
#include "pub.h"
|
#include "pub.h"
|
||||||
|
|
||||||
bool setHandle(uintptr handle);
|
bool setHandle(uintptr handle);
|
||||||
bool IsValid();
|
bool is_valid();
|
||||||
bool IsAxEnabled(bool options);
|
bool IsAxEnabled(bool options);
|
||||||
MData GetActive(void);
|
|
||||||
void initWindow();
|
MData get_active(void);
|
||||||
|
void initWindow(uintptr handle);
|
||||||
char* get_title_by_hand(MData m_data);
|
char* get_title_by_hand(MData m_data);
|
||||||
void close_window_by_Id(MData m_data);
|
void close_window_by_Id(MData m_data);
|
||||||
|
|
||||||
@ -24,8 +24,8 @@ uintptr initHandle = 0;
|
|||||||
|
|
||||||
void initWindow(uintptr handle){
|
void initWindow(uintptr handle){
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
mData.CgID = 0;
|
pub_mData.CgID = 0;
|
||||||
mData.AxID = 0;
|
pub_mData.AxID = 0;
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
Display *rDisplay = XOpenDisplay(NULL);
|
Display *rDisplay = XOpenDisplay(NULL);
|
||||||
// If atoms loaded
|
// If atoms loaded
|
||||||
@ -34,10 +34,10 @@ void initWindow(uintptr handle){
|
|||||||
if (rDisplay != NULL) {LoadAtoms();}
|
if (rDisplay != NULL) {LoadAtoms();}
|
||||||
}
|
}
|
||||||
|
|
||||||
mData.XWin = 0;
|
pub_mData.XWin = 0;
|
||||||
XCloseDisplay(rDisplay);
|
XCloseDisplay(rDisplay);
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
mData.HWnd = 0;
|
pub_mData.HWnd = 0;
|
||||||
#endif
|
#endif
|
||||||
setHandle(handle);
|
setHandle(handle);
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ bool Is64Bit() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MData set_handle_pid(uintptr pid, uintptr isHwnd){
|
MData set_handle_pid(uintptr pid, int8_t isPid){
|
||||||
MData win;
|
MData win;
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
// Handle to a AXUIElementRef
|
// 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
|
win.XWin = (Window)pid; // Handle to an X11 window
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
// win.HWnd = (HWND)pid; // Handle to a window HWND
|
// win.HWnd = (HWND)pid; // Handle to a window HWND
|
||||||
if (isHwnd == 0) {
|
win.HWnd = getHwnd(pid, isPid);
|
||||||
win.HWnd = GetHwndByPId(pid);
|
|
||||||
} else {
|
|
||||||
win.HWnd = (HWND)pid;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return win;
|
return win;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_handle_pid_mData(uintptr pid, uintptr isHwnd){
|
void set_handle_pid_mData(uintptr pid, int8_t isPid){
|
||||||
MData win = set_handle_pid(pid, isHwnd);
|
MData win = set_handle_pid(pid, isPid);
|
||||||
mData = win;
|
pub_mData = win;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValid(){
|
bool is_valid() {
|
||||||
initWindow(initHandle);
|
initWindow(initHandle);
|
||||||
if (!IsAxEnabled(true)) {
|
if (!IsAxEnabled(true)) {
|
||||||
printf("%s\n", "Window: Accessibility API is disabled!\n"
|
printf("%s\n", "Window: Accessibility API is disabled! "
|
||||||
"Failed to enable access for assistive devices.");
|
"Failed to enable access for assistive devices. \n");
|
||||||
}
|
}
|
||||||
MData actdata = GetActive();
|
MData actdata = get_active();
|
||||||
|
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
mData.CgID = actdata.CgID;
|
pub_mData.CgID = actdata.CgID;
|
||||||
mData.AxID = actdata.AxID;
|
pub_mData.AxID = actdata.AxID;
|
||||||
if (mData.CgID == 0 || mData.AxID == 0){ return false; }
|
if (pub_mData.CgID == 0 || pub_mData.AxID == 0) { return false; }
|
||||||
|
|
||||||
CFTypeRef r = NULL;
|
CFTypeRef r = NULL;
|
||||||
// Attempt to get the window role
|
// Attempt to get the window role
|
||||||
if (AXUIElementCopyAttributeValue(mData.AxID, kAXRoleAttribute, &r) == kAXErrorSuccess && r){
|
if (AXUIElementCopyAttributeValue(pub_mData.AxID, kAXRoleAttribute, &r) == kAXErrorSuccess && r){
|
||||||
CFRelease(r);
|
CFRelease(r);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
mData.XWin = actdata.XWin;
|
pub_mData.XWin = actdata.XWin;
|
||||||
if (mData.XWin == 0) { return false; }
|
if (pub_mData.XWin == 0) { return false; }
|
||||||
|
|
||||||
Display *rDisplay = XOpenDisplay(NULL);
|
Display *rDisplay = XOpenDisplay(NULL);
|
||||||
// Check for a valid X-Window display
|
// Check for a valid X-Window display
|
||||||
@ -107,8 +103,11 @@ bool IsValid(){
|
|||||||
XDismissErrors();
|
XDismissErrors();
|
||||||
|
|
||||||
// Get the window PID property
|
// Get the window PID property
|
||||||
void* result = GetWindowProperty(mData, WM_PID,NULL);
|
void* result = GetWindowProperty(pub_mData, WM_PID,NULL);
|
||||||
if (result == NULL) { return false; }
|
if (result == NULL) {
|
||||||
|
XCloseDisplay(rDisplay);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Free result and return true
|
// Free result and return true
|
||||||
XFree(result);
|
XFree(result);
|
||||||
@ -116,12 +115,12 @@ bool IsValid(){
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
mData.HWnd = actdata.HWnd;
|
pub_mData.HWnd = actdata.HWnd;
|
||||||
if (mData.HWnd == 0) {
|
if (pub_mData.HWnd == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return IsWindow(mData.HWnd) != 0;
|
return IsWindow(pub_mData.HWnd) != 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,16 +130,13 @@ bool IsAxEnabled(bool options){
|
|||||||
static dispatch_once_t once; dispatch_once (&once,
|
static dispatch_once_t once; dispatch_once (&once,
|
||||||
^{
|
^{
|
||||||
// Open the framework
|
// Open the framework
|
||||||
void* handle = dlopen("/System/Library/Frameworks/Application"
|
void* handle = dlopen("/System/Library/Frameworks/Application"
|
||||||
"Services.framework/ApplicationServices", RTLD_LAZY);
|
"Services.framework/ApplicationServices", RTLD_LAZY);
|
||||||
|
|
||||||
// Validate the handle
|
// Validate the handle
|
||||||
if (handle != NULL) {
|
if (handle != NULL) {
|
||||||
*(void**) (&gAXIsProcessTrustedWithOptions) =
|
*(void**) (&gAXIsProcessTrustedWithOptions) = dlsym (handle, "AXIsProcessTrustedWithOptions");
|
||||||
dlsym (handle, "AXIsProcessTrustedWithOptions");
|
gkAXTrustedCheckOptionPrompt = (CFStringRef*) dlsym (handle, "kAXTrustedCheckOptionPrompt");
|
||||||
|
|
||||||
gkAXTrustedCheckOptionPrompt =
|
|
||||||
(CFStringRef*) dlsym (handle, "kAXTrustedCheckOptionPrompt");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -156,7 +152,6 @@ bool IsAxEnabled(bool options){
|
|||||||
|
|
||||||
// Determine whether the process is actually trusted
|
// Determine whether the process is actually trusted
|
||||||
bool result = (*gAXIsProcessTrustedWithOptions)(o);
|
bool result = (*gAXIsProcessTrustedWithOptions)(o);
|
||||||
|
|
||||||
// Free memory
|
// Free memory
|
||||||
CFRelease(o);
|
CFRelease(o);
|
||||||
return result;
|
return result;
|
||||||
@ -180,13 +175,13 @@ bool IsAxEnabled(bool options){
|
|||||||
bool setHandle(uintptr handle){
|
bool setHandle(uintptr handle){
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
// Release the AX element
|
// Release the AX element
|
||||||
if (mData.AxID != NULL) {
|
if (pub_mData.AxID != NULL) {
|
||||||
CFRelease(mData.AxID);
|
CFRelease(pub_mData.AxID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset both values
|
// Reset both values
|
||||||
mData.CgID = 0;
|
pub_mData.CgID = 0;
|
||||||
mData.AxID = 0;
|
pub_mData.AxID = 0;
|
||||||
|
|
||||||
if (handle == 0) {
|
if (handle == 0) {
|
||||||
// return 0;
|
// return 0;
|
||||||
@ -197,8 +192,8 @@ bool setHandle(uintptr handle){
|
|||||||
CGWindowID cgID = (CGWindowID)handle;
|
CGWindowID cgID = (CGWindowID)handle;
|
||||||
AXUIElementRef axID = GetUIElement(cgID);
|
AXUIElementRef axID = GetUIElement(cgID);
|
||||||
if (axID != NULL){
|
if (axID != NULL){
|
||||||
mData.CgID = cgID;
|
pub_mData.CgID = cgID;
|
||||||
mData.AxID = axID;
|
pub_mData.AxID = axID;
|
||||||
// return 0;
|
// return 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -206,46 +201,35 @@ bool setHandle(uintptr handle){
|
|||||||
// return 1;
|
// return 1;
|
||||||
return false;
|
return false;
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
mData.XWin = (Window)handle;
|
pub_mData.XWin = (Window)handle;
|
||||||
if (handle == 0){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsValid()){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mData.XWin = 0;
|
|
||||||
return false;
|
|
||||||
#elif defined(IS_WINDOWS)
|
|
||||||
mData.HWnd = (HWND)handle;
|
|
||||||
if (handle == 0) {
|
if (handle == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsValid()) {
|
if (is_valid()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mData.HWnd = 0;
|
pub_mData.XWin = 0;
|
||||||
|
return false;
|
||||||
|
#elif defined(IS_WINDOWS)
|
||||||
|
pub_mData.HWnd = (HWND)handle;
|
||||||
|
if (handle == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_valid()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub_mData.HWnd = 0;
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// uint32 uintptr
|
|
||||||
uintptr getHandle() {
|
|
||||||
#if defined(IS_MACOSX)
|
|
||||||
return (uintptr)mData.CgID;
|
|
||||||
#elif defined(USE_X11)
|
|
||||||
return (uintptr)mData.XWin;
|
|
||||||
#elif defined(IS_WINDOWS)
|
|
||||||
return (uintptr)mData.HWnd;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsTopMost(void){
|
bool IsTopMost(void){
|
||||||
// Check the window validity
|
// Check the window validity
|
||||||
if (!IsValid()) {return false;}
|
if (!is_valid()) { return false; }
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
return false; // WARNING: Unavailable
|
return false; // WARNING: Unavailable
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
@ -253,17 +237,17 @@ bool IsTopMost(void){
|
|||||||
// XDismissErrors ();
|
// XDismissErrors ();
|
||||||
// return GetState (mData.XWin, STATE_TOPMOST);
|
// return GetState (mData.XWin, STATE_TOPMOST);
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
return (GetWindowLongPtr(mData.HWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
|
return (GetWindowLongPtr(pub_mData.HWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsMinimized(void){
|
bool IsMinimized(void){
|
||||||
// Check the window validity
|
// Check the window validity
|
||||||
if (!IsValid()) {return false;}
|
if (!is_valid()) { return false; }
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
CFBooleanRef data = NULL;
|
CFBooleanRef data = NULL;
|
||||||
// Determine whether the window is minimized
|
// Determine whether the window is minimized
|
||||||
if (AXUIElementCopyAttributeValue(mData.AxID, kAXMinimizedAttribute,
|
if (AXUIElementCopyAttributeValue(pub_mData.AxID, kAXMinimizedAttribute,
|
||||||
(CFTypeRef*) &data) == kAXErrorSuccess && data != NULL) {
|
(CFTypeRef*) &data) == kAXErrorSuccess && data != NULL) {
|
||||||
// Convert resulting data into a bool
|
// Convert resulting data into a bool
|
||||||
bool result = CFBooleanGetValue(data);
|
bool result = CFBooleanGetValue(data);
|
||||||
@ -277,14 +261,14 @@ bool IsMinimized(void){
|
|||||||
// XDismissErrors();
|
// XDismissErrors();
|
||||||
// return GetState(mData.XWin, STATE_MINIMIZE);
|
// return GetState(mData.XWin, STATE_MINIMIZE);
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
return (GetWindowLongPtr(mData.HWnd, GWL_STYLE) & WS_MINIMIZE) != 0;
|
return (GetWindowLongPtr(pub_mData.HWnd, GWL_STYLE) & WS_MINIMIZE) != 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//////
|
//////
|
||||||
bool IsMaximized(void){
|
bool IsMaximized(void){
|
||||||
// Check the window validity
|
// Check the window validity
|
||||||
if (!IsValid()) {return false;}
|
if (!is_valid()) { return false; }
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
return false; // WARNING: Unavailable
|
return false; // WARNING: Unavailable
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
@ -292,20 +276,19 @@ bool IsMaximized(void){
|
|||||||
// XDismissErrors();
|
// XDismissErrors();
|
||||||
// return GetState(mData.XWin, STATE_MAXIMIZE);
|
// return GetState(mData.XWin, STATE_MAXIMIZE);
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
return (GetWindowLongPtr(mData.HWnd, GWL_STYLE) & WS_MAXIMIZE) != 0;
|
return (GetWindowLongPtr(pub_mData.HWnd, GWL_STYLE) & WS_MAXIMIZE) != 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetActive(const MData win) {
|
void set_active(const MData win) {
|
||||||
// Check if the window is valid
|
// Check if the window is valid
|
||||||
if (!IsValid()) { return; }
|
if (!is_valid()) { return; }
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
// Attempt to raise the specified window object
|
// Attempt to raise the specified window object
|
||||||
if (AXUIElementPerformAction(win.AxID, kAXRaiseAction) != kAXErrorSuccess) {
|
if (AXUIElementPerformAction(win.AxID, kAXRaiseAction) != kAXErrorSuccess) {
|
||||||
pid_t pid = 0;
|
pid_t pid = 0;
|
||||||
// Attempt to retrieve the PID of the window
|
// Attempt to retrieve the PID of the window
|
||||||
if (AXUIElementGetPid(win.AxID, &pid)
|
if (AXUIElementGetPid(win.AxID, &pid) != kAXErrorSuccess || !pid) { return; }
|
||||||
!= kAXErrorSuccess || !pid) {return;}
|
|
||||||
|
|
||||||
// Ignore deprecated warnings
|
// Ignore deprecated warnings
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
@ -320,7 +303,6 @@ void SetActive(const MData win) {
|
|||||||
|
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
// Ignore X errors
|
// Ignore X errors
|
||||||
XDismissErrors();
|
XDismissErrors();
|
||||||
@ -352,7 +334,6 @@ void SetActive(const MData win) {
|
|||||||
} else {
|
} else {
|
||||||
// Attempt to raise the specified window
|
// Attempt to raise the specified window
|
||||||
XRaiseWindow(rDisplay, win.XWin);
|
XRaiseWindow(rDisplay, win.XWin);
|
||||||
|
|
||||||
// Set the specified window's input focus
|
// Set the specified window's input focus
|
||||||
XSetInputFocus(rDisplay, win.XWin, RevertToParent, CurrentTime);
|
XSetInputFocus(rDisplay, win.XWin, RevertToParent, CurrentTime);
|
||||||
}
|
}
|
||||||
@ -366,7 +347,7 @@ void SetActive(const MData win) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
MData GetActive(void) {
|
MData get_active(void) {
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
MData result;
|
MData result;
|
||||||
// Ignore deprecated warnings
|
// Ignore deprecated warnings
|
||||||
@ -383,14 +364,14 @@ MData GetActive(void) {
|
|||||||
|
|
||||||
// Create accessibility object using focused PID
|
// Create accessibility object using focused PID
|
||||||
AXUIElementRef focused = AXUIElementCreateApplication(pid);
|
AXUIElementRef focused = AXUIElementCreateApplication(pid);
|
||||||
if (focused == NULL) {return result; }// Verify
|
if (focused == NULL) { return result; } // Verify
|
||||||
|
|
||||||
AXUIElementRef element;
|
AXUIElementRef element;
|
||||||
|
CGWindowID win = 0;
|
||||||
// Retrieve the currently focused window
|
// Retrieve the currently focused window
|
||||||
if (AXUIElementCopyAttributeValue(focused, kAXFocusedWindowAttribute, (CFTypeRef*) &element)
|
if (AXUIElementCopyAttributeValue(focused, kAXFocusedWindowAttribute, (CFTypeRef*) &element)
|
||||||
== kAXErrorSuccess && element) {
|
== kAXErrorSuccess && element) {
|
||||||
|
|
||||||
CGWindowID win = 0;
|
|
||||||
// Use undocumented API to get WID
|
// Use undocumented API to get WID
|
||||||
if (_AXUIElementGetWindow(element, &win) == kAXErrorSuccess && win) {
|
if (_AXUIElementGetWindow(element, &win) == kAXErrorSuccess && win) {
|
||||||
// Manually set internals
|
// Manually set internals
|
||||||
@ -399,6 +380,9 @@ MData GetActive(void) {
|
|||||||
} else {
|
} else {
|
||||||
CFRelease(element);
|
CFRelease(element);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
result.CgID = win;
|
||||||
|
result.AxID = element;
|
||||||
}
|
}
|
||||||
CFRelease(focused);
|
CFRelease(focused);
|
||||||
|
|
||||||
@ -427,6 +411,7 @@ MData GetActive(void) {
|
|||||||
if (window != 0) {
|
if (window != 0) {
|
||||||
// Set and return the foreground window
|
// Set and return the foreground window
|
||||||
result.XWin = (Window)window;
|
result.XWin = (Window)window;
|
||||||
|
XCloseDisplay(rDisplay);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,39 +445,37 @@ MData GetActive(void) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SetTopMost(bool state){
|
void SetTopMost(bool state){
|
||||||
// Check window validity
|
// Check window validity
|
||||||
if (!IsValid()) {return;}
|
if (!is_valid()) { return; }
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
// WARNING: Unavailable
|
// WARNING: Unavailable
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
// Ignore X errors
|
// Ignore X errors
|
||||||
// XDismissErrors();
|
// XDismissErrors();
|
||||||
// SetState(mData.XWin, STATE_TOPMOST, state);
|
// SetState(pub_mData.XWin, STATE_TOPMOST, state);
|
||||||
#elif defined(IS_WINDOWS)
|
#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);
|
0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_main_window (){
|
void close_main_window () {
|
||||||
// Check if the window is valid
|
// Check if the window is valid
|
||||||
if (!IsValid()) { return; }
|
if (!is_valid()) { return; }
|
||||||
|
|
||||||
close_window_by_Id(mData);
|
close_window_by_Id(pub_mData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_window_by_PId(uintptr pid, uintptr isHwnd){
|
void close_window_by_PId(uintptr pid, int8_t isPid){
|
||||||
MData win = set_handle_pid(pid, isHwnd);
|
MData win = set_handle_pid(pid, isPid);
|
||||||
close_window_by_Id(win);
|
close_window_by_Id(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// CloseWindow
|
// CloseWindow
|
||||||
void close_window_by_Id(MData m_data){
|
void close_window_by_Id(MData m_data){
|
||||||
// Check window validity
|
// Check window validity
|
||||||
if (!IsValid()) { return; }
|
if (!is_valid()) { return; }
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
AXUIElementRef b = NULL;
|
AXUIElementRef b = NULL;
|
||||||
// Retrieve the close button of this window
|
// Retrieve the close button of this window
|
||||||
@ -517,14 +500,14 @@ void close_window_by_Id(MData m_data){
|
|||||||
|
|
||||||
char* get_main_title(){
|
char* get_main_title(){
|
||||||
// Check if the window is valid
|
// Check if the window is valid
|
||||||
if (!IsValid()) { return "IsValid failed."; }
|
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){
|
char* get_title_by_pid(uintptr pid, int8_t isPid){
|
||||||
MData win = set_handle_pid(pid, isHwnd);
|
MData win = set_handle_pid(pid, isPid);
|
||||||
return get_title_by_hand(win);
|
return get_title_by_hand(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* named(void *result) {
|
char* named(void *result) {
|
||||||
@ -543,13 +526,12 @@ char* named(void *result) {
|
|||||||
|
|
||||||
char* get_title_by_hand(MData m_data){
|
char* get_title_by_hand(MData m_data){
|
||||||
// Check if the window is valid
|
// Check if the window is valid
|
||||||
if (!IsValid()) {return "IsValid failed.";}
|
if (!is_valid()) { return "is_valid failed."; }
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
CFStringRef data = NULL;
|
CFStringRef data = NULL;
|
||||||
|
|
||||||
// Determine the current title of the window
|
// Determine the current title of the window
|
||||||
if (AXUIElementCopyAttributeValue(m_data.AxID,
|
if (AXUIElementCopyAttributeValue(m_data.AxID, kAXTitleAttribute, (CFTypeRef*) &data) ==
|
||||||
kAXTitleAttribute, (CFTypeRef*) &data) == kAXErrorSuccess && data != NULL) {
|
kAXErrorSuccess && data != NULL) {
|
||||||
char conv[512];
|
char conv[512];
|
||||||
// Convert result to a C-String
|
// Convert result to a C-String
|
||||||
CFStringGetCString(data, conv, 512, kCFStringEncodingUTF8);
|
CFStringGetCString(data, conv, 512, kCFStringEncodingUTF8);
|
||||||
@ -603,23 +585,22 @@ char* get_title_by_hand(MData m_data){
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t WGetPID(void) {
|
int32_t get_PID(void) {
|
||||||
// Check window validity
|
// Check window validity
|
||||||
if (!IsValid()) { return 0; }
|
if (!is_valid()) { return 0; }
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
pid_t pid = 0;
|
pid_t pid = 0;
|
||||||
// Attempt to retrieve the window pid
|
// Attempt to retrieve the window pid
|
||||||
if (AXUIElementGetPid(mData.AxID, &pid)== kAXErrorSuccess) {
|
if (AXUIElementGetPid(pub_mData.AxID, &pid)== kAXErrorSuccess) {
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#elif defined(USE_X11)
|
#elif defined(USE_X11)
|
||||||
// Ignore X errors
|
// Ignore X errors
|
||||||
XDismissErrors();
|
XDismissErrors();
|
||||||
|
|
||||||
// Get the window PID
|
// 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
|
// Check result and convert it
|
||||||
if (result == NULL) { return 0; }
|
if (result == NULL) { return 0; }
|
||||||
|
|
||||||
@ -628,8 +609,7 @@ int32_t WGetPID(void) {
|
|||||||
return pid;
|
return pid;
|
||||||
#elif defined(IS_WINDOWS)
|
#elif defined(IS_WINDOWS)
|
||||||
DWORD id = 0;
|
DWORD id = 0;
|
||||||
GetWindowThreadProcessId(mData.HWnd, &id);
|
GetWindowThreadProcessId(pub_mData.HWnd, &id);
|
||||||
return id;
|
return id;
|
||||||
#endif
|
#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