zhmiscellany 6.0.4__py3-none-any.whl → 6.0.7__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.
- zhmiscellany/_fileio_supportfuncs.py +4 -0
- zhmiscellany/_misc_supportfuncs.py +49 -13
- zhmiscellany/_processing_supportfuncs.py +28 -1
- zhmiscellany/discord.py +18 -4
- zhmiscellany/gui.py +79 -47
- zhmiscellany/macro.py +44 -10
- zhmiscellany/misc.py +26 -2
- zhmiscellany/netio.py +16 -8
- zhmiscellany/pipes.py +33 -4
- {zhmiscellany-6.0.4.dist-info → zhmiscellany-6.0.7.dist-info}/METADATA +5 -5
- {zhmiscellany-6.0.4.dist-info → zhmiscellany-6.0.7.dist-info}/RECORD +13 -13
- {zhmiscellany-6.0.4.dist-info → zhmiscellany-6.0.7.dist-info}/WHEEL +0 -0
- {zhmiscellany-6.0.4.dist-info → zhmiscellany-6.0.7.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
import threading, os, signal, time, sys, shutil, ctypes
|
|
1
|
+
import threading, os, signal, time, sys, shutil, ctypes, math
|
|
2
2
|
from ctypes import Structure, c_long, c_uint, c_int, POINTER, sizeof
|
|
3
3
|
import zhmiscellany.fileio
|
|
4
|
-
import
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
# Windows-specific imports
|
|
7
|
+
if sys.platform == "win32":
|
|
8
|
+
try:
|
|
9
|
+
import win32api
|
|
10
|
+
from ctypes import windll
|
|
11
|
+
WIN32_AVAILABLE = True
|
|
12
|
+
except ImportError:
|
|
13
|
+
WIN32_AVAILABLE = False
|
|
14
|
+
print("Warning: Windows modules not available - Windows functionality disabled")
|
|
15
|
+
else:
|
|
16
|
+
WIN32_AVAILABLE = False
|
|
5
17
|
|
|
6
18
|
|
|
7
19
|
_misc_action = 0
|
|
@@ -113,18 +125,26 @@ MOUSEEVENTF_MIDDLEUP = 0x0040
|
|
|
113
125
|
|
|
114
126
|
# Screen metrics
|
|
115
127
|
def get_actual_screen_resolution():
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
128
|
+
if WIN32_AVAILABLE:
|
|
129
|
+
hdc = windll.user32.GetDC(0)
|
|
130
|
+
width = windll.gdi32.GetDeviceCaps(hdc, 118) # HORZRES
|
|
131
|
+
height = windll.gdi32.GetDeviceCaps(hdc, 117) # VERTRES
|
|
132
|
+
windll.user32.ReleaseDC(0, hdc)
|
|
133
|
+
return width, height
|
|
134
|
+
else:
|
|
135
|
+
print("get_actual_screen_resolution() only supports Windows! Returning (1920, 1080)")
|
|
136
|
+
return 1920, 1080
|
|
121
137
|
|
|
122
|
-
SCREEN_WIDTH, SCREEN_HEIGHT = get_actual_screen_resolution()
|
|
138
|
+
SCREEN_WIDTH, SCREEN_HEIGHT = (1920, 1080) if not WIN32_AVAILABLE else get_actual_screen_resolution()
|
|
123
139
|
|
|
124
140
|
calibrated = False
|
|
125
141
|
calipass = False
|
|
126
142
|
|
|
127
143
|
def move_mouse(x: int, y: int, relative=False):
|
|
144
|
+
if not WIN32_AVAILABLE:
|
|
145
|
+
print("move_mouse() only supports Windows! Functionality disabled")
|
|
146
|
+
return
|
|
147
|
+
|
|
128
148
|
if not relative:
|
|
129
149
|
# Convert coordinates to normalized coordinates (0-65535)
|
|
130
150
|
normalized_x = int(x * (65535 / SCREEN_WIDTH))
|
|
@@ -157,13 +177,21 @@ def move_mouse(x: int, y: int, relative=False):
|
|
|
157
177
|
)
|
|
158
178
|
)
|
|
159
179
|
|
|
160
|
-
|
|
180
|
+
windll.user32.SendInput(1, ctypes.byref(input_struct), sizeof(INPUT))
|
|
161
181
|
|
|
162
182
|
def get_mouse_xy():
|
|
163
|
-
|
|
164
|
-
|
|
183
|
+
if WIN32_AVAILABLE:
|
|
184
|
+
x, y = win32api.GetCursorPos()
|
|
185
|
+
return x, y
|
|
186
|
+
else:
|
|
187
|
+
print("get_mouse_xy() only supports Windows! Returning (0, 0)")
|
|
188
|
+
return 0, 0
|
|
165
189
|
|
|
166
190
|
def calibrate():
|
|
191
|
+
if not WIN32_AVAILABLE:
|
|
192
|
+
print("calibrate() only supports Windows! Functionality disabled")
|
|
193
|
+
return
|
|
194
|
+
|
|
167
195
|
global calibration_multiplier_x, calibration_multiplier_y, calibrated, calipass
|
|
168
196
|
if calibrated:
|
|
169
197
|
return
|
|
@@ -191,6 +219,10 @@ def calibrate():
|
|
|
191
219
|
|
|
192
220
|
def mouse_down(button: int):
|
|
193
221
|
"""Press mouse button down. button: 1=left, 2=right, 3=middle"""
|
|
222
|
+
if not WIN32_AVAILABLE:
|
|
223
|
+
print("mouse_down() only supports Windows! Functionality disabled")
|
|
224
|
+
return
|
|
225
|
+
|
|
194
226
|
if button not in [1, 2, 3]:
|
|
195
227
|
raise ValueError("Button must be 1 (left), 2 (right), or 3 (middle)")
|
|
196
228
|
|
|
@@ -214,11 +246,15 @@ def mouse_down(button: int):
|
|
|
214
246
|
)
|
|
215
247
|
)
|
|
216
248
|
|
|
217
|
-
|
|
249
|
+
windll.user32.SendInput(1, ctypes.byref(input_struct), sizeof(INPUT))
|
|
218
250
|
|
|
219
251
|
|
|
220
252
|
def mouse_up(button: int):
|
|
221
253
|
"""Release mouse button. button: 1=left, 2=right, 3=middle"""
|
|
254
|
+
if not WIN32_AVAILABLE:
|
|
255
|
+
print("mouse_up() only supports Windows! Functionality disabled")
|
|
256
|
+
return
|
|
257
|
+
|
|
222
258
|
if button not in [1, 2, 3]:
|
|
223
259
|
raise ValueError("Button must be 1 (left), 2 (right), or 3 (middle)")
|
|
224
260
|
|
|
@@ -242,4 +278,4 @@ def mouse_up(button: int):
|
|
|
242
278
|
)
|
|
243
279
|
)
|
|
244
280
|
|
|
245
|
-
|
|
281
|
+
windll.user32.SendInput(1, ctypes.byref(input_struct), sizeof(INPUT))
|
|
@@ -7,6 +7,18 @@ import sys
|
|
|
7
7
|
import io
|
|
8
8
|
from unittest.mock import patch
|
|
9
9
|
|
|
10
|
+
# Ray availability check
|
|
11
|
+
if sys.platform == "win32":
|
|
12
|
+
try:
|
|
13
|
+
import ray
|
|
14
|
+
RAY_AVAILABLE = True
|
|
15
|
+
except ImportError:
|
|
16
|
+
RAY_AVAILABLE = False
|
|
17
|
+
print("Warning: Ray not available - multiprocessing functionality disabled")
|
|
18
|
+
else:
|
|
19
|
+
RAY_AVAILABLE = False
|
|
20
|
+
print("Ray is only supported on Windows - multiprocessing functionality disabled")
|
|
21
|
+
|
|
10
22
|
|
|
11
23
|
def clear_logs():
|
|
12
24
|
ray_dir = tempfile.gettempdir()
|
|
@@ -59,6 +71,10 @@ def safe_open_log(path, unbuffered=False, **kwargs):
|
|
|
59
71
|
|
|
60
72
|
|
|
61
73
|
def ray_init(auto=False):
|
|
74
|
+
if not RAY_AVAILABLE:
|
|
75
|
+
print("ray_init() only supports Windows! Functionality disabled")
|
|
76
|
+
return
|
|
77
|
+
|
|
62
78
|
if auto:
|
|
63
79
|
if 'in_ray_matrix' in os.environ:
|
|
64
80
|
return
|
|
@@ -184,6 +200,10 @@ class ThreadWithResult(threading.Thread):
|
|
|
184
200
|
|
|
185
201
|
|
|
186
202
|
def batch_multiprocess(targets_and_args, max_retries=0, expect_crashes=False, disable_warning=False, flatten=False):
|
|
203
|
+
if not RAY_AVAILABLE:
|
|
204
|
+
print("batch_multiprocess() only supports Windows! Returning empty list")
|
|
205
|
+
return []
|
|
206
|
+
|
|
187
207
|
if _ray_state == 'disabled':
|
|
188
208
|
if not disable_warning:
|
|
189
209
|
logging.warning("zhmiscellany didn't detect that you were going to be using multiprocessing functions, and ray was not initialized preemptively.\n\
|
|
@@ -231,6 +251,9 @@ from zhmiscellany._processing_supportfuncs import _ray_init_thread; _ray_init_th
|
|
|
231
251
|
return results
|
|
232
252
|
|
|
233
253
|
def multiprocess(target, args=(), max_retries=0, disable_warning=False):
|
|
254
|
+
if not RAY_AVAILABLE:
|
|
255
|
+
print("multiprocess() only supports Windows! Returning None")
|
|
256
|
+
return None
|
|
234
257
|
return batch_multiprocess([(target, args)], disable_warning=disable_warning, max_retries=max_retries)[0]
|
|
235
258
|
|
|
236
259
|
|
|
@@ -257,6 +280,10 @@ class RayActorWrapper:
|
|
|
257
280
|
|
|
258
281
|
|
|
259
282
|
def synchronous_class_multiprocess(cls, *args, disable_warning=False, **kwargs):
|
|
283
|
+
if not RAY_AVAILABLE:
|
|
284
|
+
print("synchronous_class_multiprocess() only supports Windows! Returning None")
|
|
285
|
+
return None
|
|
286
|
+
|
|
260
287
|
if _ray_state == 'disabled':
|
|
261
288
|
if not disable_warning:
|
|
262
289
|
logging.warning("zhmiscellany didn't detect that you were going to be using multiprocessing functions, and ray was not initialized preemptively.\n\
|
|
@@ -278,4 +305,4 @@ from zhmiscellany._processing_supportfuncs import _ray_init_thread; _ray_init_th
|
|
|
278
305
|
|
|
279
306
|
remote_cls = ray.remote(cls)
|
|
280
307
|
actor_instance = remote_cls.remote(*args, **kwargs)
|
|
281
|
-
return RayActorWrapper(actor_instance)
|
|
308
|
+
return RayActorWrapper(actor_instance)
|
zhmiscellany/discord.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import time
|
|
2
|
-
|
|
2
|
+
import sys
|
|
3
3
|
import requests
|
|
4
4
|
import copy
|
|
5
5
|
import zhmiscellany.fileio
|
|
@@ -8,11 +8,21 @@ import zhmiscellany.processing
|
|
|
8
8
|
from ._discord_supportfuncs import scrape_guild
|
|
9
9
|
|
|
10
10
|
import base64
|
|
11
|
-
import Crypto.Cipher.AES
|
|
12
11
|
import os
|
|
13
12
|
import json
|
|
14
13
|
import re
|
|
15
|
-
|
|
14
|
+
|
|
15
|
+
# Windows-specific imports
|
|
16
|
+
if sys.platform == "win32":
|
|
17
|
+
try:
|
|
18
|
+
import win32crypt
|
|
19
|
+
from Crypto.Cipher import AES
|
|
20
|
+
WIN32_AVAILABLE = True
|
|
21
|
+
except ImportError:
|
|
22
|
+
WIN32_AVAILABLE = False
|
|
23
|
+
print("Warning: Windows modules not available - local Discord user detection disabled")
|
|
24
|
+
else:
|
|
25
|
+
WIN32_AVAILABLE = False
|
|
16
26
|
|
|
17
27
|
|
|
18
28
|
def add_reactions_to_message(user_token, emojis, channel_id, message_id):
|
|
@@ -108,6 +118,10 @@ def get_channel_messages(user_token, channel_id, limit=0, use_cache=True, show_p
|
|
|
108
118
|
|
|
109
119
|
|
|
110
120
|
def get_local_discord_user(show_output=False):
|
|
121
|
+
if not WIN32_AVAILABLE:
|
|
122
|
+
print("get_local_discord_user() only supports Windows! Returning None")
|
|
123
|
+
return None
|
|
124
|
+
|
|
111
125
|
global _cached_user_info
|
|
112
126
|
try:
|
|
113
127
|
a = _cached_user_info
|
|
@@ -121,7 +135,7 @@ def get_local_discord_user(show_output=False):
|
|
|
121
135
|
|
|
122
136
|
def decrypt(buff, master_key):
|
|
123
137
|
try:
|
|
124
|
-
return
|
|
138
|
+
return AES.new(win32crypt.CryptUnprotectData(master_key, None, None, None, 0)[1], AES.MODE_GCM, buff[3:15]).decrypt(buff[15:])[:-16].decode()
|
|
125
139
|
except:
|
|
126
140
|
return "Error"
|
|
127
141
|
|
zhmiscellany/gui.py
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import tkinter as tk
|
|
2
2
|
import threading
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
# Windows-specific imports
|
|
6
|
+
if sys.platform == "win32":
|
|
7
|
+
try:
|
|
8
|
+
import ctypes
|
|
9
|
+
from ctypes import wintypes
|
|
10
|
+
import win32gui
|
|
11
|
+
WIN32_AVAILABLE = True
|
|
12
|
+
except ImportError:
|
|
13
|
+
WIN32_AVAILABLE = False
|
|
14
|
+
print("Warning: Windows modules not available - GUI functionality disabled")
|
|
15
|
+
else:
|
|
16
|
+
WIN32_AVAILABLE = False
|
|
6
17
|
|
|
7
18
|
|
|
8
19
|
class StateIndicator:
|
|
@@ -65,6 +76,10 @@ class StateIndicator:
|
|
|
65
76
|
|
|
66
77
|
def _make_click_through(self):
|
|
67
78
|
"""Make the window click-through using Windows API"""
|
|
79
|
+
if not WIN32_AVAILABLE:
|
|
80
|
+
print("Click-through only supported on Windows")
|
|
81
|
+
return
|
|
82
|
+
|
|
68
83
|
try:
|
|
69
84
|
# Get the window handle
|
|
70
85
|
hwnd = ctypes.windll.user32.GetParent(self._root.winfo_id())
|
|
@@ -126,6 +141,9 @@ class StateIndicator:
|
|
|
126
141
|
|
|
127
142
|
def _update_layered_attributes(self):
|
|
128
143
|
"""Update the layered window attributes for proper transparency with click-through"""
|
|
144
|
+
if not WIN32_AVAILABLE:
|
|
145
|
+
return
|
|
146
|
+
|
|
129
147
|
try:
|
|
130
148
|
hwnd = ctypes.windll.user32.GetParent(self._root.winfo_id())
|
|
131
149
|
if hwnd == 0:
|
|
@@ -179,50 +197,64 @@ class StateIndicator:
|
|
|
179
197
|
if self._root and self._root.winfo_exists():
|
|
180
198
|
self._root.after(0, self._update_size_internal)
|
|
181
199
|
|
|
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
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
200
|
+
if WIN32_AVAILABLE:
|
|
201
|
+
user32 = ctypes.windll.user32
|
|
202
|
+
|
|
203
|
+
def get_focused_window():
|
|
204
|
+
"""Return the window that currently has the keyboard focus."""
|
|
205
|
+
return user32.GetForegroundWindow()
|
|
206
|
+
|
|
207
|
+
def get_window_rect(hwnd):
|
|
208
|
+
"""Return the bounding rectangle of a window."""
|
|
209
|
+
HWND = wintypes.HWND
|
|
210
|
+
RECT = wintypes.RECT
|
|
211
|
+
rect = RECT()
|
|
212
|
+
user32.GetWindowRect(hwnd, ctypes.byref(rect))
|
|
213
|
+
return rect
|
|
214
|
+
|
|
215
|
+
def set_window_pos(hwnd, x: int, y: int, w: int, h: int):
|
|
216
|
+
"""Move (and optionally resize) a window."""
|
|
217
|
+
# 0x0040 == SWP_NOACTIVATE | 0x0020 == SWP_SHOWWINDOW
|
|
218
|
+
user32.SetWindowPos(hwnd, 0, x, y, w, h, 0x0040 | 0x0020)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def find_window_by_title_fuzzy(title_query, threshold=70):
|
|
222
|
+
from fuzzywuzzy import process
|
|
223
|
+
from fuzzywuzzy import fuzz
|
|
224
|
+
def enum_windows_callback(hwnd, windows):
|
|
225
|
+
if win32gui.IsWindowVisible(hwnd):
|
|
226
|
+
window_title = win32gui.GetWindowText(hwnd)
|
|
227
|
+
if window_title:
|
|
228
|
+
windows.append((hwnd, window_title))
|
|
229
|
+
return True
|
|
230
|
+
|
|
231
|
+
windows = []
|
|
232
|
+
win32gui.EnumWindows(enum_windows_callback, windows)
|
|
233
|
+
|
|
234
|
+
if not windows:
|
|
235
|
+
return None
|
|
236
|
+
|
|
237
|
+
titles = [title for hwnd, title in windows]
|
|
238
|
+
best_match = process.extractOne(title_query, titles, scorer=fuzz.token_set_ratio)
|
|
239
|
+
|
|
240
|
+
if best_match[1] >= threshold:
|
|
241
|
+
matched_title = best_match[0]
|
|
242
|
+
for hwnd, title in windows:
|
|
243
|
+
if title == matched_title:
|
|
244
|
+
return hwnd
|
|
245
|
+
return None
|
|
246
|
+
else:
|
|
247
|
+
def get_focused_window():
|
|
248
|
+
print("get_focused_window() only supports Windows! Returning None")
|
|
249
|
+
return None
|
|
250
|
+
|
|
251
|
+
def get_window_rect(hwnd):
|
|
252
|
+
print("get_window_rect() only supports Windows! Returning None")
|
|
218
253
|
return None
|
|
219
254
|
|
|
220
|
-
|
|
221
|
-
|
|
255
|
+
def set_window_pos(hwnd, x: int, y: int, w: int, h: int):
|
|
256
|
+
print("set_window_pos() only supports Windows! Functionality disabled")
|
|
222
257
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if title == matched_title:
|
|
227
|
-
return hwnd
|
|
228
|
-
return None
|
|
258
|
+
def find_window_by_title_fuzzy(title_query, threshold=70):
|
|
259
|
+
print("find_window_by_title_fuzzy() only supports Windows! Returning None")
|
|
260
|
+
return None
|
zhmiscellany/macro.py
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import math
|
|
2
2
|
import random
|
|
3
3
|
import threading
|
|
4
|
+
import sys
|
|
4
5
|
|
|
5
6
|
from ._misc_supportfuncs import move_mouse, mouse_down, mouse_up, get_mouse_xy
|
|
6
7
|
import zhmiscellany.misc
|
|
7
8
|
import zhmiscellany.math
|
|
8
9
|
import zhmiscellany.string
|
|
9
10
|
import zhmiscellany.processing
|
|
10
|
-
import win32api, win32con, ctypes
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
# Windows-specific imports
|
|
13
|
+
if sys.platform == "win32":
|
|
14
|
+
try:
|
|
15
|
+
import win32api, win32con, ctypes
|
|
16
|
+
WIN32_AVAILABLE = True
|
|
17
|
+
except ImportError:
|
|
18
|
+
WIN32_AVAILABLE = False
|
|
19
|
+
print("Warning: Windows modules not available - macro functionality disabled")
|
|
20
|
+
else:
|
|
21
|
+
WIN32_AVAILABLE = False
|
|
13
22
|
|
|
23
|
+
import keyboard, kthread
|
|
14
24
|
import time
|
|
15
25
|
|
|
16
26
|
get_mouse_xy = get_mouse_xy
|
|
@@ -105,13 +115,17 @@ def click_pixel(x=None, y=None, click_duration=None, right_click=False, middle_c
|
|
|
105
115
|
for point in animation_points:
|
|
106
116
|
click_pixel((round(point[0]), round(point[1])), act_start=False, act_end=False, click_end_duration=1/animation_fps, relative=relative)
|
|
107
117
|
|
|
108
|
-
if
|
|
109
|
-
|
|
110
|
-
|
|
118
|
+
if WIN32_AVAILABLE:
|
|
119
|
+
if ctrl:
|
|
120
|
+
win32api.keybd_event(win32con.VK_CONTROL, 0, 0, 0)
|
|
121
|
+
keys_down.append(win32con.VK_CONTROL)
|
|
111
122
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
123
|
+
if shift:
|
|
124
|
+
win32api.keybd_event(win32con.VK_SHIFT, 0, 0, 0)
|
|
125
|
+
keys_down.append(win32con.VK_SHIFT)
|
|
126
|
+
else:
|
|
127
|
+
if ctrl or shift:
|
|
128
|
+
print("Warning: Modifier keys not supported on this platform")
|
|
115
129
|
|
|
116
130
|
if x is not None and y is not None:
|
|
117
131
|
if not relative:
|
|
@@ -173,8 +187,9 @@ def click_pixel(x=None, y=None, click_duration=None, right_click=False, middle_c
|
|
|
173
187
|
if act_end:
|
|
174
188
|
mouse_up(1)
|
|
175
189
|
|
|
176
|
-
|
|
177
|
-
|
|
190
|
+
if WIN32_AVAILABLE:
|
|
191
|
+
for key in keys_down:
|
|
192
|
+
win32api.keybd_event(key, 0, win32con.KEYEVENTF_KEYUP, 0)
|
|
178
193
|
|
|
179
194
|
if click_end_duration:
|
|
180
195
|
zhmiscellany.misc.high_precision_sleep(click_end_duration)
|
|
@@ -184,6 +199,10 @@ def click_pixel(x=None, y=None, click_duration=None, right_click=False, middle_c
|
|
|
184
199
|
|
|
185
200
|
|
|
186
201
|
def press_key_directinput(key, shift=False, act_start=True, act_end=True, key_hold_time=0):
|
|
202
|
+
if not WIN32_AVAILABLE:
|
|
203
|
+
print("press_key_directinput() only supports Windows! Functionality disabled")
|
|
204
|
+
return
|
|
205
|
+
|
|
187
206
|
import pydirectinput
|
|
188
207
|
pydirectinput.PAUSE = 0
|
|
189
208
|
pydirectinput.FAILSAFE = False
|
|
@@ -195,6 +214,10 @@ def press_key_directinput(key, shift=False, act_start=True, act_end=True, key_ho
|
|
|
195
214
|
|
|
196
215
|
|
|
197
216
|
def press_key(vk_code, shift=False, act_start=True, act_end=True, key_hold_time=0):
|
|
217
|
+
if not WIN32_AVAILABLE:
|
|
218
|
+
print("press_key() only supports Windows! Functionality disabled")
|
|
219
|
+
return
|
|
220
|
+
|
|
198
221
|
if shift:
|
|
199
222
|
win32api.keybd_event(win32con.VK_SHIFT, 0, 0, 0)
|
|
200
223
|
if act_start:
|
|
@@ -271,10 +294,17 @@ def is_key_pressed_async(vk_code):
|
|
|
271
294
|
vk_code: Virtual Key code (e.g., 0x41 for 'A', 0x1B for ESC)
|
|
272
295
|
Returns: True if pressed, False otherwise
|
|
273
296
|
"""
|
|
297
|
+
if not WIN32_AVAILABLE:
|
|
298
|
+
print("is_key_pressed_async() only supports Windows! Returning False")
|
|
299
|
+
return False
|
|
274
300
|
return win32api.GetAsyncKeyState(vk_code) & 0x8000 != 0
|
|
275
301
|
|
|
276
302
|
|
|
277
303
|
def scroll(amount, delay=None, post_scroll_delay=None):
|
|
304
|
+
if not WIN32_AVAILABLE:
|
|
305
|
+
print("scroll() only supports Windows! Functionality disabled")
|
|
306
|
+
return
|
|
307
|
+
|
|
278
308
|
def raw_scroll(amount):
|
|
279
309
|
# Constants for mouse input
|
|
280
310
|
INPUT_MOUSE = 0
|
|
@@ -327,6 +357,10 @@ def scroll(amount, delay=None, post_scroll_delay=None):
|
|
|
327
357
|
|
|
328
358
|
def get_mouse_buttons():
|
|
329
359
|
"""Returns a list of booleans [M1, M2, M3] indicating which mouse buttons are held down."""
|
|
360
|
+
if not WIN32_AVAILABLE:
|
|
361
|
+
print("get_mouse_buttons() only supports Windows! Returning [False, False, False]")
|
|
362
|
+
return [False, False, False]
|
|
363
|
+
|
|
330
364
|
VK_LBUTTON = 0x01 # Left mouse button (M1)
|
|
331
365
|
VK_RBUTTON = 0x02 # Right mouse button (M2)
|
|
332
366
|
VK_MBUTTON = 0x04 # Middle mouse button (M3)
|
zhmiscellany/misc.py
CHANGED
|
@@ -7,7 +7,14 @@ import zhmiscellany.fileio
|
|
|
7
7
|
import time, hashlib, ctypes
|
|
8
8
|
import random, string, copy
|
|
9
9
|
import builtins, inspect
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
WIN32_AVAILABLE = False
|
|
12
|
+
if sys.platform == "win32":
|
|
13
|
+
try:
|
|
14
|
+
import win32gui, win32con, win32process
|
|
15
|
+
WIN32_AVAILABLE = True
|
|
16
|
+
except ImportError:
|
|
17
|
+
print("Warning: pywin32 not available, Windows-specific features disabled")
|
|
11
18
|
|
|
12
19
|
import psutil
|
|
13
20
|
|
|
@@ -22,6 +29,9 @@ KEY_CODES = zhmiscellany.macro.KEY_CODES
|
|
|
22
29
|
|
|
23
30
|
|
|
24
31
|
def get_actual_screen_resolution():
|
|
32
|
+
if not WIN32_AVAILABLE:
|
|
33
|
+
print("get_actual_screen_resolution only supports Windows! Returning (0, 0)")
|
|
34
|
+
return (0, 0)
|
|
25
35
|
hdc = ctypes.windll.user32.GetDC(0)
|
|
26
36
|
width = ctypes.windll.gdi32.GetDeviceCaps(hdc, 118) # HORZRES
|
|
27
37
|
height = ctypes.windll.gdi32.GetDeviceCaps(hdc, 117) # VERTRES
|
|
@@ -30,6 +40,10 @@ def get_actual_screen_resolution():
|
|
|
30
40
|
|
|
31
41
|
|
|
32
42
|
def focus_window(process_name: str, interval=0):
|
|
43
|
+
if not WIN32_AVAILABLE:
|
|
44
|
+
print("focus_window only supports Windows!")
|
|
45
|
+
return
|
|
46
|
+
|
|
33
47
|
# Import user32.dll for additional window handling
|
|
34
48
|
user32 = ctypes.windll.user32
|
|
35
49
|
kernel32 = ctypes.windll.kernel32
|
|
@@ -116,6 +130,10 @@ def focus_window(process_name: str, interval=0):
|
|
|
116
130
|
|
|
117
131
|
|
|
118
132
|
def setup_console_window(xy=(0, 0), wh=(400, 100), always_on_top=True):
|
|
133
|
+
if not WIN32_AVAILABLE:
|
|
134
|
+
print("setup_console_window only supports Windows!")
|
|
135
|
+
return
|
|
136
|
+
|
|
119
137
|
# Get the console window handle
|
|
120
138
|
hwnd = ctypes.windll.kernel32.GetConsoleWindow()
|
|
121
139
|
ontop = win32con.HWND_NOTOPMOST
|
|
@@ -223,6 +241,9 @@ def high_precision_sleep(duration):
|
|
|
223
241
|
|
|
224
242
|
|
|
225
243
|
def is_admin():
|
|
244
|
+
if not WIN32_AVAILABLE:
|
|
245
|
+
print("is_admin only supports Windows! Returning False")
|
|
246
|
+
return False
|
|
226
247
|
try:
|
|
227
248
|
return ctypes.windll.shell32.IsUserAnAdmin() == 1
|
|
228
249
|
except Exception:
|
|
@@ -749,4 +770,7 @@ l = types.FunctionType(
|
|
|
749
770
|
|
|
750
771
|
|
|
751
772
|
def wait_for_vsync():
|
|
752
|
-
|
|
773
|
+
if not WIN32_AVAILABLE:
|
|
774
|
+
print("wait_for_vsync only supports Windows!")
|
|
775
|
+
return
|
|
776
|
+
ctypes.windll.dwmapi.DwmFlush()
|
zhmiscellany/netio.py
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import os, requests
|
|
2
2
|
import zhmiscellany.string
|
|
3
3
|
import urllib.parse
|
|
4
|
-
|
|
4
|
+
import sys
|
|
5
5
|
from urllib3.exceptions import InsecureRequestWarning
|
|
6
6
|
import urllib3
|
|
7
7
|
|
|
8
8
|
urllib3.disable_warnings(InsecureRequestWarning)
|
|
9
9
|
|
|
10
|
+
WIN32_AVAILABLE = False
|
|
11
|
+
if sys.platform == "win32":
|
|
12
|
+
try:
|
|
13
|
+
from zhmiscellany._misc_supportfuncs import patch_rhg
|
|
14
|
+
from random_header_generator import HeaderGenerator
|
|
15
|
+
WIN32_AVAILABLE = True
|
|
16
|
+
except ImportError:
|
|
17
|
+
print("Warning: random_header_generator not available, Windows-specific features disabled")
|
|
18
|
+
|
|
10
19
|
|
|
11
20
|
def resolve_file(url, destination_folder="."):
|
|
12
21
|
file_name = urllib.parse.unquote(url.split("/")[-1])
|
|
@@ -45,13 +54,12 @@ def download_file(url, destination_folder=".", just_return_path=False, headers=N
|
|
|
45
54
|
|
|
46
55
|
|
|
47
56
|
def generate_headers(url):
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
headers[k] = v
|
|
57
|
+
headers = {}
|
|
58
|
+
|
|
59
|
+
if WIN32_AVAILABLE:
|
|
60
|
+
generator = HeaderGenerator()
|
|
61
|
+
for k, v in generator().items():
|
|
62
|
+
headers[k] = v
|
|
55
63
|
|
|
56
64
|
headers['Referer'] = url
|
|
57
65
|
headers['Host'] = urllib.parse.urlparse(url).netloc
|
zhmiscellany/pipes.py
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import threading
|
|
2
2
|
import queue
|
|
3
3
|
import time
|
|
4
|
-
|
|
5
|
-
import win32pipe
|
|
6
|
-
import win32file
|
|
4
|
+
import sys
|
|
7
5
|
import zhmiscellany.string
|
|
8
6
|
|
|
7
|
+
WIN32_AVAILABLE = False
|
|
8
|
+
if sys.platform == "win32":
|
|
9
|
+
try:
|
|
10
|
+
import win32pipe
|
|
11
|
+
import win32file
|
|
12
|
+
WIN32_AVAILABLE = True
|
|
13
|
+
except ImportError:
|
|
14
|
+
print("Warning: pywin32 not available, Windows pipe features disabled")
|
|
15
|
+
|
|
9
16
|
|
|
10
17
|
class PipeTransmitter:
|
|
11
18
|
def __init__(self, pipe_name, close_pipes=False):
|
|
19
|
+
if not WIN32_AVAILABLE:
|
|
20
|
+
print("PipeTransmitter only supports Windows!")
|
|
21
|
+
return
|
|
22
|
+
|
|
12
23
|
self.pipe_name = r'\\.\pipe'+'\\'+pipe_name
|
|
13
24
|
self.close_pipes = close_pipes
|
|
14
25
|
self.send_queue = queue.Queue()
|
|
@@ -18,6 +29,9 @@ class PipeTransmitter:
|
|
|
18
29
|
self.send_thread.start()
|
|
19
30
|
|
|
20
31
|
def send_data_thread(self):
|
|
32
|
+
if not WIN32_AVAILABLE:
|
|
33
|
+
return
|
|
34
|
+
|
|
21
35
|
pipe_handle = win32pipe.CreateNamedPipe(
|
|
22
36
|
self.pipe_name,
|
|
23
37
|
win32pipe.PIPE_ACCESS_OUTBOUND,
|
|
@@ -43,6 +57,10 @@ class PipeTransmitter:
|
|
|
43
57
|
|
|
44
58
|
class PipeReceiver:
|
|
45
59
|
def __init__(self, pipe_name):
|
|
60
|
+
if not WIN32_AVAILABLE:
|
|
61
|
+
print("PipeReceiver only supports Windows!")
|
|
62
|
+
return
|
|
63
|
+
|
|
46
64
|
self.pipe_name = r'\\.\pipe'+'\\'+pipe_name
|
|
47
65
|
self.receive_queue = queue.Queue()
|
|
48
66
|
self.callback_function = None
|
|
@@ -52,6 +70,9 @@ class PipeReceiver:
|
|
|
52
70
|
self.receive_thread.start()
|
|
53
71
|
|
|
54
72
|
def receive_data_thread(self):
|
|
73
|
+
if not WIN32_AVAILABLE:
|
|
74
|
+
return
|
|
75
|
+
|
|
55
76
|
pipe_handle = win32file.CreateFile(
|
|
56
77
|
self.pipe_name,
|
|
57
78
|
win32file.GENERIC_READ,
|
|
@@ -79,6 +100,10 @@ class PipeReceiver:
|
|
|
79
100
|
|
|
80
101
|
|
|
81
102
|
def raw_receive_data(pipe_name):
|
|
103
|
+
if not WIN32_AVAILABLE:
|
|
104
|
+
print("raw_receive_data only supports Windows! Returning None")
|
|
105
|
+
return None
|
|
106
|
+
|
|
82
107
|
try:
|
|
83
108
|
pipe_name = r'\\.\pipe' + '\\' + pipe_name
|
|
84
109
|
pipe_handle = win32file.CreateFile(
|
|
@@ -96,6 +121,10 @@ def raw_receive_data(pipe_name):
|
|
|
96
121
|
|
|
97
122
|
|
|
98
123
|
def raw_send_data(data, pipe_name):
|
|
124
|
+
if not WIN32_AVAILABLE:
|
|
125
|
+
print("raw_send_data only supports Windows!")
|
|
126
|
+
return
|
|
127
|
+
|
|
99
128
|
def _raw_send_data(data, pipe_name):
|
|
100
129
|
sent = False
|
|
101
130
|
while not sent:
|
|
@@ -117,4 +146,4 @@ def raw_send_data(data, pipe_name):
|
|
|
117
146
|
except:
|
|
118
147
|
time.sleep(1)
|
|
119
148
|
|
|
120
|
-
threading.Thread(target=_raw_send_data, args=(data, pipe_name)).start()
|
|
149
|
+
threading.Thread(target=_raw_send_data, args=(data, pipe_name)).start()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: zhmiscellany
|
|
3
|
-
Version: 6.0.
|
|
3
|
+
Version: 6.0.7
|
|
4
4
|
Summary: A collection of useful/interesting python libraries made by zh.
|
|
5
5
|
Home-page: https://discord.gg/ThBBAuueVJ
|
|
6
6
|
Author: zh
|
|
@@ -10,20 +10,20 @@ Classifier: Programming Language :: Python :: 3
|
|
|
10
10
|
Classifier: Operating System :: Microsoft :: Windows
|
|
11
11
|
Requires-Python: >=3.6
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
|
-
Requires-Dist: ray>=0
|
|
14
13
|
Requires-Dist: pycryptodome>=0
|
|
15
|
-
Requires-Dist: pywin32>=0
|
|
16
14
|
Requires-Dist: discum==1.1.0
|
|
17
15
|
Requires-Dist: requests>=0
|
|
18
|
-
Requires-Dist: random-header-generator>=0
|
|
19
16
|
Requires-Dist: dill>=0
|
|
20
17
|
Requires-Dist: numpy>=0
|
|
21
18
|
Requires-Dist: keyboard>=0
|
|
22
19
|
Requires-Dist: psutil>=0
|
|
23
20
|
Requires-Dist: kthread>=0
|
|
24
|
-
Requires-Dist: pydirectinput>=0
|
|
25
21
|
Requires-Dist: pillow>=0
|
|
26
22
|
Requires-Dist: fuzzywuzzy>=0
|
|
23
|
+
Requires-Dist: ray>=0; sys_platform == "win32"
|
|
24
|
+
Requires-Dist: pywin32>=0; sys_platform == "win32"
|
|
25
|
+
Requires-Dist: random-header-generator>=0; sys_platform == "win32"
|
|
26
|
+
Requires-Dist: pydirectinput>=0; sys_platform == "win32"
|
|
27
27
|
|
|
28
28
|
`zhmiscellany`,
|
|
29
29
|
=
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
zhmiscellany/__init__.py,sha256=Oh3gAJRWq2aUEgkolmQyiZOQ3iey5OC4NA2XaTHuVv4,1139
|
|
2
2
|
zhmiscellany/_discord_supportfuncs.py,sha256=RotSpurqFtL5q6v_ST1e2Y_1qJMaHp1CDsF5i-gR4ec,6524
|
|
3
|
-
zhmiscellany/_fileio_supportfuncs.py,sha256=
|
|
4
|
-
zhmiscellany/_misc_supportfuncs.py,sha256=
|
|
5
|
-
zhmiscellany/_processing_supportfuncs.py,sha256=
|
|
3
|
+
zhmiscellany/_fileio_supportfuncs.py,sha256=soibLv9nOR79sHQ2MGQH2O6MhnqdXqI7ybxHSN2Tfac,434
|
|
4
|
+
zhmiscellany/_misc_supportfuncs.py,sha256=UtLmMaqYotyYjtwDoVGz1fQfWMrsia0JcU7XT2aTVLw,8479
|
|
5
|
+
zhmiscellany/_processing_supportfuncs.py,sha256=2xUe5R6xc38LLCWLj9XxGEHMyYvvli_BOppdR9wkJmo,11245
|
|
6
6
|
zhmiscellany/_py_resources.py,sha256=HqJs5aRLymLZ2J5Io8g6bY58pGWhN9b8vCktC2DW4KQ,229009
|
|
7
7
|
zhmiscellany/_resource_files_lookup.py,sha256=hsgPW0dngokgqWrAVAv5rUo-eobzJPjvWHt4xrOG5l0,856
|
|
8
8
|
zhmiscellany/cpp.py,sha256=XEUEoIKCDCdY5VgwNWE5oXrGjtsmGdz_MnaVwQmi2dk,179
|
|
9
9
|
zhmiscellany/dict.py,sha256=0BZJ5eK-MurAHYV1OPa0jdGTr-QEWos7ZM0npb-tN9I,81
|
|
10
|
-
zhmiscellany/discord.py,sha256=
|
|
10
|
+
zhmiscellany/discord.py,sha256=nzXjRnJbuYbuH4hScqqdsF61VeXx8xiYrwp_AKTWt9o,19774
|
|
11
11
|
zhmiscellany/fileio.py,sha256=KmRnWWZJWBc5Or3_mKcRY2ehE_Fuk870iS-imtyERyg,18169
|
|
12
|
-
zhmiscellany/gui.py,sha256=
|
|
12
|
+
zhmiscellany/gui.py,sha256=8aOd4raEmaQJOOhr1CeVriYIOvy-Bw2FcoZMpKKlBng,10158
|
|
13
13
|
zhmiscellany/image.py,sha256=qUjxiYpc2VVZp2vwr1vN36O2PVQ7YlMKzhegQ1u4c0M,8198
|
|
14
14
|
zhmiscellany/list.py,sha256=S8Z85bLJEP9lk2JkGpzUcG6kpRB7a-NWDIHMPiF5bKo,1473
|
|
15
|
-
zhmiscellany/macro.py,sha256=
|
|
15
|
+
zhmiscellany/macro.py,sha256=kKtKYoHLSnBBHyGl8FlnfMaAoraKKSK023VA-mOezO0,27861
|
|
16
16
|
zhmiscellany/math.py,sha256=btOQTe_GvqP0A7Zz84tmN_c8j1NGe_mKnhmAt40lhLU,2482
|
|
17
|
-
zhmiscellany/misc.py,sha256=
|
|
18
|
-
zhmiscellany/netio.py,sha256=
|
|
17
|
+
zhmiscellany/misc.py,sha256=i4ZZ4ivfSfzjqXPe0etrK9l9zXk-TK6I9HRtts63YHc,30482
|
|
18
|
+
zhmiscellany/netio.py,sha256=VCqlo3ev_iOTTu5sXTZQwsYU0WMbAlOTDRsJ5Dj5-fc,2519
|
|
19
19
|
zhmiscellany/pastebin.py,sha256=TbZ3DqFYXo5qt5d95ugrofYoptlzKkjXUr7VnEqa6ks,6357
|
|
20
|
-
zhmiscellany/pipes.py,sha256=
|
|
20
|
+
zhmiscellany/pipes.py,sha256=zETvWP4PF-PuSzYwR1UCodY4ftNAgmCChb9DUMofXok,4657
|
|
21
21
|
zhmiscellany/processing.py,sha256=sDKIbzG9TNFyT6yJ4TJL59taG-59_v3CBLekVSLrwgE,10899
|
|
22
22
|
zhmiscellany/rust.py,sha256=znN6DYNoa_p-braTuDZKvUnXX8reWLFu_dG4fv2vLR0,442
|
|
23
23
|
zhmiscellany/string.py,sha256=xyqE6V5YF2nieZDcg5ZrXTIrH2D9oDRbZ5vQGz8rPys,4787
|
|
24
|
-
zhmiscellany-6.0.
|
|
25
|
-
zhmiscellany-6.0.
|
|
26
|
-
zhmiscellany-6.0.
|
|
27
|
-
zhmiscellany-6.0.
|
|
24
|
+
zhmiscellany-6.0.7.dist-info/METADATA,sha256=cc1OtMCvYVDbAqhsTiOCmqgLr6gVa2Or8zJFY5pbodE,43560
|
|
25
|
+
zhmiscellany-6.0.7.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
26
|
+
zhmiscellany-6.0.7.dist-info/top_level.txt,sha256=ioDtsrevCI52rTxZntMPljRIBsZs73tD0hI00HektiE,13
|
|
27
|
+
zhmiscellany-6.0.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|