Compare commits

...

230 Commits

Author SHA1 Message Date
Evans
a8c387a070
Merge pull request #725 from go-vgo/bitmap-pr
Some checks failed
Go / test (macOS-latest) (push) Has been cancelled
Go / test (windows-latest) (push) Has been cancelled
Update: use hid event in macos
2025-05-17 13:04:47 -07:00
vcaesar
3eef3b5879 Add: add CGEventSourceRef source
Some checks failed
Go / test (macOS-latest) (push) Has been cancelled
Go / test (windows-latest) (push) Has been cancelled
2025-05-17 13:01:03 -07:00
vcaesar
b731094f61 Update: update if defined 2025-05-17 12:54:35 -07:00
vcaesar
8d4679db07 Merge remote-tracking branch 'origin/master' into bitmap-pr 2025-05-17 12:42:12 -07:00
vcaesar
02c668a946 Update: add CFRelease source 2025-05-17 12:37:38 -07:00
vcaesar
5c2864485d Update: use hid event in macos 2025-05-17 12:33:16 -07:00
Evans
f101b10497
Merge pull request #724 from go-vgo/bitmap-pr
Fixed: fixed default key toggle delay
2025-05-17 12:03:01 -07:00
vcaesar
73c07dc991 Fixed: fixed default key toggle delay 2025-05-17 12:01:12 -07:00
Evans
fc47bc8216
Merge pull request #723 from go-vgo/bitmap-pr
Update: update go mod and CI
2025-05-17 11:56:33 -07:00
vcaesar
912ddcbfe4 Update: update go mod and CI 2025-05-17 11:53:45 -07:00
Evans
57b5e5bca2
Merge pull request #720 from go-vgo/bitmap-pr
Some checks failed
Go / test (macOS-latest) (push) Has been cancelled
Go / test (windows-latest) (push) Has been cancelled
Update: update import
2025-04-19 12:56:42 -07:00
vcaesar
8031f7f526 Update: update import
Some checks failed
Go / test (macOS-latest) (push) Has been cancelled
Go / test (windows-latest) (push) Has been cancelled
2025-04-19 12:54:47 -07:00
Evans
36bc85ad19
Merge pull request #719 from go-vgo/bitmap-pr
Some checks are pending
Go / test (macOS-latest) (push) Waiting to run
Go / test (windows-latest) (push) Waiting to run
Fix: fixed mac os version min required #698
2025-04-19 10:06:37 -07:00
vcaesar
5fc2bd4c73 Fix: fixed mac os version min required #698
Some checks are pending
Go / test (macOS-latest) (push) Waiting to run
Go / test (windows-latest) (push) Waiting to run
2025-04-19 10:05:01 -07:00
Evans
47abfac5ee
Merge pull request #716 from go-vgo/bitmap-pr
Some checks failed
Go / test (macOS-latest) (push) Has been cancelled
Go / test (windows-latest) (push) Has been cancelled
Fixed: fixed windows Scale #713 and Update readme.md
2025-04-11 14:37:12 -07:00
vcaesar
df0731c4df Fixed: fixed windows Scale #713 and Update readme.md
Some checks failed
Go / test (macOS-latest) (push) Has been cancelled
Go / test (windows-latest) (push) Has been cancelled
2025-04-11 14:34:15 -07:00
Evans
03432155c1
Merge pull request #711 from go-vgo/bitmap-pr
Some checks failed
Go / test (macOS-latest) (push) Has been cancelled
Go / test (windows-latest) (push) Has been cancelled
Refactor: simplify mouse movement implementation for Windows
2025-03-08 15:03:56 -08:00
vcaesar
6a1f060a8c Refactor: simplify mouse movement implementation for Windows, use setCursorPos instead of mouse_event
Some checks failed
Go / test (macOS-latest) (push) Has been cancelled
Go / test (windows-latest) (push) Has been cancelled
2025-03-08 15:02:39 -08:00
Evans
e924f25fe1
Merge pull request #708 from go-vgo/bitmap-pr
Some checks failed
Go / test (macOS-latest) (push) Has been cancelled
Go / test (windows-latest) (push) Has been cancelled
Update: updated go mod
2025-02-17 15:56:32 -08:00
vcaesar
d300eedf54 Update: updated go mod
Some checks failed
Go / test (macOS-latest) (push) Has been cancelled
Go / test (windows-latest) (push) Has been cancelled
2025-02-17 15:54:57 -08:00
Evans
c07f3f0171
Merge pull request #701 from ronaldpetty/patch-1
Some checks failed
Go / test (macOS-latest) (push) Has been cancelled
Go / test (windows-latest) (push) Has been cancelled
Update README.md
2024-12-10 11:32:09 -08:00
Ronald Petty
0b18fa5058
Update README.md
Added missing import
2024-12-09 19:51:43 -08:00
Evans
471f7ba05f
Merge pull request #695 from go-vgo/bitmap-pr
Some checks failed
Go / test (macOS-latest) (push) Has been cancelled
Go / test (windows-latest) (push) Has been cancelled
Update: update go mod
2024-10-07 14:17:46 -07:00
vcaesar
a84a195c4c Update: update go mod
Some checks failed
Go / test (macOS-latest) (push) Has been cancelled
Go / test (windows-latest) (push) Has been cancelled
2024-10-07 14:15:17 -07:00
Evans
c8df366f89
Merge pull request #694 from go-vgo/bitmap-pr
Update: update readme.md
2024-10-07 14:10:09 -07:00
vcaesar
70f811ce53 Update: update readme.md 2024-10-07 14:09:01 -07:00
Evans
ecc260ea31
Merge pull request #693 from go-vgo/bitmap-pr
Update: update screen capture code and examples
2024-10-07 14:00:37 -07:00
vcaesar
78d01703b8 Update: update examples and test code, README.md 2024-10-07 13:56:46 -07:00
vcaesar
47cde13dab Update: update screen capture code and examples 2024-10-07 13:45:03 -07:00
aohanhongzhi
8db59aac2d
capture error (#663)
* capture error

* aohanhongzhi

* Update go.mod

---------

Co-authored-by: Evans <vzvway@gmail.com>
2024-10-07 13:29:39 -07:00
Evans
217d6cf1f1
Merge pull request #692 from go-vgo/bitmap-pr
Some checks are pending
Go / test (macOS-latest) (push) Waiting to run
Go / test (windows-latest) (push) Waiting to run
Fixed: default use high capture resolution in macos15
2024-10-06 18:12:41 -07:00
vcaesar
75fd24ea0a Fixed: Fixed x11 build
Some checks are pending
Go / test (macOS-latest) (push) Waiting to run
Go / test (windows-latest) (push) Waiting to run
2024-10-06 18:11:23 -07:00
vcaesar
bed6776ca2 Fixed: default use high capture resolution in macos15 2024-10-06 18:04:17 -07:00
Evans
1923d7bb48
Merge pull request #691 from go-vgo/bitmap-pr
Update: move scale to screen and rename pub mdata
2024-10-06 17:54:40 -07:00
vcaesar
ead43d062e Fixed: fix x11 build 2024-10-06 17:51:51 -07:00
vcaesar
3258566802 Update: move scale to screen and rename pub mdata 2024-10-06 17:40:34 -07:00
Evans
0de26ecee4
Merge pull request #685 from go-vgo/bitmap-pr
Add: export Handle data and add more window handle function #683
2024-09-17 13:39:26 -07:00
vcaesar
c48e3d072c Update: Fixed godoc 2024-09-17 13:38:38 -07:00
vcaesar
b1ad7db6be Add: export Handle data and add more window handle function #683 2024-09-17 13:32:46 -07:00
Evans
0110b85d40
Merge pull request #684 from go-vgo/bitmap-pr
Add: export xClose main display function
2024-09-17 13:14:54 -07:00
vcaesar
3e5b10f720 Add: export XClose main display function 2024-09-17 13:11:02 -07:00
vcaesar
cb51e2aa10 Update: cleary some code style 2024-09-17 12:59:15 -07:00
Evans
85f2702683
Merge pull request #682 from go-vgo/bitmap-pr
Update: update screengrab to fixed macos 15
2024-09-15 12:25:18 -07:00
vcaesar
5b9871b063 Merge remote-tracking branch 'origin/master' into bitmap-pr 2024-09-05 13:26:02 -07:00
vcaesar
b201ab9f80 Update: update screengrad with fixed macos 15 2024-09-05 13:23:14 -07:00
Evans
d3e364fa26
Merge pull request #681 from go-vgo/bitmap-pr
Update: update go mod
2024-09-05 13:11:35 -07:00
vcaesar
1f437d12e4 Update: update go mod 2024-09-05 13:09:51 -07:00
Evans
c5110d0ac8
Merge pull request #675 from go-vgo/bitmap-pr
Update: update CI to newest
2024-08-16 11:36:44 -07:00
vcaesar
f98b4c52bd Update: update CI to newest 2024-08-16 11:35:18 -07:00
Evans
f1db2ede4a
Merge pull request #671 from go-vgo/bitmap-pr
Update: add svae capture and update go mod
2024-08-05 13:13:39 -07:00
vcaesar
d90493e63e Update: add svae capture and update go mod 2024-08-05 13:11:56 -07:00
Evans
63eb594ea5
Merge pull request #661 from go-vgo/bitmap-pr
Update: update go mod to newest
2024-06-12 13:06:53 -07:00
vcaesar
8a990ac042 Update: update go mod to newest 2024-06-12 13:02:30 -07:00
Evans
bf1758b424
Merge pull request #660 from go-vgo/bitmap-pr
Update: update CI and dockerfile
2024-06-05 12:40:24 -07:00
vcaesar
9424b71a73 Update: update CI and dockerfile 2024-06-05 12:38:39 -07:00
Evans
6c137427db
Merge pull request #649 from nzlov/patch-1
fix: DragSmooth Repeat Call MoveScale
2024-04-15 10:14:33 -07:00
Evans
ffbf4f875b
Merge pull request #651 from rustfix/master
chore: fix function names in comment
2024-04-15 10:11:35 -07:00
rustfix
05c54c6f25 chore: fix function names in comment
Signed-off-by: rustfix <771054535@qq.com>
2024-04-15 11:37:14 +08:00
nzlov
3171c5bdff
fix: DragSmooth Repeat Call MoveScale
`DragSmooth` calls `MoveScale` followed by `MoveSmooth`, and `MoveSmooth` calls `MoveScale` within `MoveSmooth`, resulting in duplicate calls to `MoveScale`.
2024-04-07 14:08:26 +08:00
Evans
b718cf4a8c
Merge pull request #643 from go-vgo/bitmap-pr
Update: bump CI to newest
2024-02-23 08:52:47 -08:00
vcaesar
bfc28d12fa Merge remote-tracking branch 'origin/master' into bitmap-pr 2024-02-23 08:49:07 -08:00
vcaesar
e9421b58b6 Update: bump CI to newest 2024-02-23 08:47:11 -08:00
Evans
4d780b9908
Merge pull request #630 from go-vgo/bitmap-pr
Add: add next Linux and Windows files
2023-12-20 09:55:27 -08:00
vcaesar
39818d41fa Add: add next Linux and Windows files 2023-12-20 09:52:51 -08:00
Evans
eacf74f488
Merge pull request #629 from sleep2144985/patch-1
fix: x11 capslock reference the wrong constant
2023-12-20 09:21:17 -08:00
sleep2144985
61b77ce3e1
fix: x11 capslock reference the wrong constant 2023-12-20 17:35:11 +08:00
Evans
01e4fffcb8
Merge pull request #623 from go-vgo/bitmap-pr
Update: update readme.md
2023-11-13 10:27:41 -08:00
vcaesar
e2f5f54804 Update: update readme.md 2023-11-13 10:22:10 -08:00
Evans
f22f063926
Merge pull request #622 from go-vgo/bitmap-pr
Update: update readme.md
2023-11-13 09:25:31 -08:00
vcaesar
722feb7ba3 Update: update readme.md 2023-11-13 09:23:29 -08:00
Evans
dbf0d84f12
Merge pull request #617 from go-vgo/bitmap-pr
Update: gofmt the code
2023-10-30 08:26:49 -07:00
vcaesar
b8a6b1778e Update: gofmt the code 2023-10-30 08:24:33 -07:00
Evans
a780825c09
Merge pull request #612 from yms2772/master
Fix: panic occurs when current window is minimized on macOS
2023-09-15 07:21:43 -07:00
Mokky
de675b4dd2
Update window.h
Fix: error when current window is minimized
2023-09-07 20:53:58 +09:00
Evans
ef191f2dfd
Merge pull request #610 from go-vgo/bitmap-pr
Update: update gomod and fixed warning
2023-09-03 12:16:46 -07:00
vcaesar
44b2715de0 Merge remote-tracking branch 'origin/master' into bitmap-pr 2023-09-03 12:13:17 -07:00
vcaesar
90f41269da Update: update gomod and fixed warning 2023-09-03 12:12:56 -07:00
Evans
8a5ca54915
Merge pull request #607 from testwill/typo
fix: continuous typo
2023-08-27 08:59:04 -07:00
guangwu
5b0ac98ef3
fix: continuous typo 2023-08-26 11:45:07 +08:00
Evans
c2b5c864d2
Merge pull request #605 from go-vgo/bitmap-pr
Update: bump CI
2023-08-18 10:35:19 -07:00
vcaesar
0c4055bfee Update: bump CI 2023-08-18 10:28:15 -07:00
Evans
af32110521
Merge pull request #593 from go-vgo/bitmap-pr
Update: update and remove some old code
2023-07-06 10:20:04 -07:00
vcaesar
5c3cbd6e17 Update: update and remove some old code 2023-07-06 10:14:42 -07:00
Evans
3182fb9d73
Merge pull request #592 from go-vgo/bitmap-pr
Fix: fixed typo
2023-07-05 11:05:21 -07:00
vcaesar
6fa2f418fa Fix: fixed typo 2023-07-05 11:02:55 -07:00
Jean Raby
8e7a413ec6
Fix x11 display leak (#590)
* Call XCloseDisplay in all return paths

Add test to confirm XOpenDisplay leak is plugged

* whitespace
2023-06-11 10:17:26 -07:00
Evans
8ce3a5dff0
Merge pull request #577 from go-vgo/bitmap-pr
Update: Update README.md and documents, Update dockerfile and CI
2023-04-09 12:44:01 -07:00
vcaesar
8ea126d35b Update: Update dockerfile and CI 2023-04-09 12:41:44 -07:00
vcaesar
c62f7fd81e Update README.md and documents 2023-04-09 12:40:01 -07:00
Evans
92fd032685
Merge pull request #572 from go-vgo/bitmap-pr
Update: fixed windows scale move and Location(), update godoc
2023-03-13 11:11:40 -07:00
vcaesar
ffcf6b26cd Update: fixed windows scale move and Location(), update godoc 2023-03-13 11:07:26 -07:00
Evans
451bb91209
Merge pull request #571 from go-vgo/bitmap-pr
Update: move type conversion to key.md and update godoc
2023-03-11 08:53:48 -08:00
vcaesar
cbca6d08c7 Update: move type conversion to key.md and update godoc 2023-03-11 08:51:29 -08:00
Evans
d249cdcd9e
Merge pull request #570 from wilon/master
Update README.md, add type conversion list.
2023-03-10 23:06:19 -08:00
Weilong Wang
4140463ed1
Update README.md, add type conversion list. 2023-03-10 15:12:21 +08:00
Evans
186bceb9d0
Merge pull request #568 from go-vgo/bitmap-pr
Fixed: fixed code and CI
2023-02-27 09:53:51 -08:00
vcaesar
01212c5684 Fixed: fixed code and CI 2023-02-27 09:49:26 -08:00
Evans
07dd53a897
Merge pull request #567 from go-vgo/bitmap-pr
Add: add the GetDesktopWindow and scale support
2023-02-27 09:37:07 -08:00
vcaesar
9afa311121 Add: add the GetDesktopWindow and scale support 2023-02-27 09:35:35 -08:00
Evans
94be6c56c1
Merge pull request #566 from go-vgo/bitmap-pr
Update: update go mod
2023-02-23 09:55:56 -08:00
vcaesar
e0583e83ec Update: update gops mod 2023-02-23 09:54:44 -08:00
vcaesar
6a2ffab625 Update: update go mod 2023-02-22 09:59:50 -08:00
Evans
679aef0f70
Merge pull request #564 from go-vgo/bitmap-pr
Update: bump go CI to 1.20.x
2023-02-18 09:30:09 -08:00
vcaesar
cc6f1934f9 Update: bump go CI to 1.20.x 2023-02-18 09:28:58 -08:00
Evans
4bdacf4187
Merge pull request #563 from go-vgo/dependabot/go_modules/golang.org/x/image-0.5.0
Bump golang.org/x/image from 0.1.0 to 0.5.0
2023-02-17 07:29:47 -08:00
dependabot[bot]
c8d35acd24
Bump golang.org/x/image from 0.1.0 to 0.5.0
Bumps [golang.org/x/image](https://github.com/golang/image) from 0.1.0 to 0.5.0.
- [Release notes](https://github.com/golang/image/releases)
- [Commits](https://github.com/golang/image/compare/v0.1.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/image
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-17 14:43:17 +00:00
Evans
e4848b4608
Merge pull request #560 from go-vgo/bitmap-pr
Update: update and add more examples
2023-02-01 10:28:44 -08:00
vcaesar
f47571eaae Update: update examples 2023-02-01 10:28:17 -08:00
vcaesar
dd149367b3 Update: update and add more examples 2023-02-01 10:25:11 -08:00
Evans
da736a93ee
Merge pull request #559 from go-vgo/bitmap-pr
Add: add more capture screens hot support and fixed bug
2023-01-23 18:16:35 -08:00
vcaesar
73a40e7861 Add: add more capture screens hot support and fixed bug 2023-01-23 18:14:28 -08:00
Evans
5e5c4ddbfa
Merge pull request #558 from go-vgo/bitmap-pr
Add: add mouse of scale support and optimize the multi screen
2023-01-22 18:39:46 -08:00
vcaesar
23d3df9027 Update: update examples 2023-01-22 18:38:28 -08:00
vcaesar
bb76af18f0 Add: add mouse of scale support and optimize the multi screen 2023-01-22 18:34:03 -08:00
Evans
b13320884a
Merge pull request #557 from go-vgo/bitmap-pr
Update: used NotPid option args and move Deprecated func to v1
2023-01-20 13:56:38 -08:00
vcaesar
df1617d894 Update: used NotPid option args and move Deprecated func to v1 2023-01-20 13:53:06 -08:00
Evans
b20007917d
Merge pull request #556 from go-vgo/bitmap-pr
Add: add capture multi screen default support in windows
2023-01-19 10:10:45 -08:00
vcaesar
f830c8ed13 Add: add capture multi screen default support 2023-01-19 10:06:56 -08:00
vcaesar
736fa1cc26 Add: add windows capture multi screen support 2023-01-18 11:45:18 -08:00
Evans
9f8d308eaa
Merge pull request #555 from go-vgo/bitmap-pr
Fixed: fixed mac key release and remove the toggle defaut sleep
2023-01-15 09:16:44 -08:00
vcaesar
95be5f752f Fixed: fixed mac key release and remove the toggle defaut sleep 2023-01-15 09:12:40 -08:00
Evans
4bc64ebf67
Merge pull request #554 from go-vgo/bitmap-pr
Fix: fixed mac multi screen capture
2023-01-11 16:10:44 -08:00
vcaesar
bdae1a7759 Fix: fixed mac multi screen capture 2023-01-11 16:08:24 -08:00
Evans
c9e1c3db67
Merge pull request #551 from go-vgo/bitmap-pr
Add: add cmd to the ctrl supported
2022-12-15 09:02:13 -08:00
vcaesar
e8b3975205 Add: add cmd to the ctrl supported 2022-12-15 08:58:17 -08:00
vcaesar
f4f4a3d319 Update: Update CI 2022-12-10 15:50:41 -08:00
Evans
3052272818
Merge pull request #550 from go-vgo/bitmap-pr
Update: Optimize window hand code
2022-11-28 14:26:43 -08:00
vcaesar
6313e52156 Update: Optimize window hand code 2022-11-28 14:21:03 -08:00
vcaesar
f911550742 Update: Update README.md and godoc 2022-11-28 13:40:01 -08:00
Evans
2f936e1f49
Merge pull request #543 from go-vgo/bitmap-pr
Add: add win32 send key event by pid support
2022-11-27 18:43:34 -08:00
vcaesar
7aa5beb8f7 Fixed: fixed typo 2022-11-27 18:40:51 -08:00
vcaesar
4eea01b88d Fixed: fixed windows int type 2022-11-27 18:38:05 -08:00
vcaesar
7103f6b891 Update README.md 2022-11-27 18:33:32 -08:00
vcaesar
bb90d71b5f Add: add windows key tap and type by pid support 2022-11-27 18:30:05 -08:00
vcaesar
0ef48f1c4d Merge remote-tracking branch 'origin/master' into bitmap-pr 2022-11-27 18:12:04 -08:00
Evans
be6984fd34
Merge pull request #549 from go-vgo/test-pr
Update & Add: unified use the int to replace int32...
2022-11-27 18:11:13 -08:00
vcaesar
2f2ed595f6 Fixed: fixed test 2022-11-27 18:08:51 -08:00
vcaesar
5079db2df7 Fixed: fixed x11 type convert 2022-11-27 18:06:14 -08:00
vcaesar
469cd4da5e Update & Add: unified use the int to replace int32;
unified name and add more func;
Update gomod and CI
2022-11-27 17:55:45 -08:00
vcaesar
a8faa0e906 Update README.md 2022-11-21 10:29:09 -08:00
vcaesar
0293ab5d0c Add: add win32 send key event by pid support 2022-11-01 10:39:48 -07:00
Evans
fc5dac6f8a
Merge pull request #539 from go-vgo/bitmap-pr
Unified name and Update godoc, fixed typo
2022-11-01 10:32:12 -07:00
vcaesar
4bf054f47a Unifed and rename some function for Pad 2022-11-01 10:28:00 -07:00
vcaesar
c3cda41c2d Update: update godoc and fixed typo 2022-09-14 15:23:09 -07:00
vcaesar
e9b5a9251e Update: Unified pid and xid name, Update godoc, fixed typo 2022-09-13 15:49:21 -07:00
vcaesar
47ca6812fe Update README.md 2022-09-12 15:20:48 -07:00
Evans
4ad733fe83
Merge pull request #532 from go-vgo/bitmap-pr
Update: Bump CI to 1.19
2022-09-06 14:53:18 -07:00
vcaesar
f428ffb1fb Update: Bump CI to 1.19 2022-09-06 14:51:08 -07:00
Evans
a1cb2ebef2
Merge pull request #520 from wilon/master
convert img lose 1 pixel bug
2022-07-31 14:39:54 -07:00
Weilong Wang
31c248aedd
convert img lose 1 pixel bug 2022-07-31 16:47:14 +08:00
Evans
db2eda3e1f
Merge pull request #513 from go-vgo/bitmap-pr
add get the HWND by PID support
2022-06-26 10:25:08 -07:00
vcaesar
ee25e577e5 add get the HWND by PID support 2022-06-26 10:23:17 -07:00
Evans
62c61cf52a
Merge pull request #510 from go-vgo/bitmap-pr
Fixed Windows bitmap copy #501
2022-06-23 21:13:34 -07:00
vcaesar
1934220f50 Fixed Windows bitmap copy #501 2022-06-23 21:11:41 -07:00
Evans
673c9a68a3
Merge pull request #509 from go-vgo/bitmap-pr
Updated dockerfile and CI
2022-06-13 13:26:52 -07:00
vcaesar
e08e05307e Updated dockerfile and CI 2022-06-13 11:38:35 -07:00
Evans
e53c75ff95
Merge pull request #505 from go-vgo/bitmap-pr
Update gomod and CI fixed dependabot alert
2022-05-28 23:34:26 -07:00
vcaesar
c5cdd0a33f Update gomod and CI fixed dependabot alert 2022-05-28 23:32:26 -07:00
Evans
8ba7338861
Merge pull request #498 from go-vgo/bitmap-pr
Add more key and mouse examples and Update CI
2022-04-14 09:00:22 -07:00
vcaesar
7df3bc3800 Add more key and mouse examples code 2022-04-14 08:57:09 -07:00
vcaesar
8744c88f5f Update dockerfile and CI 2022-04-13 13:03:56 -07:00
Evans
e533734f0b
Merge pull request #495 from go-vgo/bitmap-pr
Optimize keyboard code and Update examples
2022-04-09 10:34:10 -07:00
vcaesar
a2e387b448 Optimize keyboard code and Update examples 2022-04-09 10:33:02 -07:00
Evans
bfa6b232be
Merge pull request #494 from go-vgo/bitmap-pr
Fixed type x11 key bug #493
2022-04-08 14:11:19 -07:00
vcaesar
51ca08e484 Fixed type x11 key bug #493 2022-04-08 14:10:02 -07:00
Evans
debc2719ee
Merge pull request #490 from go-vgo/bitmap-pr
Removed Windows VIRTUALScreen size and Update examples
2022-03-21 10:07:23 -07:00
vcaesar
985c590284 Removed Windows VIRTUALScreen size and Update examples 2022-03-21 10:05:02 -07:00
Evans
94c4b98edd
Merge pull request #489 from go-vgo/bitmap-pr
Update CI to go1.18
2022-03-16 02:13:52 -07:00
vcaesar
895aed8f22 Update CI to go 1.18 2022-03-16 02:12:03 -07:00
vcaesar
6bf430b1cd Update dockerfile and appveyor 2022-03-10 08:08:22 -08:00
Evans
1d2ec44308
Merge pull request #484 from go-vgo/bitmap-pr
Update widows ReleaseDC code
2022-03-03 16:50:58 -08:00
vcaesar
60bf136aa1 Update widows ReleaseDC code 2022-02-27 16:33:25 -08:00
Evans
e7c518eb2a
Merge pull request #480 from go-vgo/bitmap-pr
Optimize x11 alert show
2022-02-22 14:55:37 -08:00
vcaesar
e755317599 Fixed import format 2022-02-22 14:54:44 -08:00
vcaesar
efc7c90b9f Optimize x11 alert show 2022-02-22 14:33:29 -08:00
Evans
c493c4981d
Merge pull request #478 from go-vgo/bitmap-pr
Fixed x11 warning
2022-02-19 11:50:14 -08:00
vcaesar
f110d5bf9e Fixed x11 warning 2022-02-19 11:48:54 -08:00
Evans
ade0381d15
Merge pull request #476 from go-vgo/bitmap-pr
Optimize key code and add more examples code
2022-02-18 10:24:23 -08:00
vcaesar
0dcc87c355 Optimize key code and add more examples code 2022-02-18 10:21:31 -08:00
Evans
3d7cce3a31
Merge pull request #475 from go-vgo/bitmap-pr
Add send key event by pid support [mac]
2022-02-17 12:36:44 -08:00
vcaesar
60ddc20e02 Update Unicode Type args 2022-02-17 12:29:18 -08:00
vcaesar
16e0808dbd Fixed CI build 2022-02-17 12:21:27 -08:00
vcaesar
3278758575 Add send key event by pid support [mac] 2022-02-17 12:10:41 -08:00
vcaesar
389f7c6802 rename win32.h to pubs.h 2022-02-17 11:44:06 -08:00
Evans
ffa27a50cc
Merge pull request #474 from go-vgo/bitmap-pr
Add capital letter key define and events listen test html
2022-02-17 10:20:28 -08:00
vcaesar
e1c5590f30 Add capital letter key define 2022-02-17 10:15:49 -08:00
vcaesar
93a9f8194f Add events listen test html 2022-02-17 10:13:11 -08:00
Evans
a917683d97
Merge pull request #473 from go-vgo/bitmap-pr
Add uppercase key support with default and Update godoc
2022-02-17 09:50:58 -08:00
vcaesar
34d0fbf4bc Add uppercase key support with default and Update godoc 2022-02-17 09:47:48 -08:00
Evans
3e97de3745
Merge pull request #471 from go-vgo/bitmap-pr
Optimize key toggle code and Update README.md
2022-02-15 15:09:51 -08:00
vcaesar
2f79ebe879 Optimize key toggle code 2022-02-15 15:03:47 -08:00
vcaesar
ab66b269b8 Update README.md 2022-02-15 14:26:44 -08:00
vcaesar
a00655dbe4 Update dockerfile & appveyor 2022-02-14 03:36:06 -08:00
Evans
45b85e1ec3
Merge pull request #466 from go-vgo/bitmap-pr
Update README.md and bytewidth C type
2022-02-09 10:23:01 -08:00
vcaesar
c395a0dcd6 Update README.md and bytewidth C type 2022-02-09 10:20:57 -08:00
Evans
5d651eb627
Merge pull request #465 from go-vgo/bitmap-pr
Update key examples
2022-02-08 03:48:24 -08:00
vcaesar
c0ef98e712 Update key examples 2022-02-08 03:47:06 -08:00
Evans
d14fae83be
Merge pull request #464 from go-vgo/bitmap-pr
Add image and byte to CBitmap support
2022-02-08 03:11:19 -08:00
vcaesar
8aa3348a2a Add image and byte to CBitmap support 2022-02-08 03:09:26 -08:00
Evans
ebdc6878e5
Merge pull request #463 from go-vgo/bitmap-pr
Update README.md and remove unused code
2022-02-06 00:53:45 -08:00
vcaesar
a9d995fdf6 Update README.md 2022-02-06 00:51:37 -08:00
vcaesar
be9b02c588 Update README.md and remove unused code 2022-02-06 00:46:41 -08:00
Laurent Demailly
264f658a46
Fix typo in doc for GetMousePos (#462) 2022-02-06 00:42:18 -08:00
Evans
6c1e845183
Merge pull request #460 from go-vgo/bitmap-pr
Merged git log and fixed CI
2022-02-04 00:29:46 -08:00
vcaesar
84d85b1995 Merge remote-tracking branch 'origin/master' into bitmap-pr 2022-02-04 00:27:31 -08:00
vcaesar
4a043157ad Update define Fixed windows CI 2022-02-04 00:27:17 -08:00
Evans
1fac32d382
Merge pull request #459 from go-vgo/bitmap-pr
Add GetMainId and IsMain function support
2022-02-04 00:22:36 -08:00
vcaesar
74c3f6e08e Add GetMainId and IsMain function support 2022-02-04 00:20:23 -08:00
Evans
76b123142f
Merge pull request #458 from go-vgo/bitmap-pr
Add clear scroll API and Update examples
2022-02-04 00:04:57 -08:00
vcaesar
b543a49322 Add clear scroll API and Update examples 2022-02-04 00:02:34 -08:00
Evans
fafd2bfcd4
Merge pull request #457 from go-vgo/bitmap-pr
Refactor some mouse and window C code to Go
2022-02-03 03:33:33 -08:00
vcaesar
b439c59d85 Upload miss code fixed CI 2022-02-03 03:21:18 -08:00
vcaesar
5d460e5100 Fixed CI build 2022-02-03 03:14:44 -08:00
vcaesar
d82ca8cee4 Refactor some mouse and window C code to Go 2022-02-03 03:03:32 -08:00
Evans
3655e795d7
Merge pull request #456 from go-vgo/bitmap-pr
Removed msc, macro and  other C code
2022-02-03 01:43:25 -08:00
vcaesar
f0b614d78e Removed msc, macro and other C code 2022-02-03 01:41:46 -08:00
Evans
c61fe44788
Merge pull request #455 from go-vgo/bitmap-pr
Add more keyUp args and SetDelay() support, add more test code
2022-02-02 21:22:50 -08:00
vcaesar
2d52e2c008 Add more keyUp args and SetDelay() support, add more test code 2022-02-02 21:20:02 -08:00
Evans
75cfe774b3
Merge pull request #454 from go-vgo/bitmap-pr
Refactor some keyboard C code to go
2022-02-01 00:09:18 -08:00
vcaesar
00fa7ff5fc Fixed Linux CI build 2022-02-01 00:05:51 -08:00
vcaesar
4599d66f5b Fixed CI build 2022-01-31 23:41:31 -08:00
vcaesar
2502329583 Remove SetKeydelay code 2022-01-31 23:18:31 -08:00
vcaesar
82cde2281e Update issue and PR template 2022-01-31 23:14:53 -08:00
vcaesar
99963bc6fc Refactor some keyboard C code to go 2022-01-31 23:12:24 -08:00
Evans
c5446b655d
Merge pull request #453 from go-vgo/bitmap-pr
Update godoc
2022-01-31 17:27:32 -08:00
vcaesar
ed45411f5c Update godoc 2022-01-31 17:25:23 -08:00
Evans
b6ef01a929
Merge pull request #452 from go-vgo/bitmap-pr
Refactor error return to clear type, fixed some sleep
2022-01-28 12:36:41 -08:00
vcaesar
149d0f8307 Refactor error return to clear type, fixed some sleep 2022-01-28 12:35:05 -08:00
Evans
e81c9ec843
Merge pull request #451 from go-vgo/bitmap-pr
Add more test code and Update README.md
2022-01-27 10:12:20 -08:00
vcaesar
cd7ed72bf2 Add more test code and Update README.md 2022-01-27 10:08:44 -08:00
81 changed files with 2772 additions and 3044 deletions

View File

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

View File

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

View File

@ -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**.
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.
**You MUST delete the content above including this line before posting, otherwise your issue will be invalid.**
- Robotgo version (or commit ref):
- Go version:
- Gcc version:

View File

@ -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)
4. Describe what your pull request does and which issue you're targeting (if any and **Please use English**)
5. ... if it is not related to any particular issues, explain why we should not reject your pull request.
6. The Commits must use English, must be test and No useless submissions.
6. The Commits must **use English**, must be test and No useless submissions.
**You MUST delete the content above including this line before posting, otherwise your pull request will be invalid.**
**Please provide Issues links to:**
- Issues: #1

View File

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

View File

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

View File

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

183
README.md
View File

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

View File

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

View File

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

View File

@ -5,89 +5,32 @@
#include "types.h"
#include "rgb.h"
#include <assert.h>
// #include <stdint.h>
#if defined(_MSC_VER)
#include "ms_stdint.h"
#else
#include <stdint.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
struct _MMBitmap {
uint8_t *imageBuffer; /* Pixels stored in Quad I format; i.e., origin is in
* top left. Length should be height * bytewidth. */
size_t width; /* Never 0, unless image is NULL. */
size_t height; /* Never 0, unless image is NULL. */
size_t bytewidth; /* The aligned width (width + padding). */
uint8_t *imageBuffer; /* Pixels stored in Quad I format; */
int32_t width; /* Never 0, unless image is NULL. */
int32_t height; /* Never 0, unless image is NULL. */
int32_t bytewidth; /* The aligned width (width + padding). */
uint8_t bitsPerPixel; /* Should be either 24 or 32. */
uint8_t bytesPerPixel; /* For convenience; should be bitsPerPixel / 8. */
};
typedef struct _MMBitmap MMBitmap;
typedef MMBitmap *MMBitmapRef;
// MMBitmapRef bitmap;
/* Creates new MMBitmap with the given values.
* 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);
#define MMBitmapPointInBounds(image, p) ((p).x < (image)->width && (p).y < (image)->height)
/* Releases memory occupied by MMBitmap. */
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(). */
/* Get pointer to pixel of MMBitmapRef. No bounds checking is performed */
#define MMRGBColorRefAtPoint(image, x, y) \
(MMRGBColor *)(assert(MMBitmapPointInBounds(image, MMPointMake(x, y))), \
((image)->imageBuffer) + (((image)->bytewidth * (y)) \
+ ((x) * (image)->bytesPerPixel)))
(MMRGBColor *)(assert(MMBitmapPointInBounds(image, MMPointInt32Make(x, y))), \
((image)->imageBuffer) + (((image)->bytewidth * (y)) + ((x) * (image)->bytesPerPixel)))
/* Dereference pixel of MMBitmapRef. Again, no bounds checking is performed. */
#define MMRGBColorAtPoint(image, x, y) *MMRGBColorRefAtPoint(image, x, y)
/* Hex/integer value of color at point. */
#define MMRGBHexAtPoint(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
#define MMRGBHexAtPoint(image, x, y) hexFromMMRGB(MMRGBColorAtPoint(image, x, y))
#endif /* MMBITMAP_H */

2
base/base.go Normal file
View File

@ -0,0 +1,2 @@
// https://github.com/golang/go/issues/26366
package base

View File

@ -2,8 +2,8 @@
#include <assert.h>
#include <string.h>
MMBitmapRef createMMBitmap_c(uint8_t *buffer, size_t width, size_t height,
size_t bytewidth, uint8_t bitsPerPixel, uint8_t bytesPerPixel
MMBitmapRef createMMBitmap_c(uint8_t *buffer, int32_t width, int32_t height,
int32_t bytewidth, uint8_t bitsPerPixel, uint8_t bytesPerPixel
) {
MMBitmapRef bitmap = malloc(sizeof(MMBitmap));
if (bitmap == NULL) { return NULL; }

View File

@ -4,11 +4,7 @@
#include <stdint.h>
#define DEADBEEF_MAX UINT32_MAX
/* 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." */
/* Dead Beef Random Number Generator From: http://inglorion.net/software/deadbeef_rand */
/* Generates a random number between 0 and DEADBEEF_MAX. */
uint32_t deadbeef_rand(void);
@ -22,14 +18,11 @@ uint32_t deadbeef_generate_seed(void);
/* Seeds with the above function. */
#define deadbeef_srand_time() deadbeef_srand(deadbeef_generate_seed())
/* Returns random double in the range [a, b).
* Taken directly from the rand() man page. */
/* Returns random double in the range [a, b).*/
#define DEADBEEF_UNIFORM(a, b) \
((a) + (deadbeef_rand() / (((double)DEADBEEF_MAX / (b - a) + 1))))
/* 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)
/* Returns random integer in the range [a, b).*/
#define DEADBEEF_RANDRANGE(a, b) (uint32_t)DEADBEEF_UNIFORM(a, b)
#endif /* DEADBEEF_RAND_H */

View File

@ -15,8 +15,7 @@ void deadbeef_srand(uint32_t x) {
deadbeef_beef = 0xdeadbeef;
}
/* Taken directly from the documentation:
* http://inglorion.net/software/cstuff/deadbeef_rand/ */
/* Taken directly from the documentation: http://inglorion.net/software/cstuff/deadbeef_rand/ */
uint32_t deadbeef_generate_seed(void) {
uint32_t t = (uint32_t)time(NULL);
uint32_t c = (uint32_t)clock();

View File

@ -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 */

View File

@ -1,7 +1,6 @@
#pragma once
/* A complicated, portable model for declaring inline functions in
* header files. */
/* A complicated, portable model for declaring inline functions in header files. */
#if !defined(H_INLINE)
#if defined(__GNUC__)
#define H_INLINE static __inline__ __attribute__((always_inline))

View File

@ -5,6 +5,7 @@
#include "os.h"
#include "inline_keywords.h"
// todo: removed
#if !defined(IS_WINDOWS)
/* Make sure nanosleep gets defined even when using C89. */
#if !defined(__USE_POSIX199309) || !__USE_POSIX199309
@ -14,21 +15,12 @@
#include <time.h> /* For nanosleep() */
#endif
/*
* A more widely supported alternative to usleep(), based on Sleep() in Windows
* and nanosleep() everywhere else.
*
* Pauses execution for the given amount of milliseconds.
*/
/* A more widely supported alternative to usleep(), based on Sleep() in Windows and nanosleep() */
H_INLINE void microsleep(double milliseconds) {
#if defined(IS_WINDOWS)
Sleep((DWORD)milliseconds); /* (Unfortunately truncated to a 32-bit integer.) */
#else
/* Technically, nanosleep() is not an ANSI function, but it is the most
* 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. */
/* Technically, nanosleep() is not an ANSI function */
struct timespec sleepytime;
sleepytime.tv_sec = milliseconds / 1000;
sleepytime.tv_nsec = (milliseconds - (sleepytime.tv_sec * 1000)) * 1000000;

View File

@ -1,25 +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 */

View File

@ -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 */

View File

@ -2,19 +2,12 @@
#ifndef 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__)
#define IS_MACOSX
#endif /* IS_MACOSX */
#if !defined(IS_WINDOWS) && (defined(WIN32) || defined(_WIN32) || \
defined(__WIN32__) || defined(__WINDOWS__) || defined(__CYGWIN__))
defined(__WIN32__) || defined(__WINDOWS__) || defined(__CYGWIN__))
#define IS_WINDOWS
#endif /* IS_WINDOWS */
@ -30,8 +23,7 @@
#error "Sorry, this platform isn't supported yet!"
#endif
/* Interval to align by for large buffers (e.g. bitmaps). */
/* Must be a power of 2. */
/* Interval to align by for large buffers (e.g. bitmaps). Must be a power of 2. */
#ifndef BYTE_ALIGN
#define BYTE_ALIGN 4 /* Bytes to align pixel buffers to. */
/* #include <stddef.h> */

View File

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

View File

@ -5,20 +5,7 @@
#include <stdlib.h> /* For abs() */
#include <math.h>
#include "inline_keywords.h" /* For H_INLINE */
// #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. */
#include <stdint.h>
/* #define MMRGB_IS_BGR (offsetof(MMRGBColor, red) > offsetof(MMRGBColor, blue)) */
#define MMRGB_IS_BGR 1
@ -28,20 +15,15 @@ struct _MMRGBColor {
uint8_t green;
uint8_t red;
};
typedef struct _MMRGBColor MMRGBColor;
/* MMRGBHex is a hexadecimal color value, akin to HTML's, in the form 0xRRGGBB
* where RR is the red value expressed as hexadecimal, GG is the green value,
* and BB is the blue value. */
/* MMRGBHex is a hexadecimal color value*/
typedef uint32_t MMRGBHex;
#define MMRGBHEX_MIN 0x000000
#define MMRGBHEX_MAX 0xFFFFFF
/* Converts rgb color to hexadecimal value.
* |red|, |green|, and |blue| should each be of the type |uint8_t|, where the
* range is 0 - 255. */
/* Converts rgb color to hexadecimal value. */
#define RGB_TO_HEX(red, green, blue) (((red) << 16) | ((green) << 8) | (blue))
/* Convenience wrapper for MMRGBColors. */
@ -67,9 +49,7 @@ H_INLINE MMRGBColor MMRGBFromHex(MMRGBHex hex) {
(c1).blue == (c2).blue && \
(c1).green == (c2).green)
/* 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
* color and 1 denotes any color. */
/* Returns whether two colors are similar within the given range, |tolerance|.*/
H_INLINE int MMRGBColorSimilarToColor(MMRGBColor c1, MMRGBColor c2, float tolerance) {
/* Speedy case */
if (tolerance <= 0.0f) {
@ -78,8 +58,7 @@ H_INLINE int MMRGBColorSimilarToColor(MMRGBColor c1, MMRGBColor c2, float tolera
uint8_t d1 = c1.red - c2.red;
uint8_t d2 = c1.green - c2.green;
uint8_t d3 = c1.blue - c2.blue;
return sqrt((double)(d1 * d1) +
(d2 * d2) +
return sqrt((double)(d1 * d1) + (d2 * d2) +
(d3 * d3)) <= (tolerance * 442.0f);
}
}
@ -89,14 +68,10 @@ H_INLINE int MMRGBHexSimilarToColor(MMRGBHex h1, MMRGBHex h2, float tolerance) {
if (tolerance <= 0.0f) {
return h1 == h2;
} 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 d2 = GREEN_FROM_HEX(h1) - GREEN_FROM_HEX(h2);
int d3 = BLUE_FROM_HEX(h1) - BLUE_FROM_HEX(h2);
return sqrt((double)(d1 * d1) +
(d2 * d2) +
return sqrt((double)(d1 * d1) + (d2 * d2) +
(d3 * d3)) <= (tolerance * 442.0f);
}
}

View File

@ -6,6 +6,7 @@
#include "inline_keywords.h" /* For H_INLINE */
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
/* Some generic, cross-platform types. */
#ifdef RobotGo_64
@ -16,49 +17,24 @@
typedef uint32_t uintptr; // Unsigned pointer integer
#endif
struct _MMPoint {
size_t x;
size_t y;
};
typedef struct _MMPoint MMPoint;
struct _MMPointInt32 {
int32_t x;
int32_t y;
};
typedef struct _MMPointInt32 MMPointInt32;
struct _MMSize {
size_t width;
size_t height;
};
typedef struct _MMSize MMSize;
struct _MMSizeInt32 {
int32_t w;
int32_t h;
};
typedef struct _MMSizeInt32 MMSizeInt32;
struct _MMRect {
MMPoint origin;
MMSize size;
};
typedef struct _MMRect MMRect;
struct _MMRectInt32 {
MMPointInt32 origin;
MMSizeInt32 size;
};
typedef struct _MMRectInt32 MMRectInt32;
H_INLINE MMPoint MMPointMake(size_t x, size_t y) {
MMPoint point;
point.x = x;
point.y = y;
return point;
}
H_INLINE MMPointInt32 MMPointInt32Make(int32_t x, int32_t y) {
MMPointInt32 point;
point.x = x;
@ -66,13 +42,6 @@ H_INLINE MMPointInt32 MMPointInt32Make(int32_t x, int32_t y) {
return point;
}
H_INLINE MMSize MMSizeMake(size_t width, size_t height) {
MMSize size;
size.width = width;
size.height = height;
return size;
}
H_INLINE MMSizeInt32 MMSizeInt32Make(int32_t w, int32_t h) {
MMSizeInt32 size;
size.w = w;
@ -80,13 +49,6 @@ H_INLINE MMSizeInt32 MMSizeInt32Make(int32_t w, int32_t h) {
return size;
}
H_INLINE MMRect MMRectMake(size_t x, size_t y, size_t width, size_t height) {
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;
rect.origin = MMPointInt32Make(x, y);
@ -94,17 +56,12 @@ H_INLINE MMRectInt32 MMRectInt32Make(int32_t x, int32_t y, int32_t w, int32_t h)
return rect;
}
//
#define MMPointZero MMPointMake(0, 0)
#define MMPointZero MMPointInt32Make(0, 0)
#if defined(IS_MACOSX)
#define CGPointFromMMPoint(p) CGPointMake((CGFloat)(p).x, (CGFloat)(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)
#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

View File

@ -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 */

View File

@ -1,6 +1,6 @@
#include "xdisplay.h"
#include <stdio.h> /* For fputs() */
#include <stdlib.h> /* For atexit() */
#include <X11/Xlib.h>
static Display *mainDisplay = NULL;
static int registered = 0;
@ -8,6 +8,13 @@ static int registered = 0;
static char *displayName = NULL;
static int hasDisplayNameChanged = 0;
void XCloseMainDisplay(void) {
if (mainDisplay != NULL) {
XCloseDisplay(mainDisplay);
mainDisplay = NULL;
}
}
Display *XGetMainDisplay(void) {
/* Close the display if displayName has changed */
if (hasDisplayNameChanged) {
@ -40,13 +47,6 @@ Display *XGetMainDisplay(void) {
return mainDisplay;
}
void XCloseMainDisplay(void) {
if (mainDisplay != NULL) {
XCloseDisplay(mainDisplay);
mainDisplay = NULL;
}
}
void setXDisplay(char *name) {
displayName = strdup(name);
hasDisplayNameChanged = 1;
@ -55,4 +55,3 @@ void setXDisplay(char *name) {
char *getXDisplay(void) {
return displayName;
}

View File

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

View File

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

119
doc.go Normal file
View 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
View 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).

View File

@ -1,3 +1,25 @@
## Type Conversion
| | type conversion | func |
| --- | --------------------------------- | ----------------------- |
| \* | robotgo.Bitmap -> robotgo.CBitmap | robotgo.ToCBitmap() |
| | robotgo.Bitmap -> \*image.RGBA | robotgo.ToRGBAGo() |
| \* | robotgo.CBitmap -> C.MMBitmapRef | robotgo.ToMMBitmapRef() |
| | robotgo.CBitmap -> robotgo.Bitmap | robotgo.ToBitmap() |
| | robotgo.CBitmap -> image.Image | robotgo.ToImage() |
| | robotgo.CBitmap -> \*image.RGBA | robotgo.ToRGBA() |
| \* | C.MMBitmapRef -> robotgo.CBitmap | robotgo.CBitmap() |
| \* | image.Image -> robotgo.Bitmap | robotgo.ImgToBitmap() |
| | image.Image -> robotgo.CBitmap | robotgo.ImgToCBitmap() |
| | image.Image -> []byte | robotgo.ToByteImg() |
| | image.Image -> string | robotgo.ToStringImg() |
| \* | \*image.RGBA -> robotgo.Bitmap | robotgo.RGBAToBitmap() |
| \* | []byte -> image.Image | robotgo.ByteToImg() |
| | []byte-> robotgo.CBitmap | robotgo.ByteToCBitmap() |
| | []byte -> string | string() |
| \* | string -> image.Image | robotgo.StrToImg() |
| | string -> byte | []byte() |
# Keys
```Go
@ -118,4 +140,4 @@
"lights_kbd_toggle" Toggle keyboard backlight on/off No Windows support
"lights_kbd_up" Turn up keyboard backlight brightness No Windows support
"lights_kbd_down" Turn down keyboard backlight brightness No Windows support
```
```

View File

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

View File

@ -18,26 +18,29 @@ import (
)
func typeStr() {
// importing "Hello World"
robotgo.TypeStr("Hello World!", 1.0)
// typing "Hello World"
robotgo.TypeStr("Hello World!", 0, 1)
robotgo.KeySleep = 100
robotgo.TypeStr("だんしゃり")
robotgo.TypeStr("Hi galaxy. こんにちは世界. 你好, 再见!")
robotgo.TypeStr("Hi galaxy, hi stars, hi MT.Rainier, hi sea. こんにちは世界.")
robotgo.TypeStr("So, hi, bye! 你好, 再见!")
robotgo.Sleep(1)
robotgo.TypeStr("So, hi, bye!")
robotgo.TypeStr("Hi, Seattle space needle, Golden gate bridge, One world trade center.")
robotgo.MilliSleep(100)
ustr := uint32(robotgo.CharCodeAt("So, hi, bye!", 0))
robotgo.UnicodeType(ustr)
robotgo.PasteStr("paste string")
err := robotgo.PasteStr("paste string")
fmt.Println("PasteStr: ", err)
}
func keyTap() {
// press "enter"
robotgo.KeyTap("enter")
robotgo.KeyTap(robotgo.Enter)
robotgo.KeySleep = 200
robotgo.KeyTap("a")
robotgo.MilliSleep(100)
@ -45,19 +48,19 @@ func keyTap() {
// hide window
err := robotgo.KeyTap("h", "cmd")
if err != "" {
if err != nil {
fmt.Println("robotgo.KeyTap run error is: ", err)
}
robotgo.KeyTap("h", "cmd", 12)
robotgo.KeyTap("h", "cmd")
// press "i", "alt", "command" Key combination
robotgo.KeyTap("i", "alt", "command")
robotgo.KeyTap("i", "alt", "cmd", 11)
robotgo.KeyTap(robotgo.KeyI, robotgo.Alt, robotgo.Cmd)
robotgo.KeyTap("i", "alt", "cmd")
arr := []string{"alt", "cmd"}
robotgo.KeyTap("i", arr)
robotgo.KeyTap("i", arr, 12)
robotgo.KeyTap("i", arr)
robotgo.KeyTap("i", "cmd", " alt", "shift")
@ -71,9 +74,17 @@ func keyTap() {
robotgo.KeyTap("a", "control")
}
func special() {
robotgo.TypeStr("{}")
robotgo.KeyTap("[", "]")
robotgo.KeyToggle("(")
robotgo.KeyToggle("(", "up")
}
func keyToggle() {
// robotgo.KeySleep = 150
robotgo.KeyToggle("a", "down")
robotgo.KeyToggle(robotgo.KeyA)
robotgo.KeyToggle("a", "down", "alt")
robotgo.Sleep(1)
@ -81,8 +92,8 @@ func keyToggle() {
robotgo.MilliSleep(100)
robotgo.KeyToggle("q", "up", "alt", "cmd", "shift")
err := robotgo.KeyToggle("enter", "down")
if err != "" {
err := robotgo.KeyToggle(robotgo.Enter)
if err != nil {
fmt.Println("robotgo.KeyToggle run error is: ", err)
}
}
@ -110,6 +121,7 @@ func key() {
////////////////////////////////////////////////////////////////////////////////
typeStr()
special()
keyTap()
keyToggle()

View File

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

View File

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

View File

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

View File

@ -28,7 +28,7 @@ func alert() {
func get() {
// get the current process id
pid := robotgo.GetPID()
pid := robotgo.GetPid()
fmt.Println("pid----", pid)
// get current Window Active
@ -49,31 +49,45 @@ func get() {
func findIds() {
// find the process id by the process name
fpid, err := robotgo.FindIds("Google")
if err == nil {
fmt.Println("pids...", fpid)
if len(fpid) > 0 {
robotgo.ActivePID(fpid[0])
if err != nil {
fmt.Println(err)
return
}
tl := robotgo.GetTitle(fpid[0])
fmt.Println("pid[0] title is: ", tl)
if len(fpid) > 0 {
robotgo.KeyTap("a", fpid[0])
robotgo.TypeStr("Hi galaxy!", fpid[0])
x, y, w, h := robotgo.GetBounds(fpid[0])
fmt.Println("GetBounds is: ", x, y, w, h)
robotgo.KeyToggle("a", fpid[0], "cmd")
robotgo.KeyToggle("a", fpid[0], "cmd", "up")
}
// Windows
// hwnd := robotgo.FindWindow("google")
// hwnd := robotgo.GetHWND()
robotgo.MinWindow(fpid[0])
robotgo.MaxWindow(fpid[0])
robotgo.CloseWindow(fpid[0])
robotgo.Kill(fpid[0])
fmt.Println("pids...", fpid)
if len(fpid) > 0 {
err = robotgo.ActivePid(fpid[0])
if err != nil {
fmt.Println(err)
}
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() {
robotgo.ActivePID(100)
robotgo.ActivePid(100)
// robotgo.Sleep(2)
robotgo.ActiveName("code")
robotgo.Sleep(1)

49
go.mod
View File

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

123
go.sum
View File

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

6
img.go
View File

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

739
key.go Normal file
View File

@ -0,0 +1,739 @@
// 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 keyToggles(k string, keyArr []string, pid int) error {
if len(keyArr) <= 0 {
keyArr = append(keyArr, "down")
}
down := true
if keyArr[0] == "up" {
down = false
}
if keyArr[0] == "up" || keyArr[0] == "down" {
keyArr = keyArr[1:]
}
flags := getFlagsFromValue(keyArr)
key, err := checkKeyCodes(k)
if err != nil {
return err
}
C.toggleKeyCode(key, C.bool(down), flags, C.uintptr(pid))
MilliSleep(KeySleep)
return nil
}
/*
__ ___ ___________ ____ .______ ______ ___ .______ _______
| |/ / | ____\ \ / / | _ \ / __ \ / \ | _ \ | \
| ' / | |__ \ \/ / | |_) | | | | | / ^ \ | |_) | | .--. |
| < | __| \_ _/ | _ < | | | | / /_\ \ | / | | | |
| . \ | |____ | | | |_) | | `--' | / _____ \ | |\ \----.| '--' |
|__|\__\ |_______| |__| |______/ \______/ /__/ \__\ | _| `._____||_______/
*/
// 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)
}
// 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
if len(key) > 0 && unicode.IsUpper([]rune(key)[0]) {
args = append(args, "shift")
}
key = strings.ToLower(key)
if _, ok := Special[key]; ok {
key = Special[key]
if len(args) <= 0 {
args = append(args, "shift")
}
}
pid := 0
if len(args) > 0 {
if reflect.TypeOf(args[0]) == reflect.TypeOf(keyArr) {
keyArr = args[0].([]string)
} else {
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)
}
// 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 {
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) <= 1 {
args = append(args, "shift")
}
}
pid := 0
var keyArr []string
if len(args) > 0 && reflect.TypeOf(args[0]) == reflect.TypeOf(pid) {
pid = args[0].(int)
keyArr = ToStrings(args[1:])
} else {
keyArr = ToStrings(args)
}
return keyToggles(key, keyArr, pid)
}
// KeyPress press key string
func KeyPress(key string, args ...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
}

View File

@ -1,397 +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 "";
}
// remove
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 set_keyboard_delay(size_t val){
keyboardDelay = val;
}

11
key/key.go Normal file
View 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
View File

@ -0,0 +1,4 @@
//go:build windows
// +build windows
package key

View File

@ -4,11 +4,6 @@
#include "../base/os.h"
#ifdef __cplusplus
extern "C"
{
#endif
#if defined(IS_MACOSX)
#include <Carbon/Carbon.h> /* Really only need <HIToolbox/Events.h> */
@ -96,6 +91,13 @@ enum _MMKeyCode {
K_NUMPAD_CLEAR = kVK_ANSI_KeypadClear,
K_NUMPAD_ENTER = kVK_ANSI_KeypadEnter,
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_DOWN = 1001,
@ -177,7 +179,7 @@ enum _MMKeyCode {
K_SHIFT = XK_Shift_L,
K_LSHIFT = XK_Shift_L,
K_RSHIFT = XK_Shift_R,
K_CAPSLOCK = XK_Shift_Lock,
K_CAPSLOCK = XK_Caps_Lock,
K_SPACE = XK_space,
K_INSERT = XK_Insert,
K_PRINTSCREEN = XK_Print,
@ -204,6 +206,13 @@ enum _MMKeyCode {
K_NUMPAD_CLEAR = K_NOT_A_KEY,
K_NUMPAD_ENTER = 96, // XK_KP_Enter
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_DOWN = XF86XK_AudioLowerVolume,
@ -227,6 +236,53 @@ enum _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)
enum _MMKeyCode {
@ -308,6 +364,13 @@ enum _MMKeyCode {
K_NUMPAD_CLEAR = K_NOT_A_KEY,
K_NUMPAD_ENTER = VK_RETURN,
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_DOWN = VK_VOLUME_DOWN,
@ -338,7 +401,3 @@ typedef int MMKeyCode;
MMKeyCode keyCodeForChar(const char c);
#endif /* KEYCODE_H */
#ifdef __cplusplus
}
#endif

View File

@ -4,68 +4,16 @@
#include <CoreFoundation/CoreFoundation.h>
#include <Carbon/Carbon.h> /* For kVK_ constants, and TIS functions. */
/* Returns string representation of key, if it is printable.
* Ownership follows the Create Rule; that is, it is the caller's
* responsibility to release the returned object. */
/* Returns string representation of key, if it is printable.
Ownership follows the Create Rule;
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
MMKeyCode keyCodeForChar(const char c){
MMKeyCode keyCodeForChar(const char c) {
#if defined(IS_MACOSX)
/* OS X does not appear to have a built-in function for this, so instead we
* have to write our own. */
/* OS X does not appear to have a built-in function for this,
so instead it to write our own. */
static CFMutableDictionaryRef charToCodeDict = NULL;
CGKeyCode code;
UniChar character = c;
@ -89,20 +37,13 @@ MMKeyCode keyCodeForChar(const char c){
}
charStr = CFStringCreateWithCharacters(kCFAllocatorDefault, &character, 1);
/* Our values may be NULL (0), so we need to use this function. */
if (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr,
(const void **)&code)) {
if (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr, (const void **)&code)) {
code = UINT16_MAX; /* Error */
}
CFRelease(charStr);
// TISGetInputSourceProperty may return nil so we need fallback
if (code == UINT16_MAX) {
code = keyCodeForCharFallBack(c);
}
if (code == UINT16_MAX) {
return K_NOT_A_KEY;
}
@ -117,17 +58,13 @@ MMKeyCode keyCodeForChar(const char c){
return code;
#elif defined(USE_X11)
MMKeyCode code;
char buf[2];
buf[0] = c;
buf[1] = '\0';
code = XStringToKeysym(buf);
MMKeyCode code = XStringToKeysym(buf);
if (code == NoSymbol) {
/* Some special keys are apparently not handled properly by
* XStringToKeysym() on some systems, so search for them instead in our
* mapping table. */
/* Some special keys are apparently not handled properly */
struct XSpecialCharacterMapping* xs = XSpecialCharacterTable;
while (xs->name) {
if (c == xs->name) {
@ -143,74 +80,33 @@ MMKeyCode keyCodeForChar(const char c){
return K_NOT_A_KEY;
}
// x11 key bug
if (c == 60) {
code = 44;
}
return code;
#endif
}
#if defined(IS_MACOSX)
CFStringRef createStringForKey(CGKeyCode keyCode){
TISInputSourceRef currentKeyboard = TISCopyCurrentASCIICapableKeyboardInputSource();
CFDataRef layoutData = (CFDataRef) TISGetInputSourceProperty(
currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
CFStringRef createStringForKey(CGKeyCode keyCode){
// TISInputSourceRef currentKeyboard = TISCopyCurrentASCIICapableKeyboardInputSource();
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardLayoutInputSource();
CFDataRef layoutData = (CFDataRef) TISGetInputSourceProperty(
currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
if (layoutData == nil) { return 0; }
if (layoutData == nil) { return 0; }
const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *) CFDataGetBytePtr(layoutData);
UInt32 keysDown = 0;
UniChar chars[4];
UniCharCount realLength;
const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *) CFDataGetBytePtr(layoutData);
UInt32 keysDown = 0;
UniChar chars[4];
UniCharCount realLength;
UCKeyTranslate(keyboardLayout, keyCode, kUCKeyActionDisplay, 0, LMGetKbdType(),
kUCKeyTranslateNoDeadKeysBit, &keysDown,
sizeof(chars) / sizeof(chars[0]), &realLength, chars);
CFRelease(currentKeyboard);
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 CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1);
}
return K_NOT_A_KEY;
}
#endif

View File

@ -2,19 +2,12 @@
#ifndef KEYPRESS_H
#define KEYPRESS_H
#include <stdlib.h>
#include "../base/os.h"
#include "../base/types.h"
#include "keycode.h"
#if defined(_MSC_VER)
#include "../base/ms_stdbool.h"
#else
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdbool.h>
#if defined(IS_MACOSX)
typedef enum {
@ -32,7 +25,6 @@ extern "C"
MOD_CONTROL = ControlMask,
MOD_SHIFT = ShiftMask
};
typedef unsigned int MMKeyFlags;
#elif defined(IS_WINDOWS)
enum _MMKeyFlags {
@ -43,43 +35,12 @@ extern "C"
MOD_SHIFT = 0, */
MOD_META = MOD_WIN
};
typedef unsigned int MMKeyFlags;
#endif
#if defined(IS_WINDOWS)
/* Send win32 key event for given key. */
void win32KeyEvent(int key, MMKeyFlags flags);
#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
}
/* Send win32 key event for given key. */
void win32KeyEvent(int key, MMKeyFlags flags, uintptr pid, int8_t isPid);
#endif
#endif /* KEYPRESS_H */

View File

@ -1,6 +1,17 @@
#include "keypress.h"
// #include "../base/deadbeef_rand_c.h"
// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/robotgo/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#include "../base/deadbeef_rand_c.h"
#include "../base/microsleep.h"
#include "keypress.h"
#include "keycode_c.h"
#include <ctype.h> /* For isupper() */
#if defined(IS_MACOSX)
@ -14,104 +25,142 @@
/* Convenience wrappers around ugly APIs. */
#if defined(IS_WINDOWS)
#define WIN32_KEY_EVENT_WAIT(key, flags) \
(win32KeyEvent(key, flags), Sleep(DEADBEEF_RANDRANGE(0, 1)))
HWND GetHwndByPid(DWORD dwProcessId);
HWND getHwnd(uintptr pid, int8_t isPid) {
HWND hwnd = (HWND) pid;
if (isPid == 0) {
hwnd = GetHwndByPid(pid);
}
return hwnd;
}
void WIN32_KEY_EVENT_WAIT(MMKeyCode key, DWORD flags, uintptr pid) {
win32KeyEvent(key, flags, pid, 0);
Sleep(DEADBEEF_RANDRANGE(0, 1));
}
#elif defined(USE_X11)
#define X_KEY_EVENT(display, key, is_press) ( \
XTestFakeKeyEvent(display, XKeysymToKeycode(display, key), is_press, CurrentTime), \
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)))
Display *XGetMainDisplay(void);
void X_KEY_EVENT(Display *display, MMKeyCode key, bool is_press) {
XTestFakeKeyEvent(display, XKeysymToKeycode(display, key), is_press, CurrentTime);
XSync(display, false);
}
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
#if defined(IS_MACOSX)
static io_connect_t _getAuxiliaryKeyDriver(void) {
static mach_port_t sEventDrvrRef = 0;
mach_port_t masterPort, service, iter;
kern_return_t kr;
if (!sEventDrvrRef) {
kr = IOMasterPort(bootstrap_port, &masterPort);
assert(KERN_SUCCESS == kr);
kr = IOServiceGetMatchingServices(masterPort, IOServiceMatching(kIOHIDSystemClass), &iter);
assert(KERN_SUCCESS == kr);
service = IOIteratorNext(iter);
assert(service);
kr = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &sEventDrvrRef);
assert(KERN_SUCCESS == kr);
IOObjectRelease(service);
IOObjectRelease(iter);
}
return sEventDrvrRef;
}
#endif
#if defined(IS_WINDOWS)
void win32KeyEvent(int key, MMKeyFlags flags) {
int scan = MapVirtualKey(key & 0xff, MAPVK_VK_TO_VSC);
/* Set the scan code for extended keys */
switch (key){
case VK_RCONTROL:
case VK_SNAPSHOT: /* Print Screen */
case VK_RMENU: /* Right Alt / Alt Gr */
case VK_PAUSE: /* Pause / Break */
case VK_HOME:
case VK_UP:
case VK_PRIOR: /* Page up */
case VK_LEFT:
case VK_RIGHT:
case VK_END:
case VK_DOWN:
case VK_NEXT: /* 'Page Down' */
case VK_INSERT:
case VK_DELETE:
case VK_LWIN:
case VK_RWIN:
case VK_APPS: /* Application */
case VK_VOLUME_MUTE:
case VK_VOLUME_DOWN:
case VK_VOLUME_UP:
case VK_MEDIA_NEXT_TRACK:
case VK_MEDIA_PREV_TRACK:
case VK_MEDIA_STOP:
case VK_MEDIA_PLAY_PAUSE:
case VK_BROWSER_BACK:
case VK_BROWSER_FORWARD:
case VK_BROWSER_REFRESH:
case VK_BROWSER_STOP:
case VK_BROWSER_SEARCH:
case VK_BROWSER_FAVORITES:
case VK_BROWSER_HOME:
case VK_LAUNCH_MAIL:
{
flags |= KEYEVENTF_EXTENDEDKEY;
break;
int SendTo(uintptr pid, CGEventRef event) {
if (pid != 0) {
CGEventPostToPid(pid, event);
} else {
CGEventPost(kCGHIDEventTap, event);
}
CFRelease(event);
return 0;
}
/* Set the scan code for keyup */
// if ( flags & KEYEVENTF_KEYUP ) {
// scan |= 0x80;
// }
// keybd_event(key, scan, flags, 0);
INPUT keyInput;
static io_connect_t _getAuxiliaryKeyDriver(void) {
static mach_port_t sEventDrvrRef = 0;
mach_port_t masterPort, service, iter;
kern_return_t kr;
keyInput.type = INPUT_KEYBOARD;
keyInput.ki.wVk = key;
keyInput.ki.wScan = scan;
keyInput.ki.dwFlags = flags;
keyInput.ki.time = 0;
keyInput.ki.dwExtraInfo = 0;
SendInput(1, &keyInput, sizeof(keyInput));
}
if (!sEventDrvrRef) {
kr = IOMasterPort(bootstrap_port, &masterPort);
assert(KERN_SUCCESS == kr);
kr = IOServiceGetMatchingServices(masterPort, IOServiceMatching(kIOHIDSystemClass), &iter);
assert(KERN_SUCCESS == kr);
service = IOIteratorNext(iter);
assert(service);
kr = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &sEventDrvrRef);
assert(KERN_SUCCESS == kr);
IOObjectRelease(service);
IOObjectRelease(iter);
}
return sEventDrvrRef;
}
#elif defined(IS_WINDOWS)
void win32KeyEvent(int key, MMKeyFlags flags, uintptr pid, int8_t isPid) {
int scan = MapVirtualKey(key & 0xff, MAPVK_VK_TO_VSC);
/* Set the scan code for extended keys */
switch (key){
case VK_RCONTROL:
case VK_SNAPSHOT: /* Print Screen */
case VK_RMENU: /* Right Alt / Alt Gr */
case VK_PAUSE: /* Pause / Break */
case VK_HOME:
case VK_UP:
case VK_PRIOR: /* Page up */
case VK_LEFT:
case VK_RIGHT:
case VK_END:
case VK_DOWN:
case VK_NEXT: /* 'Page Down' */
case VK_INSERT:
case VK_DELETE:
case VK_LWIN:
case VK_RWIN:
case VK_APPS: /* Application */
case VK_VOLUME_MUTE:
case VK_VOLUME_DOWN:
case VK_VOLUME_UP:
case VK_MEDIA_NEXT_TRACK:
case VK_MEDIA_PREV_TRACK:
case VK_MEDIA_STOP:
case VK_MEDIA_PLAY_PAUSE:
case VK_BROWSER_BACK:
case VK_BROWSER_FORWARD:
case VK_BROWSER_REFRESH:
case VK_BROWSER_STOP:
case VK_BROWSER_SEARCH:
case VK_BROWSER_FAVORITES:
case VK_BROWSER_HOME:
case VK_LAUNCH_MAIL:
{
flags |= KEYEVENTF_EXTENDEDKEY;
break;
}
}
// todo: test this
if (pid != 0) {
HWND hwnd = getHwnd(pid, isPid);
int down = (flags == 0 ? WM_KEYDOWN : WM_KEYUP);
// SendMessage(hwnd, down, key, 0);
PostMessageW(hwnd, down, key, 0);
return;
}
/* Set the scan code for keyup */
// if ( flags & KEYEVENTF_KEYUP ) {
// scan |= 0x80;
// }
// keybd_event(key, scan, flags, 0);
INPUT keyInput;
keyInput.type = INPUT_KEYBOARD;
keyInput.ki.wVk = key;
keyInput.ki.wScan = scan;
keyInput.ki.dwFlags = flags;
keyInput.ki.time = 0;
keyInput.ki.dwExtraInfo = 0;
SendInput(1, &keyInput, sizeof(keyInput));
}
#endif
void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags) {
void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags, uintptr pid) {
#if defined(IS_MACOSX)
/* The media keys all have 1000 added to them to help us detect them. */
if (code >= 1000) {
@ -130,44 +179,47 @@ void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags) {
NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE);
assert(KERN_SUCCESS == kr);
} else {
CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)code, down);
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
CGEventRef keyEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)code, down);
assert(keyEvent != NULL);
CGEventSetType(keyEvent, down ? kCGEventKeyDown : kCGEventKeyUp);
// CGEventSetFlags(keyEvent, flags);
CGEventSetFlags(keyEvent, (int) flags);
CGEventPost(kCGSessionEventTap, keyEvent);
CFRelease(keyEvent);
if (flags != 0) {
CGEventSetFlags(keyEvent, (CGEventFlags) flags);
}
SendTo(pid, keyEvent);
CFRelease(source);
}
#elif defined(IS_WINDOWS)
const DWORD dwFlags = down ? 0 : KEYEVENTF_KEYUP;
/* Parse modifier keys. */
if (flags & MOD_META) WIN32_KEY_EVENT_WAIT(K_META, dwFlags);
if (flags & MOD_ALT) WIN32_KEY_EVENT_WAIT(K_ALT, dwFlags);
if (flags & MOD_CONTROL) WIN32_KEY_EVENT_WAIT(K_CONTROL, dwFlags);
if (flags & MOD_SHIFT) WIN32_KEY_EVENT_WAIT(K_SHIFT, dwFlags);
if (flags & MOD_META) { WIN32_KEY_EVENT_WAIT(K_META, dwFlags, pid); }
if (flags & MOD_ALT) { WIN32_KEY_EVENT_WAIT(K_ALT, dwFlags, pid); }
if (flags & MOD_CONTROL) { WIN32_KEY_EVENT_WAIT(K_CONTROL, dwFlags, pid); }
if (flags & MOD_SHIFT) { WIN32_KEY_EVENT_WAIT(K_SHIFT, dwFlags, pid); }
win32KeyEvent(code, dwFlags);
win32KeyEvent(code, dwFlags, pid, 0);
#elif defined(USE_X11)
Display *display = XGetMainDisplay();
const Bool is_press = down ? True : False; /* Just to be safe. */
/* Parse modifier keys. */
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_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_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_CONTROL) { X_KEY_EVENT_WAIT(display, K_CONTROL, is_press); }
if (flags & MOD_SHIFT) { X_KEY_EVENT_WAIT(display, K_SHIFT, is_press); }
X_KEY_EVENT(display, code, is_press);
#endif
}
void tapKeyCode(MMKeyCode code, MMKeyFlags flags){
toggleKeyCode(code, true, flags);
microsleep(5.0);
toggleKeyCode(code, false, flags);
}
// void tapKeyCode(MMKeyCode code, MMKeyFlags flags){
// toggleKeyCode(code, true, flags);
// microsleep(5.0);
// toggleKeyCode(code, false, flags);
// }
#if defined(USE_X11)
bool toUpper(char c) {
@ -186,14 +238,9 @@ void tapKeyCode(MMKeyCode code, MMKeyFlags flags){
}
#endif
void toggleKey(char c, const bool down, MMKeyFlags flags){
void toggleKey(char c, const bool down, MMKeyFlags flags, uintptr pid) {
MMKeyCode keyCode = keyCodeForChar(c);
//Prevent unused variable warning for Mac and Linux.
#if defined(IS_WINDOWS)
int modifiers;
#endif
#if defined(USE_X11)
if (toUpper(c) && !(flags & MOD_SHIFT)) {
flags |= MOD_SHIFT; /* Not sure if this is safe for all layouts. */
@ -205,49 +252,86 @@ void toggleKey(char c, const bool down, MMKeyFlags flags){
#endif
#if defined(IS_WINDOWS)
modifiers = keyCode >> 8; // Pull out modifers.
if ((modifiers & 1) != 0) flags |= MOD_SHIFT; // Uptdate flags from keycode modifiers.
if ((modifiers & 2) != 0) flags |= MOD_CONTROL;
if ((modifiers & 4) != 0) flags |= MOD_ALT;
int modifiers = keyCode >> 8; // Pull out modifers.
if ((modifiers & 1) != 0) { flags |= MOD_SHIFT; } // Uptdate flags from keycode modifiers.
if ((modifiers & 2) != 0) { flags |= MOD_CONTROL; }
if ((modifiers & 4) != 0) { flags |= MOD_ALT; }
keyCode = keyCode & 0xff; // Mask out modifiers.
#endif
toggleKeyCode(keyCode, down, flags);
toggleKeyCode(keyCode, down, flags, pid);
}
void tapKey(char c, MMKeyFlags flags){
toggleKey(c, true, flags);
microsleep(5.0);
toggleKey(c, false, flags);
}
// void tapKey(char c, MMKeyFlags flags){
// toggleKey(c, true, flags);
// microsleep(5.0);
// toggleKey(c, false, flags);
// }
#if defined(IS_MACOSX)
void toggleUnicode(UniChar ch, const bool down){
/* This function relies on the convenient
* CGEventKeyboardSetUnicodeString(), which allows us to not have to
* convert characters to a keycode, but does not support adding modifier
* flags. It is therefore only used in typeStringDelayed()
* -- if you need modifier keys, use the above functions instead. */
CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, 0, down);
if (keyEvent == NULL) {
fputs("Could not create keyboard event.\n", stderr);
return;
void toggleUnicode(UniChar ch, const bool down, uintptr pid) {
/* This function relies on the convenient CGEventKeyboardSetUnicodeString(),
convert characters to a keycode, but does not support adding modifier flags.
It is only used in typeString().
-- if you need modifier keys, use the above functions instead. */
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
CGEventRef keyEvent = CGEventCreateKeyboardEvent(source, 0, down);
if (keyEvent == NULL) {
fputs("Could not create keyboard event.\n", stderr);
return;
}
CGEventKeyboardSetUnicodeString(keyEvent, 1, &ch);
SendTo(pid, keyEvent);
CFRelease(source);
}
CGEventKeyboardSetUnicodeString(keyEvent, 1, &ch);
CGEventPost(kCGSessionEventTap, keyEvent);
CFRelease(keyEvent);
}
#else
#define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE, 0)
#endif
// unicode type
void unicodeType(const unsigned value, uintptr pid, int8_t isPid) {
#if defined(IS_MACOSX)
UniChar ch = (UniChar)value; // Convert to unsigned char
toggleUnicode(ch, true, pid);
microsleep(5.0);
toggleUnicode(ch, false, pid);
#elif defined(IS_WINDOWS)
if (pid != 0) {
HWND hwnd = getHwnd(pid, isPid);
// SendMessage(hwnd, down, value, 0);
PostMessageW(hwnd, WM_CHAR, value, 0);
return;
}
INPUT input[2];
memset(input, 0, sizeof(input));
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = 0;
input[0].ki.wScan = value;
input[0].ki.dwFlags = 0x4; // KEYEVENTF_UNICODE;
input[1].type = INPUT_KEYBOARD;
input[1].ki.wVk = 0;
input[1].ki.wScan = value;
input[1].ki.dwFlags = KEYEVENTF_KEYUP | 0x4; // KEYEVENTF_UNICODE;
SendInput(2, input, sizeof(INPUT));
#elif defined(USE_X11)
toggleUniKey(value, true);
microsleep(5.0);
toggleUniKey(value, false);
#endif
}
#if defined(USE_X11)
#define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE)
int input_utf(const char *utf) {
Display *dpy;
dpy = XOpenDisplay(NULL);
Display *dpy = XOpenDisplay(NULL);
KeySym sym = XStringToKeysym(utf);
// KeySym sym = XKeycodeToKeysym(dpy, utf);
@ -268,39 +352,8 @@ void toggleUnicode(UniChar ch, const bool down){
XCloseDisplay(dpy);
return 0;
}
#endif
#if !defined(USE_X11)
#else
int input_utf(const char *utf){
return 0;
}
#endif
// unicode type
void unicodeType(const unsigned value){
#if defined(IS_MACOSX)
UniChar ch = (UniChar)value; // Convert to unsigned char
toggleUnicode(ch, true);
microsleep(5.0);
toggleUnicode(ch, false);
#elif defined(IS_WINDOWS)
INPUT input[2];
memset(input, 0, sizeof(input));
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = 0;
input[0].ki.wScan = value;
input[0].ki.dwFlags = 0x4; // KEYEVENTF_UNICODE;
input[1].type = INPUT_KEYBOARD;
input[1].ki.wVk = 0;
input[1].ki.wScan = value;
input[1].ki.dwFlags = KEYEVENTF_KEYUP | 0x4; // KEYEVENTF_UNICODE;
SendInput(2, input, sizeof(INPUT));
#elif defined(USE_X11)
toggleUniKey(value, true);
microsleep(5.0);
toggleUniKey(value, false);
#endif
}
#endif

View File

@ -19,6 +19,17 @@ type uMap map[string]uint16
// MouseMap robotgo hook mouse's code map
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
var Keycode = keycode.Keycode

View File

@ -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
View 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

View File

@ -4,24 +4,10 @@
#include "../base/os.h"
#include "../base/types.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
#include <stdbool.h>
#if defined(IS_MACOSX)
// #include </System/Library/Frameworks/ApplicationServices.framework/Headers/ApplicationServices.h>
#include <ApplicationServices/ApplicationServices.h>
// #include </System/Library/Frameworks/ApplicationServices.framework/Versions/A/Headers/ApplicationServices.h>
typedef enum {
LEFT_BUTTON = kCGMouseButtonLeft,
@ -32,9 +18,7 @@ extern "C"
WheelLeft = 6,
WheelRight = 7,
} MMMouseButton;
#elif defined(USE_X11)
enum _MMMouseButton {
LEFT_BUTTON = 1,
CENTER_BUTTON = 2,
@ -45,9 +29,7 @@ extern "C"
WheelRight = 7,
};
typedef unsigned int MMMouseButton;
#elif defined(IS_WINDOWS)
enum _MMMouseButton {
LEFT_BUTTON = 1,
CENTER_BUTTON = 2,
@ -58,62 +40,8 @@ extern "C"
WheelRight = 7,
};
typedef unsigned int MMMouseButton;
#else
#error "No mouse button constants set for platform"
#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 */

View File

@ -1,12 +1,8 @@
#include "mouse.h"
// #include "../screen/screen.h"
// #include "../screen/screen_c.h"
#include "../base/deadbeef_rand_c.h"
// #include "../deadbeef_rand.h"
#include "../base/deadbeef_rand.h"
#include "../base/microsleep.h"
#include <math.h> /* For floor() */
#if defined(IS_MACOSX)
// #include </System/Library/Frameworks/ApplicationServices.framework/Headers/ApplicationServices.h>
#include <ApplicationServices/ApplicationServices.h>
@ -15,131 +11,115 @@
#include <X11/Xlib.h>
#include <X11/extensions/XTest.h>
#include <stdlib.h>
// #include "../base/xdisplay_c.h"
#endif
#if !defined(M_SQRT2)
#define M_SQRT2 1.4142135623730950488016887 /* Fix for MSVC. */
#endif
/* Some convenience macros for converting our enums to the system API types. */
#if defined(IS_MACOSX)
CGEventType MMMouseDownToCGEventType(MMMouseButton button) {
if (button == LEFT_BUTTON) {
return kCGEventLeftMouseDown;
}
if (button == RIGHT_BUTTON) {
return kCGEventRightMouseDown;
}
return kCGEventOtherMouseDown;
}
#define MMMouseToCGEventType(down, button) \
(down ? MMMouseDownToCGEventType(button) : MMMouseUpToCGEventType(button))
CGEventType MMMouseUpToCGEventType(MMMouseButton button) {
if (button == LEFT_BUTTON) { return kCGEventLeftMouseUp; }
if (button == RIGHT_BUTTON) { return kCGEventRightMouseUp; }
return kCGEventOtherMouseUp;
}
#define MMMouseDownToCGEventType(button) \
((button) == (LEFT_BUTTON) ? kCGEventLeftMouseDown \
: ((button) == RIGHT_BUTTON ? kCGEventRightMouseDown : kCGEventOtherMouseDown))
CGEventType MMMouseDragToCGEventType(MMMouseButton button) {
if (button == LEFT_BUTTON) { return kCGEventLeftMouseDragged; }
if (button == RIGHT_BUTTON) { return kCGEventRightMouseDragged; }
return kCGEventOtherMouseDragged;
}
#define MMMouseUpToCGEventType(button) \
((button) == LEFT_BUTTON ? kCGEventLeftMouseUp \
: ((button) == RIGHT_BUTTON ? kCGEventRightMouseUp : kCGEventOtherMouseUp))
#define MMMouseDragToCGEventType(button) \
((button) == LEFT_BUTTON ? kCGEventLeftMouseDragged \
: ((button) == RIGHT_BUTTON ? kCGEventRightMouseDragged : kCGEventOtherMouseDragged))
CGEventType MMMouseToCGEventType(bool down, MMMouseButton button) {
if (down) { return MMMouseDownToCGEventType(button); }
return MMMouseUpToCGEventType(button);
}
#elif defined(IS_WINDOWS)
DWORD MMMouseUpToMEventF(MMMouseButton button) {
if (button == LEFT_BUTTON) { return MOUSEEVENTF_LEFTUP; }
if (button == RIGHT_BUTTON) { return MOUSEEVENTF_RIGHTUP; }
return MOUSEEVENTF_MIDDLEUP;
}
#define MMMouseToMEventF(down, button) \
(down ? MMMouseDownToMEventF(button) : MMMouseUpToMEventF(button))
#define MMMouseUpToMEventF(button) \
((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 MMMouseDownToMEventF(MMMouseButton button) {
if (button == LEFT_BUTTON) { return MOUSEEVENTF_LEFTDOWN; }
if (button == RIGHT_BUTTON) { return MOUSEEVENTF_RIGHTDOWN; }
return MOUSEEVENTF_MIDDLEDOWN;
}
DWORD MMMouseToMEventF(bool down, MMMouseButton button) {
if (down) { return MMMouseDownToMEventF(button); }
return MMMouseUpToMEventF(button);
}
#endif
#if defined(IS_MACOSX)
/**
* Calculate the delta for a mouse move and add them to the event.
* @param event The mouse move event (by ref).
* @param point The new mouse x and y.
*/
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 delta for a mouse move and add them to the event. */
void calculateDeltas(CGEventRef *event, MMPointInt32 point) {
/* The next few lines are a workaround for games not detecting mouse moves. */
CGEventRef get = CGEventCreate(NULL);
CGPoint mouse = CGEventGetLocation(get);
// Calculate the deltas.
int64_t deltaX = point.x - mouse.x;
int64_t deltaY = point.y - mouse.y;
// Calculate the deltas.
int64_t deltaX = point.x - mouse.x;
int64_t deltaY = point.y - mouse.y;
CGEventSetIntegerValueField(*event, kCGMouseEventDeltaX, deltaX);
CGEventSetIntegerValueField(*event, kCGMouseEventDeltaY, deltaY);
CGEventSetIntegerValueField(*event, kCGMouseEventDeltaX, deltaX);
CGEventSetIntegerValueField(*event, kCGMouseEventDeltaY, deltaY);
CFRelease(get);
}
CFRelease(get);
}
#endif
/**
* Move the mouse to a specific point.
* @param point The coordinates to move the mouse to (x, y).
*/
/* Move the mouse to a specific point. */
void moveMouse(MMPointInt32 point){
#if defined(IS_MACOSX)
CGEventRef move = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved,
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
CGEventRef move = CGEventCreateMouseEvent(source, kCGEventMouseMoved,
CGPointFromMMPointInt32(point), kCGMouseButtonLeft);
calculateDeltas(&move, point);
CGEventPost(kCGSessionEventTap, move);
CGEventPost(kCGHIDEventTap, move);
CFRelease(move);
CFRelease(source);
#elif defined(USE_X11)
Display *display = XGetMainDisplay();
XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, point.x, point.y);
XSync(display, false);
#elif defined(IS_WINDOWS)
// Mouse motion is now done using SendInput with MOUSEINPUT.
// We use Absolute mouse positioning
#define MOUSE_COORD_TO_ABS(coord, width_or_height) ( \
((65536 * coord) / width_or_height) + (coord < 0 ? -1 : 1))
MMRectInt32 rect = getScreenRect(-1);
int32_t x = MOUSE_COORD_TO_ABS(point.x - rect.origin.x, rect.size.w);
int32_t y = MOUSE_COORD_TO_ABS(point.y - rect.origin.y, rect.size.h);
INPUT mouseInput;
mouseInput.type = INPUT_MOUSE;
mouseInput.mi.dx = x;
mouseInput.mi.dy = y;
mouseInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK;
mouseInput.mi.time = 0; // System will provide the timestamp
mouseInput.mi.dwExtraInfo = 0;
mouseInput.mi.mouseData = 0;
SendInput(1, &mouseInput, sizeof(mouseInput));
SetCursorPos(point.x, point.y);
#endif
}
void dragMouse(MMPointInt32 point, const MMMouseButton button){
#if defined(IS_MACOSX)
const CGEventType dragType = MMMouseDragToCGEventType(button);
CGEventRef drag = CGEventCreateMouseEvent(NULL, dragType,
CGPointFromMMPoint(point), (CGMouseButton)button);
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
CGEventRef drag = CGEventCreateMouseEvent(source, dragType,
CGPointFromMMPointInt32(point), (CGMouseButton)button);
calculateDeltas(&drag, point);
CGEventPost(kCGSessionEventTap, drag);
CGEventPost(kCGHIDEventTap, drag);
CFRelease(drag);
CFRelease(source);
#else
moveMouse(point);
#endif
}
MMPointInt32 getMousePos(){
MMPointInt32 location() {
#if defined(IS_MACOSX)
CGEventRef event = CGEventCreate(NULL);
CGPoint point = CGEventGetLocation(event);
@ -147,9 +127,9 @@ MMPointInt32 getMousePos(){
return MMPointInt32FromCGPoint(point);
#elif defined(USE_X11)
int x, y; /* This is all we care about. Seriously. */
Window garb1, garb2; /* Why you can't specify NULL as a parameter */
int garb_x, garb_y; /* is beyond me. */
int x, y; /* This is all we care about. Seriously. */
Window garb1, garb2; /* Why you can't specify NULL as a parameter */
int garb_x, garb_y; /* is beyond me. */
unsigned int more_garbage;
Display *display = XGetMainDisplay();
@ -160,24 +140,21 @@ MMPointInt32 getMousePos(){
#elif defined(IS_WINDOWS)
POINT point;
GetCursorPos(&point);
return MMPointInt32FromPOINT(point);
#endif
}
/**
* Press down a button, or release it.
* @param down True for down, false for up.
* @param button The button to press down or release.
*/
void toggleMouse(bool down, MMMouseButton button){
/* Press down a button, or release it. */
void toggleMouse(bool down, MMMouseButton button) {
#if defined(IS_MACOSX)
const CGPoint currentPos = CGPointFromMMPoint(getMousePos());
const CGPoint currentPos = CGPointFromMMPointInt32(location());
const CGEventType mouseType = MMMouseToCGEventType(down, button);
CGEventRef event = CGEventCreateMouseEvent(NULL, mouseType, currentPos, (CGMouseButton)button);
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
CGEventRef event = CGEventCreateMouseEvent(source, mouseType, currentPos, (CGMouseButton)button);
CGEventPost(kCGSessionEventTap, event);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
CFRelease(source);
#elif defined(USE_X11)
Display *display = XGetMainDisplay();
XTestFakeButtonEvent(display, button, down ? True : False, CurrentTime);
@ -203,18 +180,16 @@ void clickMouse(MMMouseButton button){
toggleMouse(false, button);
}
/**
* Special function for sending double clicks, needed for Mac OS X.
* @param button Button to click.
*/
/* Special function for sending double clicks, needed for MacOS. */
void doubleClick(MMMouseButton button){
#if defined(IS_MACOSX)
/* Double click for Mac. */
const CGPoint currentPos = CGPointFromMMPoint(getMousePos());
const CGPoint currentPos = CGPointFromMMPointInt32(location());
const CGEventType mouseTypeDown = MMMouseToCGEventType(true, button);
const CGEventType mouseTypeUP = MMMouseToCGEventType(false, button);
CGEventRef event = CGEventCreateMouseEvent(NULL, mouseTypeDown, currentPos, kCGMouseButtonLeft);
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
CGEventRef event = CGEventCreateMouseEvent(source, mouseTypeDown, currentPos, kCGMouseButtonLeft);
/* Set event to double click. */
CGEventSetIntegerValueField(event, kCGMouseEventClickState, 2);
@ -224,6 +199,7 @@ void doubleClick(MMMouseButton button){
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
CFRelease(source);
#else
/* Double click for everything else. */
clickMouse(button);
@ -232,96 +208,30 @@ void doubleClick(MMMouseButton 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
}
/* Function used to scroll the screen in the required direction. */
void scrollMouseXY(int x, int y) {
#if defined(IS_WINDOWS)
// Fix for #97,
// C89 needs variables declared on top of functions (mouseScrollInput)
// Fix for #97, C89 needs variables declared on top of functions (mouseScrollInput)
INPUT mouseScrollInputH;
INPUT mouseScrollInputV;
#endif
/* Direction should only be considered based on the scrollDirection. This
* Should not interfere. */
/* Set up the OS specific solution */
#if defined(__APPLE__)
CGEventRef event;
event = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 2, y, x);
#if defined(IS_MACOSX)
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
CGEventRef event = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitPixel, 2, y, x);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
CFRelease(source);
#elif defined(USE_X11)
int ydir = 4; /* Button 4 is up, 5 is down. */
int xdir = 6;
Display *display = XGetMainDisplay();
if (y < 0) {
ydir = 5;
}
if (x < 0) {
xdir = 7;
}
if (y < 0) { ydir = 5; }
if (x < 0) { xdir = 7; }
int xi;
int yi;
int xi; int yi;
for (xi = 0; xi < abs(x); xi++) {
XTestFakeButtonEvent(display, xdir, 1, CurrentTime);
XTestFakeButtonEvent(display, xdir, 0, CurrentTime);
@ -354,16 +264,11 @@ void scrollMouseXY(int x, int y) {
#endif
}
/*
* A crude, fast hypot() approximation to get around the fact that hypot() is
* not a standard ANSI C function.
*
* 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
*
*/
/* A crude, fast hypot() approximation to get around the fact that hypot() is not a standard ANSI C function. */
#if !defined(M_SQRT2)
#define M_SQRT2 1.4142135623730950488016887 /* Fix for MSVC. */
#endif
static double crude_hypot(double x, double y){
double big = fabs(x); /* max(|x|, |y|) */
double small = fabs(y); /* min(|x|, |y|) */
@ -378,13 +283,12 @@ static double crude_hypot(double x, double y){
}
bool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed){
MMPointInt32 pos = getMousePos();
MMSizeInt32 screenSize = getMainDisplaySize();
MMPointInt32 pos = location();
// MMSizeInt32 screenSize = getMainDisplaySize();
double velo_x = 0.0, velo_y = 0.0;
double distance;
while ((distance =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(lowSpeed, highSpeed);
double veloDistance;
@ -399,12 +303,10 @@ bool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed)
pos.x += floor(velo_x + 0.5);
pos.y += floor(velo_y + 0.5);
/* Make sure we are in the screen boundaries!
* (Strange things will happen if we are not.) */
if (pos.x >= screenSize.w || pos.y >= screenSize.h) {
return false;
}
/* Make sure we are in the screen boundaries! (Strange things will happen if we are not.) */
// if (pos.x >= screenSize.w || pos.y >= screenSize.h) {
// return false;
// }
moveMouse(pos);
/* Wait 1 - 3 milliseconds. */

4
mouse/mouse_darwin.go Normal file
View File

@ -0,0 +1,4 @@
//go:build darwin
// +build darwin
package mouse

4
mouse/mouse_windows.go Normal file
View File

@ -0,0 +1,4 @@
//go:build windows
// +build windows
package mouse

4
mouse/mouse_x11.go Normal file
View File

@ -0,0 +1,4 @@
//go:build !darwin && !windows
// +build !darwin,!windows
package mouse

14
ps.go
View File

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

View File

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

File diff suppressed because it is too large Load Diff

95
robotgo_fn_v1.go Normal file
View 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
View 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())
}

View File

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

View File

@ -42,7 +42,7 @@ func TestSize(t *testing.T) {
func TestMoveMouse(t *testing.T) {
Move(20, 20)
MilliSleep(50)
x, y := GetMousePos()
x, y := Location()
tt.Equal(t, 20, x)
tt.Equal(t, 20, y)
@ -51,7 +51,7 @@ func TestMoveMouse(t *testing.T) {
func TestMoveMouseSmooth(t *testing.T) {
b := MoveSmooth(100, 100)
MilliSleep(50)
x, y := GetMousePos()
x, y := Location()
tt.True(t, b)
tt.Equal(t, 100, x)
@ -59,16 +59,18 @@ func TestMoveMouseSmooth(t *testing.T) {
}
func TestDragMouse(t *testing.T) {
DragMouse(500, 500)
DragSmooth(500, 500)
MilliSleep(50)
x, y := GetMousePos()
x, y := Location()
tt.Equal(t, 500, x)
tt.Equal(t, 500, y)
}
func TestScrollMouse(t *testing.T) {
// ScrollMouse(120, "up")
ScrollDir(120, "up")
ScrollDir(100, "right")
Scroll(0, 120)
MilliSleep(100)
@ -83,7 +85,7 @@ func TestMoveRelative(t *testing.T) {
MoveRelative(10, -10)
MilliSleep(50)
x, y := GetMousePos()
x, y := Location()
tt.Equal(t, 210, x)
tt.Equal(t, 190, y)
}
@ -95,28 +97,42 @@ func TestMoveSmoothRelative(t *testing.T) {
MoveSmoothRelative(10, -10)
MilliSleep(50)
x, y := GetMousePos()
x, y := Location()
tt.Equal(t, 210, x)
tt.Equal(t, 190, y)
}
func TestMouseToggle(t *testing.T) {
e := Toggle("right")
tt.Zero(t, e)
tt.Nil(t, e)
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) {
e := KeyTap("v", "cmd")
tt.Empty(t, e)
tt.Nil(t, e)
e = KeyTap("enter")
tt.Empty(t, e)
tt.Nil(t, e)
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) {
@ -133,7 +149,7 @@ func TestTypeStr(t *testing.T) {
tt.Equal(t, 115, c)
e := PasteStr("s")
tt.Empty(t, e)
tt.Nil(t, e)
s1 := "abc\\\\cd/s@世界"
uc := ToUC(s1)
@ -149,12 +165,37 @@ func TestKeyCode(t *testing.T) {
s := Special["+"]
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) {
id, err := Pids()
tt.Not(t, "[]", id)
tt.IsType(t, "[]int32", id)
tt.IsType(t, "[]int", id)
tt.Nil(t, err)
ps, e := Process()
@ -177,9 +218,14 @@ func TestPs(t *testing.T) {
id, err = FindIds(n1[0])
tt.Not(t, "[]", id)
tt.IsType(t, "[]int32", id)
tt.IsType(t, "[]int", id)
tt.Nil(t, err)
if len(id) > 0 {
e := KeyTap("v", id[0], "cmd")
tt.Nil(t, e)
}
// n, e = FindPath(id[0])
// tt.NotEmpty(t, n)
// tt.Nil(t, e)
@ -192,6 +238,6 @@ func TestPs(t *testing.T) {
// log.Println("tap...")
// }()
// i := ShowAlert("t", "msg")
// tt.Zero(t, i)
// i := Alert("t", "msg")
// tt.True(t, i)
// }

View File

@ -17,7 +17,8 @@ import (
"syscall"
"unsafe"
"github.com/lxn/win"
// "github.com/lxn/win"
"github.com/tailscale/win"
)
// FindWindow find window hwnd by name
@ -52,20 +53,48 @@ func SetFocus(hwnd win.HWND) win.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) {
if len(displayId) > 0 && displayId[0] != -1 {
dpi := GetDPI(win.HWND(displayId[0]))
f = float64(dpi) / 96.0
if displayId[0] >= 0 {
dpi := GetDPI(win.HWND(displayId[0]))
f = float64(dpi) / 96.0
}
if displayId[0] == -2 {
f = float64(GetDPI(GetDesktopWindow())) / 96.0
}
} else {
f = float64(GetMainDPI()) / 96.0
}
if f == 0.0 {
f = 1.0
}
return f
}
// GetDesktopWindow get the desktop window hwnd id
func GetDesktopWindow() win.HWND {
return win.GetDesktopWindow()
}
// GetMainDPI get the display dpi
func GetMainDPI() int {
return int(GetDPI(GetHWND()))

View File

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

63
screen.go Normal file
View 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)
}

View File

@ -9,16 +9,13 @@
// except according to those terms.
#include "../base/types.h"
#include "../base/pubs.h"
#include "../base/rgb.h"
#include "../base/win32.h"
#include "screengrab_c.h"
#include "screen_c.h"
#include <stdio.h>
// #include "../MMBitmap_c.h"
void padHex(MMRGBHex color, char* hex) {
// 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);
}
@ -29,7 +26,6 @@ char* pad_hex(MMRGBHex color) {
char* str = (char*)calloc(100, sizeof(char*));
if (str) { strcpy(str, hex); }
return str;
}
@ -54,32 +50,17 @@ MMRGBHex get_px_color(int32_t x, int32_t y, int32_t display_id) {
return color;
}
bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1), display_id);
// bitmap = MMRectMake(x, y, 1, 1);
bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1), display_id, 0);
color = MMRGBHexAtPoint(bitmap, 0, 0);
destroyMMBitmap(bitmap);
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) {
#if defined(USE_X11)
setXDisplay(name);
return "success";
return "";
#else
return "SetXDisplayName is only supported on Linux";
#endif
@ -88,8 +69,8 @@ char* set_XDisplay_name(char* name) {
char* get_XDisplay_name() {
#if defined(USE_X11)
const char* display = getXDisplay();
char* sd = (char*)calloc(100, sizeof(char*));
if (sd) { strcpy(sd, display); }
return sd;
#else
@ -97,6 +78,14 @@ char* get_XDisplay_name() {
#endif
}
void close_main_display() {
#if defined(USE_X11)
XCloseMainDisplay();
#else
//
#endif
}
uint32_t get_num_displays() {
#if defined(IS_MACOSX)
uint32_t count = 0;
@ -115,6 +104,14 @@ uint32_t get_num_displays() {
#endif
}
uintptr get_hwnd_by_pid(uintptr pid) {
#if defined(IS_WINDOWS)
HWND hwnd = GetHwndByPid(pid);
return (uintptr)hwnd;
#else
return 0;
#endif
}
void bitmap_dealloc(MMBitmapRef bitmap) {
if (bitmap != NULL) {
@ -124,9 +121,8 @@ void bitmap_dealloc(MMBitmapRef bitmap) {
}
// capture_screen capture screen
MMBitmapRef capture_screen(int32_t x, int32_t y, int32_t w, int32_t h, int32_t display_id) {
MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, w, h), display_id);
// printf("%s\n", bitmap);
MMBitmapRef capture_screen(int32_t x, int32_t y, int32_t w, int32_t h, int32_t display_id, int8_t isPid) {
MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, w, h), display_id, isPid);
return bitmap;
}

1
screen/screen.go Normal file
View File

@ -0,0 +1 @@
package screen

View File

@ -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 */

View File

@ -1,14 +1,74 @@
#include "screen.h"
//#include "../base/os.h"
#if defined(IS_MACOSX)
#include <ApplicationServices/ApplicationServices.h>
#elif defined(USE_X11)
#include <X11/Xlib.h>
#include <X11/Xresource.h>
// #include "../base/xdisplay_c.h"
#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)
CGDirectDisplayID displayID = CGMainDisplayID();
CGRect displayRect = CGDisplayBounds(displayID);
@ -23,15 +83,9 @@ MMSizeInt32 getMainDisplaySize(void){
(int32_t)DisplayWidth(display, screen),
(int32_t)DisplayHeight(display, screen));
#elif defined(IS_WINDOWS)
if (GetSystemMetrics(SM_CMONITORS) == 1) {
return MMSizeInt32Make(
return MMSizeInt32Make(
(int32_t)GetSystemMetrics(SM_CXSCREEN),
(int32_t)GetSystemMetrics(SM_CYSCREEN));
} else {
return MMSizeInt32Make(
(int32_t)GetSystemMetrics(SM_CXVIRTUALSCREEN),
(int32_t)GetSystemMetrics(SM_CYVIRTUALSCREEN));
}
#endif
}
@ -53,12 +107,12 @@ MMRectInt32 getScreenRect(int32_t display_id) {
const int screen = DefaultScreen(display);
return MMRectInt32Make(
(int32_t)0,
(int32_t)0,
(int32_t)0, (int32_t)0,
(int32_t)DisplayWidth(display, screen),
(int32_t)DisplayHeight(display, screen));
#elif defined(IS_WINDOWS)
if (GetSystemMetrics(SM_CMONITORS) == 1) {
if (GetSystemMetrics(SM_CMONITORS) == 1
|| display_id == -1 || display_id == 0) {
return MMRectInt32Make(
(int32_t)0,
(int32_t)0,

View File

@ -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 */

View File

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

38
test/index.html Normal file
View 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
View File

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

View File

@ -1,14 +1,13 @@
// #include "os.h"
#if defined(IS_MACOSX)
#include <CoreFoundation/CoreFoundation.h>
#endif
#if defined(IS_MACOSX)
#define CFStringCreateWithUTF8String(string) \
((string) == NULL ? NULL : CFStringCreateWithCString(NULL, \
string, \
kCFStringEncodingUTF8))
CFStringRef CFStringCreateWithUTF8String(const char *title) {
if (title == NULL) { return NULL; }
return CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
}
#endif
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 cancelButtonTitle = CFStringCreateWithUTF8String(cancelButton);
CFOptionFlags responseFlags;
SInt32 err = CFUserNotificationDisplayAlert(
0.0, kCFUserNotificationNoteAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage,
defaultButtonTitle, cancelButtonTitle, NULL, &responseFlags);
@ -33,10 +33,9 @@ int showAlert(const char *title, const char *msg,
#elif defined(USE_X11)
return 0;
#else
/* TODO: Display custom buttons instead of the pre-defined "OK"
* and "Cancel". */
/* TODO: Display custom buttons instead of the pre-defined "OK" and "Cancel". */
int response = MessageBox(NULL, msg, title,
(cancelButton == NULL) ? MB_OK : MB_OKCANCEL);
(cancelButton == NULL) ? MB_OK : MB_OKCANCEL );
return (response == IDOK) ? 0 : 1;
#endif
}

View File

@ -12,42 +12,23 @@
#include "window.h"
#include "win_sys.h"
int show_alert(const char *title, const char *msg,
const char *defaultButton, const char *cancelButton){
return showAlert(title, msg, defaultButton, cancelButton);
}
intptr scale_x(){
return scaleX();
}
bool is_valid(){
return IsValid();
}
void min_window(uintptr pid, bool state, uintptr isHwnd){
void min_window(uintptr pid, bool state, int8_t isPid){
#if defined(IS_MACOSX)
// return 0;
AXUIElementRef axID = AXUIElementCreateApplication(pid);
AXUIElementSetAttributeValue(axID, kAXMinimizedAttribute,
state ? kCFBooleanTrue : kCFBooleanFalse);
AXUIElementSetAttributeValue(axID, kAXMinimizedAttribute,
state ? kCFBooleanTrue : kCFBooleanFalse);
#elif defined(USE_X11)
// Ignore X errors
XDismissErrors();
// SetState((Window)pid, STATE_MINIMIZE, state);
#elif defined(IS_WINDOWS)
if (isHwnd == 0) {
HWND hwnd = GetHwndByPId(pid);
win_min(hwnd, state);
} else {
win_min((HWND)pid, state);
}
HWND hwnd = getHwnd(pid, isPid);
win_min(hwnd, state);
#endif
}
void max_window(uintptr pid, bool state, uintptr isHwnd){
void max_window(uintptr pid, bool state, int8_t isPid){
#if defined(IS_MACOSX)
// return 0;
#elif defined(USE_X11)
@ -55,25 +36,13 @@ void max_window(uintptr pid, bool state, uintptr isHwnd){
// SetState((Window)pid, STATE_MINIMIZE, false);
// SetState((Window)pid, STATE_MAXIMIZE, state);
#elif defined(IS_WINDOWS)
if (isHwnd == 0) {
HWND hwnd = GetHwndByPId(pid);
win_max(hwnd, state);
} else {
win_max((HWND)pid, state);
}
HWND hwnd = getHwnd(pid, isPid);
win_max(hwnd, state);
#endif
}
void close_window(uintptr pid, uintptr isHwnd){
close_window_by_PId(pid, isHwnd);
}
bool set_handle(uintptr handle){
return setHandle(handle);
}
uintptr get_handle(){
MData mData = GetActive();
MData mData = get_active();
#if defined(IS_MACOSX)
return (uintptr)mData.CgID;
@ -84,42 +53,17 @@ uintptr get_handle(){
#endif
}
// uint32 uintptr
uintptr getHandle() {
uintptr b_get_handle() {
#if defined(IS_MACOSX)
return (uintptr)mData.CgID;
return (uintptr)pub_mData.CgID;
#elif defined(USE_X11)
return (uintptr)mData.XWin;
return (uintptr)pub_mData.XWin;
#elif defined(IS_WINDOWS)
return (uintptr)mData.HWnd;
return (uintptr)pub_mData.HWnd;
#endif
}
uintptr bget_handle(){
return getHandle();
}
void set_active(const MData win){
SetActive(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;
void active_PID(uintptr pid, int8_t isPid){
MData win = set_handle_pid(pid, isPid);
set_active(win);
}

View File

@ -28,7 +28,7 @@ struct _MData{
};
typedef struct _MData MData;
MData mData;
MData pub_mData;
struct _Bounds {
int32_t X; // Top left X coordinate
@ -46,7 +46,6 @@ typedef struct _Bounds Bounds;
static AXUIElementRef GetUIElement(CGWindowID win){
intptr pid = 0;
// double_t pid = 0;
// Create array storing window
CGWindowID window[1] = { win };
CFArrayRef wlist = CFArrayCreate(NULL, (const void**)window, 1, NULL);
@ -59,7 +58,6 @@ typedef struct _Bounds Bounds;
if (info != NULL && CFArrayGetCount(info) > 0) {
// Retrieve description from info array
CFDictionaryRef desc = (CFDictionaryRef)CFArrayGetValueAtIndex(info, 0);
// Get window PID
CFNumberRef data = (CFNumberRef) CFDictionaryGetValue(desc, kCGWindowOwnerPID);
if (data != NULL) {
@ -193,6 +191,7 @@ typedef struct _Bounds Bounds;
if (items != NULL) {
*items = (uint32_t) nItems;
}
XCloseDisplay(rDisplay);
return result;
}
}
@ -269,7 +268,8 @@ typedef struct _Bounds Bounds;
#elif defined(IS_WINDOWS)
//
HWND getHwnd(uintptr pid, int8_t isPid);
void win_min(HWND hwnd, bool state){
if (state) {
ShowWindow(hwnd, SW_MINIMIZE);

View File

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

1
window/window.go Normal file
View File

@ -0,0 +1 @@
package window

View File

@ -8,14 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// #include "../base/os.h"
#include "pub.h"
bool setHandle(uintptr handle);
bool IsValid();
bool is_valid();
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);
void close_window_by_Id(MData m_data);
@ -24,8 +24,8 @@ uintptr initHandle = 0;
void initWindow(uintptr handle){
#if defined(IS_MACOSX)
mData.CgID = 0;
mData.AxID = 0;
pub_mData.CgID = 0;
pub_mData.AxID = 0;
#elif defined(USE_X11)
Display *rDisplay = XOpenDisplay(NULL);
// If atoms loaded
@ -34,10 +34,10 @@ void initWindow(uintptr handle){
if (rDisplay != NULL) {LoadAtoms();}
}
mData.XWin = 0;
pub_mData.XWin = 0;
XCloseDisplay(rDisplay);
#elif defined(IS_WINDOWS)
mData.HWnd = 0;
pub_mData.HWnd = 0;
#endif
setHandle(handle);
}
@ -50,7 +50,7 @@ bool Is64Bit() {
return false;
}
MData set_handle_pid(uintptr pid, uintptr isHwnd){
MData set_handle_pid(uintptr pid, int8_t isPid){
MData win;
#if defined(IS_MACOSX)
// Handle to a AXUIElementRef
@ -59,45 +59,41 @@ MData set_handle_pid(uintptr pid, uintptr isHwnd){
win.XWin = (Window)pid; // Handle to an X11 window
#elif defined(IS_WINDOWS)
// win.HWnd = (HWND)pid; // Handle to a window HWND
if (isHwnd == 0) {
win.HWnd = GetHwndByPId(pid);
} else {
win.HWnd = (HWND)pid;
}
win.HWnd = getHwnd(pid, isPid);
#endif
return win;
}
void set_handle_pid_mData(uintptr pid, uintptr isHwnd){
MData win = set_handle_pid(pid, isHwnd);
mData = win;
void set_handle_pid_mData(uintptr pid, int8_t isPid){
MData win = set_handle_pid(pid, isPid);
pub_mData = win;
}
bool IsValid() {
bool is_valid() {
initWindow(initHandle);
if (!IsAxEnabled(true)) {
printf("%s\n", "Window: Accessibility API is disabled!\n"
"Failed to enable access for assistive devices.");
printf("%s\n", "Window: Accessibility API is disabled! "
"Failed to enable access for assistive devices. \n");
}
MData actdata = GetActive();
MData actdata = get_active();
#if defined(IS_MACOSX)
mData.CgID = actdata.CgID;
mData.AxID = actdata.AxID;
if (mData.CgID == 0 || mData.AxID == 0){ return false; }
pub_mData.CgID = actdata.CgID;
pub_mData.AxID = actdata.AxID;
if (pub_mData.CgID == 0 || pub_mData.AxID == 0) { return false; }
CFTypeRef r = NULL;
// Attempt to get the window role
if (AXUIElementCopyAttributeValue(mData.AxID, kAXRoleAttribute, &r) == kAXErrorSuccess && r){
if (AXUIElementCopyAttributeValue(pub_mData.AxID, kAXRoleAttribute, &r) == kAXErrorSuccess && r){
CFRelease(r);
return true;
}
return false;
#elif defined(USE_X11)
mData.XWin = actdata.XWin;
if (mData.XWin == 0) { return false; }
pub_mData.XWin = actdata.XWin;
if (pub_mData.XWin == 0) { return false; }
Display *rDisplay = XOpenDisplay(NULL);
// Check for a valid X-Window display
@ -107,8 +103,11 @@ bool IsValid() {
XDismissErrors();
// Get the window PID property
void* result = GetWindowProperty(mData, WM_PID,NULL);
if (result == NULL) { return false; }
void* result = GetWindowProperty(pub_mData, WM_PID,NULL);
if (result == NULL) {
XCloseDisplay(rDisplay);
return false;
}
// Free result and return true
XFree(result);
@ -116,12 +115,12 @@ bool IsValid() {
return true;
#elif defined(IS_WINDOWS)
mData.HWnd = actdata.HWnd;
if (mData.HWnd == 0) {
pub_mData.HWnd = actdata.HWnd;
if (pub_mData.HWnd == 0) {
return false;
}
return IsWindow(mData.HWnd) != 0;
return IsWindow(pub_mData.HWnd) != 0;
#endif
}
@ -131,16 +130,13 @@ bool IsAxEnabled(bool options){
static dispatch_once_t once; dispatch_once (&once,
^{
// Open the framework
void* handle = dlopen("/System/Library/Frameworks/Application"
"Services.framework/ApplicationServices", RTLD_LAZY);
void* handle = dlopen("/System/Library/Frameworks/Application"
"Services.framework/ApplicationServices", RTLD_LAZY);
// Validate the handle
if (handle != NULL) {
*(void**) (&gAXIsProcessTrustedWithOptions) =
dlsym (handle, "AXIsProcessTrustedWithOptions");
gkAXTrustedCheckOptionPrompt =
(CFStringRef*) dlsym (handle, "kAXTrustedCheckOptionPrompt");
*(void**) (&gAXIsProcessTrustedWithOptions) = dlsym (handle, "AXIsProcessTrustedWithOptions");
gkAXTrustedCheckOptionPrompt = (CFStringRef*) dlsym (handle, "kAXTrustedCheckOptionPrompt");
}
});
@ -156,7 +152,6 @@ bool IsAxEnabled(bool options){
// Determine whether the process is actually trusted
bool result = (*gAXIsProcessTrustedWithOptions)(o);
// Free memory
CFRelease(o);
return result;
@ -180,13 +175,13 @@ bool IsAxEnabled(bool options){
bool setHandle(uintptr handle){
#if defined(IS_MACOSX)
// Release the AX element
if (mData.AxID != NULL) {
CFRelease(mData.AxID);
if (pub_mData.AxID != NULL) {
CFRelease(pub_mData.AxID);
}
// Reset both values
mData.CgID = 0;
mData.AxID = 0;
pub_mData.CgID = 0;
pub_mData.AxID = 0;
if (handle == 0) {
// return 0;
@ -197,8 +192,8 @@ bool setHandle(uintptr handle){
CGWindowID cgID = (CGWindowID)handle;
AXUIElementRef axID = GetUIElement(cgID);
if (axID != NULL){
mData.CgID = cgID;
mData.AxID = axID;
pub_mData.CgID = cgID;
pub_mData.AxID = axID;
// return 0;
return true;
}
@ -206,35 +201,35 @@ bool setHandle(uintptr handle){
// return 1;
return false;
#elif defined(USE_X11)
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;
pub_mData.XWin = (Window)handle;
if (handle == 0) {
return true;
}
if (IsValid()) {
if (is_valid()) {
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;
#endif
}
bool IsTopMost(void){
// Check the window validity
if (!IsValid()) {return false;}
if (!is_valid()) { return false; }
#if defined(IS_MACOSX)
return false; // WARNING: Unavailable
#elif defined(USE_X11)
@ -242,17 +237,17 @@ bool IsTopMost(void){
// XDismissErrors ();
// return GetState (mData.XWin, STATE_TOPMOST);
#elif defined(IS_WINDOWS)
return (GetWindowLongPtr(mData.HWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
return (GetWindowLongPtr(pub_mData.HWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
#endif
}
bool IsMinimized(void){
// Check the window validity
if (!IsValid()) {return false;}
if (!is_valid()) { return false; }
#if defined(IS_MACOSX)
CFBooleanRef data = NULL;
// Determine whether the window is minimized
if (AXUIElementCopyAttributeValue(mData.AxID, kAXMinimizedAttribute,
if (AXUIElementCopyAttributeValue(pub_mData.AxID, kAXMinimizedAttribute,
(CFTypeRef*) &data) == kAXErrorSuccess && data != NULL) {
// Convert resulting data into a bool
bool result = CFBooleanGetValue(data);
@ -266,14 +261,14 @@ bool IsMinimized(void){
// XDismissErrors();
// return GetState(mData.XWin, STATE_MINIMIZE);
#elif defined(IS_WINDOWS)
return (GetWindowLongPtr(mData.HWnd, GWL_STYLE) & WS_MINIMIZE) != 0;
return (GetWindowLongPtr(pub_mData.HWnd, GWL_STYLE) & WS_MINIMIZE) != 0;
#endif
}
//////
bool IsMaximized(void){
// Check the window validity
if (!IsValid()) {return false;}
if (!is_valid()) { return false; }
#if defined(IS_MACOSX)
return false; // WARNING: Unavailable
#elif defined(USE_X11)
@ -281,20 +276,19 @@ bool IsMaximized(void){
// XDismissErrors();
// return GetState(mData.XWin, STATE_MAXIMIZE);
#elif defined(IS_WINDOWS)
return (GetWindowLongPtr(mData.HWnd, GWL_STYLE) & WS_MAXIMIZE) != 0;
return (GetWindowLongPtr(pub_mData.HWnd, GWL_STYLE) & WS_MAXIMIZE) != 0;
#endif
}
void SetActive(const MData win) {
void set_active(const MData win) {
// Check if the window is valid
if (!IsValid()) { return; }
if (!is_valid()) { return; }
#if defined(IS_MACOSX)
// Attempt to raise the specified window object
if (AXUIElementPerformAction(win.AxID, kAXRaiseAction) != kAXErrorSuccess) {
pid_t pid = 0;
// Attempt to retrieve the PID of the window
if (AXUIElementGetPid(win.AxID, &pid)
!= kAXErrorSuccess || !pid) {return;}
if (AXUIElementGetPid(win.AxID, &pid) != kAXErrorSuccess || !pid) { return; }
// Ignore deprecated warnings
#pragma clang diagnostic push
@ -309,7 +303,6 @@ void SetActive(const MData win) {
#pragma clang diagnostic pop
}
#elif defined(USE_X11)
// Ignore X errors
XDismissErrors();
@ -341,7 +334,6 @@ void SetActive(const MData win) {
} else {
// Attempt to raise the specified window
XRaiseWindow(rDisplay, win.XWin);
// Set the specified window's input focus
XSetInputFocus(rDisplay, win.XWin, RevertToParent, CurrentTime);
}
@ -355,7 +347,7 @@ void SetActive(const MData win) {
#endif
}
MData GetActive(void) {
MData get_active(void) {
#if defined(IS_MACOSX)
MData result;
// Ignore deprecated warnings
@ -372,14 +364,14 @@ MData GetActive(void) {
// Create accessibility object using focused PID
AXUIElementRef focused = AXUIElementCreateApplication(pid);
if (focused == NULL) {return result; }// Verify
if (focused == NULL) { return result; } // Verify
AXUIElementRef element;
CGWindowID win = 0;
// Retrieve the currently focused window
if (AXUIElementCopyAttributeValue(focused, kAXFocusedWindowAttribute, (CFTypeRef*) &element)
== kAXErrorSuccess && element) {
CGWindowID win = 0;
// Use undocumented API to get WID
if (_AXUIElementGetWindow(element, &win) == kAXErrorSuccess && win) {
// Manually set internals
@ -388,6 +380,9 @@ MData GetActive(void) {
} else {
CFRelease(element);
}
} else {
result.CgID = win;
result.AxID = element;
}
CFRelease(focused);
@ -416,6 +411,7 @@ MData GetActive(void) {
if (window != 0) {
// Set and return the foreground window
result.XWin = (Window)window;
XCloseDisplay(rDisplay);
return result;
}
}
@ -449,39 +445,37 @@ MData GetActive(void) {
#endif
}
void SetTopMost(bool state){
// Check window validity
if (!IsValid()) {return;}
if (!is_valid()) { return; }
#if defined(IS_MACOSX)
// WARNING: Unavailable
#elif defined(USE_X11)
// Ignore X errors
// XDismissErrors();
// SetState(mData.XWin, STATE_TOPMOST, state);
// SetState(pub_mData.XWin, STATE_TOPMOST, state);
#elif defined(IS_WINDOWS)
SetWindowPos(mData.HWnd, state ? HWND_TOPMOST : HWND_NOTOPMOST,
SetWindowPos(pub_mData.HWnd, state ? HWND_TOPMOST : HWND_NOTOPMOST,
0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
#endif
}
void close_main_window (){
void close_main_window () {
// 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){
MData win = set_handle_pid(pid, isHwnd);
void close_window_by_PId(uintptr pid, int8_t isPid){
MData win = set_handle_pid(pid, isPid);
close_window_by_Id(win);
}
// CloseWindow
void close_window_by_Id(MData m_data){
// Check window validity
if (!IsValid()) { return; }
if (!is_valid()) { return; }
#if defined(IS_MACOSX)
AXUIElementRef b = NULL;
// Retrieve the close button of this window
@ -506,14 +500,14 @@ void close_window_by_Id(MData m_data){
char* get_main_title(){
// Check if the window is valid
if (!IsValid()) { return "IsValid failed."; }
return get_title_by_hand(mData);
if (!is_valid()) { return "is_valid failed."; }
return get_title_by_hand(pub_mData);
}
char* get_title_by_pid(uintptr pid, uintptr isHwnd){
MData win = set_handle_pid(pid, isHwnd);
return get_title_by_hand(win);
char* get_title_by_pid(uintptr pid, int8_t isPid){
MData win = set_handle_pid(pid, isPid);
return get_title_by_hand(win);
}
char* named(void *result) {
@ -532,7 +526,7 @@ char* named(void *result) {
char* get_title_by_hand(MData m_data){
// Check if the window is valid
if (!IsValid()) { return "IsValid failed."; }
if (!is_valid()) { return "is_valid failed."; }
#if defined(IS_MACOSX)
CFStringRef data = NULL;
// Determine the current title of the window
@ -591,23 +585,22 @@ char* get_title_by_hand(MData m_data){
#endif
}
int32_t WGetPID(void) {
int32_t get_PID(void) {
// Check window validity
if (!IsValid()) { return 0; }
if (!is_valid()) { return 0; }
#if defined(IS_MACOSX)
pid_t pid = 0;
// Attempt to retrieve the window pid
if (AXUIElementGetPid(mData.AxID, &pid)== kAXErrorSuccess) {
if (AXUIElementGetPid(pub_mData.AxID, &pid)== kAXErrorSuccess) {
return pid;
}
return 0;
#elif defined(USE_X11)
// Ignore X errors
XDismissErrors();
// Get the window PID
long* result = (long*)GetWindowProperty(mData, WM_PID,NULL);
long* result = (long*)GetWindowProperty(pub_mData, WM_PID,NULL);
// Check result and convert it
if (result == NULL) { return 0; }
@ -616,8 +609,7 @@ int32_t WGetPID(void) {
return pid;
#elif defined(IS_WINDOWS)
DWORD id = 0;
GetWindowThreadProcessId(mData.HWnd, &id);
GetWindowThreadProcessId(pub_mData.HWnd, &id);
return id;
#endif
}

2
windows_n.go Normal file
View File

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