Uses 408K of libraries. Click here for Pure Java version (3830L/24K).
1 | sclass MouseMover { |
2 | Pt cur, last; |
3 | Robot robot; |
4 | java.util.Timer timer; |
5 | int interferenceMinDistance = 100; |
6 | int mouseCheckInterval = 50; |
7 | int blockTimeAfterInterference = 5000; // ms |
8 | bool endAfterInterference = true; |
9 | volatile bool interference; |
10 | bool forceActive; |
11 | long blockUntil; |
12 | new HashSet<Int> buttonsToRelease; |
13 | sbool listenToGlobalKeyPresses; |
14 | IF0<AutoCloseable> enter; |
15 | bool verbose; |
16 | |
17 | // TODO: fix this logic... |
18 | synchronized bool enabled() { ret timer != null; } |
19 | synchronized bool hasInterference() { ret interference; } |
20 | bool active() { ret enabled() && (forceActive || !hasInterference()); } |
21 | bool active2() { ret enabled() && !blocked(); } |
22 | |
23 | synchronized MouseMover enable() ctex { |
24 | if (robot == null) robot = new Robot; |
25 | if (timer == null) { |
26 | interference = false; |
27 | cur = new Pt(mouseLocation()); |
28 | timer = doEvery(mouseCheckInterval, r checkMouse); |
29 | |
30 | if (listenToGlobalKeyPresses) |
31 | onGlobalKeyPress(r { |
32 | temp callF(enter); |
33 | if (verbose) print("Key press detected"); |
34 | haveInterference(); |
35 | }); |
36 | // TODO: on global mouse click |
37 | |
38 | if (verbose) print("Mouse automation started"); |
39 | } |
40 | ret this; |
41 | } |
42 | |
43 | bool farAway(Pt a, Pt b) { |
44 | ret pointDistance(a, b) >= interferenceMinDistance; |
45 | } |
46 | |
47 | synchronized void checkMouse() { |
48 | temp callF(enter); |
49 | if (!enabled()) ret; |
50 | blocked(); // trigger resume |
51 | Pt p = new Pt(mouseLocation()); |
52 | if (farAway(p, cur) && neq(p, last)) { |
53 | if (verbose) print("Mouse movement detected: " + nPixels(iround(ptDistance(p, cur)))); |
54 | haveInterference(); |
55 | } |
56 | } |
57 | |
58 | void haveInterference() { |
59 | temp callF(enter); |
60 | //printStackTrace("haveInterference"); |
61 | if (!enabled()) ret; |
62 | interference = true; |
63 | if (endAfterInterference) { |
64 | if (verbose) print("User interference detected, stopping automation"); |
65 | disable(); |
66 | } else { |
67 | bool blockedAlready = blocked(); |
68 | blockUntil = now()+blockTimeAfterInterference; |
69 | if (!blockedAlready) |
70 | if (verbose) print("Mouse automation blocked for at least " + blockTimeAfterInterference + " ms"); |
71 | releaseButtons(); |
72 | cur = new Pt(mouseLocation()); |
73 | if (verbose) print("Set cur to " + cur); |
74 | last = null; |
75 | } |
76 | } |
77 | |
78 | synchronized void disable() { |
79 | releaseButtons(); |
80 | if (timer != null) { |
81 | timer.cancel(); |
82 | timer = null; |
83 | /*if (!interference) |
84 | if (verbose) print("Mouse automation ended without interference");*/ |
85 | } |
86 | } |
87 | |
88 | synchronized void moveMouseImmediate(Pt p) { |
89 | checkMouse(); |
90 | if (!enabled() || blocked()) ret; |
91 | p = normalizePointToScreen(p); |
92 | if (neq(cur, p)) { |
93 | if (neq(new Pt(mouseLocation()), last)) |
94 | last = cur; |
95 | cur = p; |
96 | robot.mouseMove(p.x, p.y); |
97 | } |
98 | } |
99 | |
100 | synchronized bool blocked() { |
101 | if (!enabled() || blockUntil == 0) false; |
102 | if (now() < blockUntil) true; |
103 | blockUntil = 0; |
104 | cur = new Pt(mouseLocation()); |
105 | last = null; |
106 | if (verbose) print(prefix() + "Mouse automation resumes"); |
107 | false; |
108 | } |
109 | |
110 | void moveMouse(Pt pdest) { |
111 | if (pdest == null) ret; |
112 | print("Moving mouse to " + pdest); |
113 | Point p = getMouseLocation(); |
114 | //int steps = 20, delay = 40; // slow |
115 | //int steps = 20, delay = 20; // fast |
116 | int steps = 20, delay = 30; // medium |
117 | for (int i = 1; i <= steps; i++) { |
118 | if (blocked()) break; |
119 | Point p2 = blendPoints(p, pdest.getPoint(), ((double) i) / steps); |
120 | moveMouseImmediate(new Pt(p2)); |
121 | if (i != steps) |
122 | sleep(delay); |
123 | } |
124 | } |
125 | |
126 | void click() { |
127 | temp callF(enter); |
128 | if (active2()) { |
129 | print(prefix() + "CLICKING"); |
130 | mouseClick(); |
131 | } else print(prefix() + "Not clicking, have interference: " + hasInterference()); |
132 | } |
133 | |
134 | S prefix() { ret systemHashCode(this) + ": "; } |
135 | |
136 | void pressButton() { |
137 | robot.mousePress(addAndReturn(buttonsToRelease, InputEvent.BUTTON1_DOWN_MASK)); |
138 | } |
139 | |
140 | void releaseButton() { |
141 | robot.mouseRelease(removeAndReturn(buttonsToRelease, InputEvent.BUTTON1_DOWN_MASK)); |
142 | } |
143 | |
144 | void click(Pt p) { |
145 | moveMouse(p); |
146 | click(); |
147 | } |
148 | |
149 | void click(int x, int y) { |
150 | click(new Pt(x, y)); |
151 | } |
152 | |
153 | void cleanMeUp() { |
154 | disable(); |
155 | releaseButtons(); |
156 | } |
157 | |
158 | void releaseButtons() { |
159 | for (int btn : getAndClearList(buttonsToRelease)) |
160 | robot.mouseRelease(btn); |
161 | } |
162 | |
163 | // e.g. when user presses a button that is perform an automation |
164 | void unblock() { |
165 | blockUntil = 0; |
166 | } |
167 | } |
download show line numbers debug dex old transpilations
Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, sawdedvomwva, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1005819 |
Snippet name: | MouseMover - robot-move mouse, abort when user interferes |
Eternal ID of this version: | #1005819/46 |
Text MD5: | d8c50ca179273c16fac1531ed26523cf |
Transpilation MD5: | ff5bfd6b432dd43fb7a16e0ca84d3e73 |
Author: | stefan |
Category: | javax / automation |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2019-10-03 09:20:34 |
Source code size: | 4662 bytes / 167 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 689 / 1490 |
Version history: | 45 change(s) |
Referenced in: | [show references] |