zhmiscellanylite 0.0.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ # Auto-generated by gen_zhmiscellanylite.py from zhmiscellany.
2
+ # Do NOT hand-edit; your changes will be overwritten next ship.
3
+
4
+ import zhmiscellanylite.dict
5
+ import zhmiscellanylite.fileio
6
+ import zhmiscellanylite.list
7
+ import zhmiscellanylite.math
8
+ import zhmiscellanylite.misc
9
+ import zhmiscellanylite.processing
10
+ import zhmiscellanylite.string
@@ -0,0 +1,11 @@
1
+ def is_junction(entry):
2
+ import sys
3
+ if sys.platform != "win32":
4
+ return False
5
+ try:
6
+ st = entry.stat(follow_symlinks=False)
7
+ # On Windows, st_file_attributes is available.
8
+ # FILE_ATTRIBUTE_REPARSE_POINT (0x400) indicates a reparse point (e.g. junction).
9
+ return hasattr(st, "st_file_attributes") and bool(st.st_file_attributes & 0x400)
10
+ except Exception:
11
+ return False
@@ -0,0 +1,436 @@
1
+ import sys # this one cannot be moved unfortunately
2
+
3
+ # Windows-specific imports
4
+ if sys.platform == "win32":
5
+ WIN32_AVAILABLE = True
6
+ else:
7
+ WIN32_AVAILABLE = False
8
+
9
+ _misc_action = 0
10
+ _misc_timeout_exists = 0
11
+
12
+
13
+ def do_timeout(timeout):
14
+ import time
15
+ import os
16
+ import signal
17
+ global _misc_action, _misc_timeout_exists
18
+ self_time = time.time()
19
+ _misc_timeout_exists = self_time
20
+ while True:
21
+ time.sleep(0.1)
22
+ if time.time() - _misc_action > timeout:
23
+ os.kill(os.getpid(), signal.SIGTERM)
24
+ if self_time != _misc_timeout_exists:
25
+ return
26
+
27
+
28
+ def set_activity_timeout(timeout):
29
+ import time
30
+ import threading
31
+ global _misc_action
32
+ _misc_action = time.time()
33
+ threading.Thread(target=do_timeout, args=timeout).start()
34
+
35
+
36
+ def activity():
37
+ import time
38
+ global _misc_action
39
+ _misc_action = time.time()
40
+
41
+
42
+ def patch_rhg(): # patches random_header_generator library's missing files. this only matters if zhmiscellany has been compiled into a pyinstaller executable. zhmiscellany chooses to patch this broken package for the benefit of the user.
43
+ import os
44
+ import shutil
45
+ import zhmiscellanylite.fileio
46
+ if getattr(sys, 'frozen', False):
47
+ # we are running in a PyInstaller bundle
48
+ base_path = sys._MEIPASS
49
+ cwd = os.getcwd()
50
+ os.chdir(base_path)
51
+ from ._py_resources import gen
52
+ gen()
53
+ rem_res = not os.path.exists('resources')
54
+ if not os.path.exists('random_header_generator'):
55
+ os.makedirs(r'random_header_generator')
56
+ shutil.move(r'resources\random_header_generator\data', r'random_header_generator')
57
+ if rem_res:
58
+ zhmiscellanylite.fileio.remove_folder('resources')
59
+ os.chdir(cwd)
60
+ else:
61
+ # we are running in normal Python environment
62
+ pass
63
+
64
+ _ = None
65
+ if WIN32_AVAILABLE:
66
+ _ = patch_rhg()
67
+
68
+
69
+ def patch_cpp():
70
+ import os
71
+ import shutil
72
+ if getattr(sys, 'frozen', False):
73
+ base_path = sys._MEIPASS
74
+ else:
75
+ base_path = os.path.dirname(__file__)
76
+
77
+ anyway = False
78
+ from ._resource_files_lookup import resource_files_lookup
79
+ for file in resource_files_lookup:
80
+ if not os.path.exists(os.path.join(base_path, file)):
81
+ anyway = True # missing file detected
82
+ break
83
+
84
+ fn = 'fast_array_diff.cp310-win_amd64.pyd'
85
+
86
+ tp = os.path.join(base_path, fn)
87
+
88
+ cwd = os.getcwd()
89
+ if (not os.path.exists(tp)) or anyway:
90
+ os.chdir(base_path)
91
+ from ._py_resources import gen
92
+ gen()
93
+ shutil.copy2(os.path.join(base_path, 'resources', fn), tp)
94
+ os.chdir(cwd)
95
+
96
+
97
+ if WIN32_AVAILABLE:
98
+ patch_cpp()
99
+
100
+
101
+ def get_actual_screen_resolution():
102
+ if WIN32_AVAILABLE:
103
+ from ctypes import windll
104
+ hdc = windll.user32.GetDC(0)
105
+ width = windll.gdi32.GetDeviceCaps(hdc, 118) # HORZRES
106
+ height = windll.gdi32.GetDeviceCaps(hdc, 117) # VERTRES
107
+ windll.user32.ReleaseDC(0, hdc)
108
+ return width, height
109
+ else:
110
+ # Linux implementation using pyautogui
111
+ try:
112
+ try:
113
+ import pyautogui
114
+ pyautogui.FAILSAFE = False
115
+ pyautogui.PAUSE = 0
116
+ pyautogui.MINIMUM_DURATION = 0
117
+ except KeyError:
118
+ pass
119
+ return pyautogui.size()
120
+ except Exception:
121
+ # Could not determine screen resolution on Linux, defaulting to 1920x1080
122
+ return 1920, 1080
123
+
124
+
125
+ # Initialize Globals
126
+ SCREEN_WIDTH, SCREEN_HEIGHT = get_actual_screen_resolution()
127
+ calibrated = False
128
+ calipass = False
129
+ calibration_multiplier_x = 1.0
130
+ calibration_multiplier_y = 1.0
131
+
132
+
133
+ def move_mouse(x: int, y: int, relative=False):
134
+ # --- LINUX IMPLEMENTATION ---
135
+ if not WIN32_AVAILABLE:
136
+ try:
137
+ try:
138
+ import pyautogui
139
+ pyautogui.FAILSAFE = False
140
+ pyautogui.PAUSE = 0
141
+ pyautogui.MINIMUM_DURATION = 0
142
+ except KeyError:
143
+ pass
144
+ # PyAutoGUI handles relative/absolute logic natively
145
+ if relative:
146
+ pyautogui.move(x, y)
147
+ else:
148
+ pyautogui.moveTo(x, y)
149
+ return
150
+ except ImportError:
151
+ raise ImportError("Linux support requires pyautogui. Install it via: pip install pyautogui")
152
+ else:
153
+ from ctypes import windll
154
+ from ctypes import Structure, c_long, c_uint, c_int, POINTER, sizeof
155
+ import ctypes
156
+ import math
157
+
158
+ class POINT(Structure):
159
+ _fields_ = [("x", c_long),
160
+ ("y", c_long)]
161
+
162
+ class MOUSEINPUT(Structure):
163
+ _fields_ = [("dx", c_long),
164
+ ("dy", c_long),
165
+ ("mouseData", c_uint),
166
+ ("dwFlags", c_uint),
167
+ ("time", c_uint),
168
+ ("dwExtraInfo", POINTER(c_uint))]
169
+
170
+ class INPUT_UNION(ctypes.Union):
171
+ _fields_ = [("mi", MOUSEINPUT)]
172
+
173
+ class INPUT(Structure):
174
+ _fields_ = [("type", c_int),
175
+ ("union", INPUT_UNION)]
176
+
177
+ # Constants
178
+ MOUSEEVENTF_ABSOLUTE = 0x8000
179
+ MOUSEEVENTF_MOVE = 0x0001
180
+ MOUSEEVENTF_LEFTDOWN = 0x0002
181
+ MOUSEEVENTF_LEFTUP = 0x0004
182
+ MOUSEEVENTF_RIGHTDOWN = 0x0008
183
+ MOUSEEVENTF_RIGHTUP = 0x0010
184
+ MOUSEEVENTF_MIDDLEDOWN = 0x0020
185
+ MOUSEEVENTF_MIDDLEUP = 0x0040
186
+
187
+ if not relative:
188
+ # Convert coordinates to normalized coordinates (0-65535)
189
+ normalized_x = int(x * (65535 / SCREEN_WIDTH))
190
+ normalized_y = int(y * (65535 / SCREEN_HEIGHT))
191
+ else:
192
+ calibrate()
193
+ if calibrated:
194
+ normalized_x = math.ceil(x * calibration_multiplier_x)
195
+ normalized_y = math.ceil(y * calibration_multiplier_y)
196
+ else:
197
+ normalized_x = x
198
+ normalized_y = y
199
+
200
+ if not relative:
201
+ dwflags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE
202
+ else:
203
+ dwflags = MOUSEEVENTF_MOVE
204
+
205
+ input_struct = INPUT(
206
+ type=0, # INPUT_MOUSE
207
+ union=INPUT_UNION(
208
+ mi=MOUSEINPUT(
209
+ dx=normalized_x,
210
+ dy=normalized_y,
211
+ mouseData=0,
212
+ dwFlags=dwflags,
213
+ time=0,
214
+ dwExtraInfo=None
215
+ )
216
+ )
217
+ )
218
+
219
+ windll.user32.SendInput(1, ctypes.byref(input_struct), sizeof(INPUT))
220
+
221
+
222
+ def get_mouse_xy():
223
+ # --- LINUX IMPLEMENTATION ---
224
+ if not WIN32_AVAILABLE:
225
+ try:
226
+ try:
227
+ import pyautogui
228
+ pyautogui.FAILSAFE = False
229
+ pyautogui.PAUSE = 0
230
+ pyautogui.MINIMUM_DURATION = 0
231
+ except KeyError:
232
+ pass
233
+ return pyautogui.position()
234
+ except ImportError:
235
+ raise ImportError("Linux support requires pyautogui. Install it via: pip install pyautogui")
236
+ else:
237
+ import win32api
238
+
239
+ # --- WINDOWS IMPLEMENTATION ---
240
+ x, y = win32api.GetCursorPos()
241
+ return x, y
242
+
243
+
244
+ def calibrate():
245
+ """
246
+ Windows-specific calibration for relative movement scaling.
247
+ On Linux, libraries handle this abstraction automatically, so we skip it.
248
+ """
249
+ if not WIN32_AVAILABLE:
250
+ return
251
+
252
+ global calibration_multiplier_x, calibration_multiplier_y, calibrated, calipass
253
+ if calibrated:
254
+ return
255
+ if calipass:
256
+ return
257
+ calipass = True
258
+
259
+ # calibrate relative movement, required because windows is weird
260
+ original_mouse_point = get_mouse_xy()
261
+ calibration_distance = 128
262
+ moved_pos = (0, 0)
263
+ lim = 64
264
+ i = 0
265
+
266
+ # Note: logic below calls move_mouse, which calls calibrate,
267
+ # but calipass=True prevents recursion loop
268
+ while ((not moved_pos[0]) or (not moved_pos[1])) and i < lim:
269
+ i += 1
270
+ move_mouse(0, 0) # Reset to 0,0
271
+ move_mouse(calibration_distance, calibration_distance, relative=True)
272
+ moved_pos = get_mouse_xy()
273
+
274
+ if not i < lim:
275
+ raise Exception('Relative mouse movement could not be calibrated.')
276
+
277
+ calibration_multiplier_x = calibration_distance / moved_pos[0]
278
+ calibration_multiplier_y = calibration_distance / moved_pos[1]
279
+ calibrated = True
280
+
281
+ # Return mouse to original position
282
+ move_mouse(original_mouse_point[0], original_mouse_point[1])
283
+
284
+
285
+ def mouse_down(button: int):
286
+ """Press mouse button down. button: 1=left, 2=right, 3=middle"""
287
+ if button not in [1, 2, 3]:
288
+ raise ValueError("Button must be 1 (left), 2 (right), or 3 (middle)")
289
+
290
+ # --- LINUX IMPLEMENTATION ---
291
+ if not WIN32_AVAILABLE:
292
+ try:
293
+ try:
294
+ import pyautogui
295
+ pyautogui.FAILSAFE = False
296
+ pyautogui.PAUSE = 0
297
+ pyautogui.MINIMUM_DURATION = 0
298
+ except KeyError:
299
+ pass
300
+ btn_map = {1: 'left', 2: 'right', 3: 'middle'}
301
+ pyautogui.mouseDown(button=btn_map[button])
302
+ return
303
+ except ImportError:
304
+ raise ImportError("Linux support requires pyautogui. Install it via: pip install pyautogui")
305
+ else:
306
+ from ctypes import windll
307
+ from ctypes import Structure, c_long, c_uint, c_int, POINTER, sizeof
308
+ import ctypes
309
+
310
+ class POINT(Structure):
311
+ _fields_ = [("x", c_long),
312
+ ("y", c_long)]
313
+
314
+ class MOUSEINPUT(Structure):
315
+ _fields_ = [("dx", c_long),
316
+ ("dy", c_long),
317
+ ("mouseData", c_uint),
318
+ ("dwFlags", c_uint),
319
+ ("time", c_uint),
320
+ ("dwExtraInfo", POINTER(c_uint))]
321
+
322
+ class INPUT_UNION(ctypes.Union):
323
+ _fields_ = [("mi", MOUSEINPUT)]
324
+
325
+ class INPUT(Structure):
326
+ _fields_ = [("type", c_int),
327
+ ("union", INPUT_UNION)]
328
+
329
+ # Constants
330
+ MOUSEEVENTF_ABSOLUTE = 0x8000
331
+ MOUSEEVENTF_MOVE = 0x0001
332
+ MOUSEEVENTF_LEFTDOWN = 0x0002
333
+ MOUSEEVENTF_LEFTUP = 0x0004
334
+ MOUSEEVENTF_RIGHTDOWN = 0x0008
335
+ MOUSEEVENTF_RIGHTUP = 0x0010
336
+ MOUSEEVENTF_MIDDLEDOWN = 0x0020
337
+ MOUSEEVENTF_MIDDLEUP = 0x0040
338
+
339
+ flags = {
340
+ 1: MOUSEEVENTF_LEFTDOWN,
341
+ 2: MOUSEEVENTF_RIGHTDOWN,
342
+ 3: MOUSEEVENTF_MIDDLEDOWN
343
+ }
344
+
345
+ input_struct = INPUT(
346
+ type=0, # INPUT_MOUSE
347
+ union=INPUT_UNION(
348
+ mi=MOUSEINPUT(
349
+ dx=0,
350
+ dy=0,
351
+ mouseData=0,
352
+ dwFlags=flags[button],
353
+ time=0,
354
+ dwExtraInfo=None
355
+ )
356
+ )
357
+ )
358
+
359
+ windll.user32.SendInput(1, ctypes.byref(input_struct), sizeof(INPUT))
360
+
361
+
362
+ def mouse_up(button: int):
363
+ """Release mouse button. button: 1=left, 2=right, 3=middle"""
364
+ if button not in [1, 2, 3]:
365
+ raise ValueError("Button must be 1 (left), 2 (right), or 3 (middle)")
366
+
367
+ # --- LINUX IMPLEMENTATION ---
368
+ if not WIN32_AVAILABLE:
369
+ try:
370
+ try:
371
+ import pyautogui
372
+ pyautogui.FAILSAFE = False
373
+ pyautogui.PAUSE = 0
374
+ pyautogui.MINIMUM_DURATION = 0
375
+ except KeyError:
376
+ pass
377
+ btn_map = {1: 'left', 2: 'right', 3: 'middle'}
378
+ pyautogui.mouseUp(button=btn_map[button])
379
+ return
380
+ except ImportError:
381
+ raise ImportError("Linux support requires pyautogui. Install it via: pip install pyautogui")
382
+ else:
383
+ from ctypes import windll
384
+ from ctypes import Structure, c_long, c_uint, c_int, POINTER, sizeof
385
+ import ctypes
386
+
387
+ class POINT(Structure):
388
+ _fields_ = [("x", c_long),
389
+ ("y", c_long)]
390
+
391
+ class MOUSEINPUT(Structure):
392
+ _fields_ = [("dx", c_long),
393
+ ("dy", c_long),
394
+ ("mouseData", c_uint),
395
+ ("dwFlags", c_uint),
396
+ ("time", c_uint),
397
+ ("dwExtraInfo", POINTER(c_uint))]
398
+
399
+ class INPUT_UNION(ctypes.Union):
400
+ _fields_ = [("mi", MOUSEINPUT)]
401
+
402
+ class INPUT(Structure):
403
+ _fields_ = [("type", c_int),
404
+ ("union", INPUT_UNION)]
405
+
406
+ # Constants
407
+ MOUSEEVENTF_ABSOLUTE = 0x8000
408
+ MOUSEEVENTF_MOVE = 0x0001
409
+ MOUSEEVENTF_LEFTDOWN = 0x0002
410
+ MOUSEEVENTF_LEFTUP = 0x0004
411
+ MOUSEEVENTF_RIGHTDOWN = 0x0008
412
+ MOUSEEVENTF_RIGHTUP = 0x0010
413
+ MOUSEEVENTF_MIDDLEDOWN = 0x0020
414
+ MOUSEEVENTF_MIDDLEUP = 0x0040
415
+
416
+ flags = {
417
+ 1: MOUSEEVENTF_LEFTUP,
418
+ 2: MOUSEEVENTF_RIGHTUP,
419
+ 3: MOUSEEVENTF_MIDDLEUP
420
+ }
421
+
422
+ input_struct = INPUT(
423
+ type=0, # INPUT_MOUSE
424
+ union=INPUT_UNION(
425
+ mi=MOUSEINPUT(
426
+ dx=0,
427
+ dy=0,
428
+ mouseData=0,
429
+ dwFlags=flags[button],
430
+ time=0,
431
+ dwExtraInfo=None
432
+ )
433
+ )
434
+ )
435
+
436
+ windll.user32.SendInput(1, ctypes.byref(input_struct), sizeof(INPUT))
@@ -0,0 +1,3 @@
1
+ def print_dict(ldict):
2
+ import json
3
+ print(json.dumps(ldict, indent=4))