-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathautouimini.py
More file actions
209 lines (183 loc) · 7.59 KB
/
autouimini.py
File metadata and controls
209 lines (183 loc) · 7.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
"""
AutoUIMini — Simple UI automation helper using pyautogui
Methods:
- `sleep(t)`: Sleep for a specified time adjusted by the speed rate.
- `wait_imgdiff(x, y, width, height, timeout)`: Wait for a change in a specified screen region.
- `log(msg, key)`: Log messages with timestamps.
- `presskey(key1, key2, key3)`: Press one or more keys.
- `repeatkey(key, n)`: Press a key multiple times.
- `typewrite(text)`: Type text with a delay between keystrokes.
- `runapp(appname, wait, width, height)`: Launch an application and optionally resize its window.
- `move_cursor(x, y, isswing)`: Move the mouse cursor to specified coordinates with optional swinging.
- `swing(swing_width)`: Swing the mouse cursor left and right.
- `click(x, y, isswing)`: Click at specified coordinates with optional swinging.
- `leftclick(x, y, isswing)`: Left click at specified coordinates with optional swinging.
- Properties:
- `t_rate`: Speed rate for adjusting timings.
- `t_key`: Delay after key presses.
- `t_short`: Short wait time.
- `t_move`: Mouse move delay.
- `app_timeout`: Timeout for launching applications.
- `scale`: Coordinate scaling factor for converting logical coordinates to physical pixels.
"""
import numpy as np
import time
import sys
import subprocess
import ctypes
import pyautogui
import pygetwindow as gw
from PIL import ImageChops
class autouimini:
def __init__(self) -> None:
self.t_rate = 1.0 # speed rate
self.t_key = 0.2 # key press delay
self.t_short = 0.3 # short wait
self.t_move = 0.5 # mouse move delay
self.app_timeout = 10.0 # app launch timeout
self.scale = 1.0 # DPI scaling factor
pyautogui.FAILSAFE = True
pyautogui.PAUSE = 0.1
def sleep(self, t: float) -> None:
try:
time.sleep(t / self.t_rate)
except KeyboardInterrupt:
self.log("Interrupted by Ctrl+C. Exiting...", "Info")
sys.exit(1)
def wait_imgdiff(self, x, y, width=40, height=40, timeout=5.0):
region = (int(x), int(y), int(width), int(height))
start = time.monotonic()
prev = pyautogui.screenshot(region=region)
while time.monotonic() - start < timeout:
self.sleep(self.t_short)
cur = pyautogui.screenshot(region=region)
if ImageChops.difference(prev, cur).getbbox() is not None:
self.log("Image change detected.")
return True
prev = cur
return False
def log(self, msg: str, key: str = "Info") -> None:
t=time.time()
timestamp = f"{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(t))}.{int((t - int(t)) * 1000):03d}"
msg = f"{timestamp} {msg}"
print(msg)
sys.stdout.flush()
def presskey(self, key1: str, key2: str = "", key3: str = "") -> None:
if key2 and key3:
pyautogui.hotkey(key1, key2, key3)
elif key2:
pyautogui.hotkey(key1, key2)
else:
pyautogui.press(key1)
self.sleep(self.t_key)
def repeatkey(self, key: str, n: int) -> None:
for _ in range(n):
self.presskey(key)
self.sleep(self.t_key)
def typewrite(self, text: str) -> None:
pyautogui.typewrite(text, interval=self.t_key)
self.sleep(self.t_short)
def runapp(self, appname: str, wait: float = 2.0, width: int = None, height: int = None) -> str:
old_windows = gw.getAllWindows()
self.log(f"Opening {appname}...")
self.presskey("win","r")
self.sleep(self.t_short)
self.typewrite(appname)
self.presskey("enter")
self.sleep(wait) # Wait launching new app window
# Wait for new window to appear
start_time = time.time()
while True:
new_windows = gw.getAllWindows() # Get current window titles after launching the app
added = [w for w in new_windows if w not in old_windows]
# timeout after app_timeout seconds
if time.time() - start_time > self.app_timeout:
self.log(f"Failed to launch {appname}")
break
if added:
self.log(f"Launced {appname} successfully")
self.sleep(self.t_short)
# focus the new window
win = added[0]
win.activate()
# move window to (0,0)
win.moveTo(0, 0)
# If width/height provided, resize; otherwise maximize
try:
if width and height:
win.resizeTo(int(width), int(height))
else:
win.maximize()
except Exception:
# Some window types may not support resizeTo; fall back to maximize
try:
win.maximize()
except Exception:
pass
self.sleep(self.t_short)
break
if not added:
return ""
return added[0]
def move_cursor(self, x: int, y: int, isswing: bool = False) -> None:
# Use self.scale to convert logical coordinates -> physical pixels
phys_x = int(round(x * self.scale))
phys_y = int(round(y * self.scale))
pyautogui.moveTo(phys_x, phys_y, duration=self.t_move)
self.sleep(self.t_move)
if isswing:
self.swing()
def swing(self, swing_width: int = 30) -> None:
# Swing the mouse cursor left and right from its current position.
x, y = pyautogui.position()
for dx in [-swing_width, swing_width, -swing_width, swing_width, 0]:
pyautogui.moveTo(x + dx, y, duration= 0.2)
def click(self, x: int, y: int, isswing: bool = False) -> None:
# Click at logical coordinates (x,y) after applying self.scale.
phys_x = int(round(x * self.scale))
phys_y = int(round(y * self.scale))
if isswing:
self.swing()
pyautogui.click(phys_x, phys_y)
self.sleep(self.t_key)
def leftclick(self, x: int, y: int, isswing: bool = False) -> None:
# Left click at logical coordinates after applying self.scale.
phys_x = int(round(x * self.scale))
phys_y = int(round(y * self.scale))
if isswing:
self.swing()
pyautogui.click(phys_x, phys_y, button='left')
self.sleep(self.t_key)
def set_clipboard(self, text: str) -> None:
subprocess.run("clip", text=True, input=text)
def main() -> None:
# Demo: Open MS Paint, paste screenshot, resize it.
ui = autouimini()
# Capture the current screen to clipboard first
ui.log("Capturing full screen to clipboard")
# Press PrintScreen key
ui.presskey("alt", "printscreen")
# Then open MS Paint and paste
ui.runapp("mspaint")
ui.move_cursor(490,990, isswing=True)
# Resize image to 10x10 before pasting
ui.log("Resize to 10x10")
ui.presskey("ctrl", "e")
ui.typewrite("10")
ui.presskey("tab")
ui.typewrite("10")
ui.presskey("enter")
ui.log("Pasting image from clipboard")
ui.presskey("ctrl", "v")
ui.presskey("ctrl", "a")
ui.presskey("escape")
ui.log("Resize to 50%")
ui.presskey("ctrl", "w")
ui.typewrite("50")
ui.presskey("enter")
ui.log("Copying final image to clipboard")
ui.presskey("ctrl", "a")
ui.presskey("ctrl", "c")
ui.log("Demo completed.")
if __name__ == "__main__":
main()