ascript 1.3.27__py3-none-win_amd64.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.
Files changed (177) hide show
  1. ascript/__init__.py +8 -0
  2. ascript/hooks/__init__.py +0 -0
  3. ascript/hooks/hook-ascript.py +2 -0
  4. ascript/windows/__init__.py +29 -0
  5. ascript/windows/daos/__init__.py +0 -0
  6. ascript/windows/daos/screen.py +143 -0
  7. ascript/windows/hardware/__init__.py +5 -0
  8. ascript/windows/hardware/keyboard.py +279 -0
  9. ascript/windows/hardware/logitech_driver.py +179 -0
  10. ascript/windows/hardware/mouse.py +308 -0
  11. ascript/windows/license/__init__.py +16 -0
  12. ascript/windows/license/achttp.cp310-win_amd64.pyd +0 -0
  13. ascript/windows/license/achttp.cp311-win_amd64.pyd +0 -0
  14. ascript/windows/license/achttp.cp312-win_amd64.pyd +0 -0
  15. ascript/windows/license/achttp.cp313-win_amd64.pyd +0 -0
  16. ascript/windows/license/achttp.cp314-win_amd64.pyd +0 -0
  17. ascript/windows/license/achttp.cp38-win_amd64.pyd +0 -0
  18. ascript/windows/license/achttp.cp39-win_amd64.pyd +0 -0
  19. ascript/windows/media/__init__.py +0 -0
  20. ascript/windows/resources/__init__.py +0 -0
  21. ascript/windows/resources/libs/logitech/x64/LogitechGkeyEnginesWrapper.dll +0 -0
  22. ascript/windows/resources/libs/logitech/x86/LogitechGkeyEnginesWrapper.dll +0 -0
  23. ascript/windows/resources/templates/__init__.py +0 -0
  24. ascript/windows/resources/templates/__init__py.win.template +51 -0
  25. ascript/windows/resources/templates/build.as.win.template +14 -0
  26. ascript/windows/resources/templates/build.py +71 -0
  27. ascript/windows/resources/templates/logo_windows.ico +0 -0
  28. ascript/windows/resources/templates/windows/main.py +50 -0
  29. ascript/windows/resources/templates/windows/pyproject.toml +44 -0
  30. ascript/windows/resources/templates/windows/res/img/logo.ico +0 -0
  31. ascript/windows/screen/__init__.py +13 -0
  32. ascript/windows/screen/as_cv.py +382 -0
  33. ascript/windows/screen/canny.py +128 -0
  34. ascript/windows/screen/code_scanner.py +72 -0
  35. ascript/windows/screen/color_algorithms.py +277 -0
  36. ascript/windows/screen/find_colors.py +251 -0
  37. ascript/windows/screen/find_images.py +217 -0
  38. ascript/windows/screen/ocr/__init__.py +4 -0
  39. ascript/windows/screen/ocr/ocr.py +223 -0
  40. ascript/windows/screen/ocr/rapidocr_hook.py +301 -0
  41. ascript/windows/screen/ocrx.py +169 -0
  42. ascript/windows/screen/screen_core.py +139 -0
  43. ascript/windows/store/__init__.py +21 -0
  44. ascript/windows/system/__init__.py +8 -0
  45. ascript/windows/system/device.py +355 -0
  46. ascript/windows/system/easy_print.py +115 -0
  47. ascript/windows/system/env.py +492 -0
  48. ascript/windows/system/exception/__init__.py +1 -0
  49. ascript/windows/system/key_value.py +145 -0
  50. ascript/windows/system/pip.py +175 -0
  51. ascript/windows/system/r.py +165 -0
  52. ascript/windows/system/runtime.py +62 -0
  53. ascript/windows/tools/__init__.py +27 -0
  54. ascript/windows/tools/__main__.py +21 -0
  55. ascript/windows/tools/action.json +33 -0
  56. ascript/windows/tools/action.py +168 -0
  57. ascript/windows/tools/colors_tool.py +391 -0
  58. ascript/windows/tools/config.py +26 -0
  59. ascript/windows/tools/dumptool.py +18 -0
  60. ascript/windows/tools/eel_api.py +495 -0
  61. ascript/windows/tools/gpplug/__init__.py +0 -0
  62. ascript/windows/tools/gpplug/plug.py +70 -0
  63. ascript/windows/tools/mouse_catch.py +168 -0
  64. ascript/windows/tools/plug_manager.py +38 -0
  65. ascript/windows/tools/tool_api.py +906 -0
  66. ascript/windows/tools/tool_window.py +56 -0
  67. ascript/windows/tools/uia_worker.py +365 -0
  68. ascript/windows/tools/web/app_store_window.html +481 -0
  69. ascript/windows/tools/web/colors.html +532 -0
  70. ascript/windows/tools/web/css/screen.css +1342 -0
  71. ascript/windows/tools/web/css/viewtree.css +357 -0
  72. ascript/windows/tools/web/flot_control.html +195 -0
  73. ascript/windows/tools/web/img/ico/favicon.png +0 -0
  74. ascript/windows/tools/web/img/ico/paintpalette.png +0 -0
  75. ascript/windows/tools/web/img/svg/find_colors.svg +1 -0
  76. ascript/windows/tools/web/img/svg/find_images.svg +1 -0
  77. ascript/windows/tools/web/img/svg/illustration-6.svg +89 -0
  78. ascript/windows/tools/web/img/svg/img_default.svg +1 -0
  79. ascript/windows/tools/web/img/svg/ocr.svg +1 -0
  80. ascript/windows/tools/web/js/screen/colors.js +466 -0
  81. ascript/windows/tools/web/js/screen/gp_plug.js +108 -0
  82. ascript/windows/tools/web/js/screen/image_mouse.js +464 -0
  83. ascript/windows/tools/web/js/screen/img_view.js +558 -0
  84. ascript/windows/tools/web/js/screen/plug.js +246 -0
  85. ascript/windows/tools/web/js/screen/screen.js +690 -0
  86. ascript/windows/tools/web/js/screen/screen_api.js +778 -0
  87. ascript/windows/tools/web/js/screen/screen_maker.js +10 -0
  88. ascript/windows/tools/web/js/utils/map.js +73 -0
  89. ascript/windows/tools/web/js/utils/upload.js +157 -0
  90. ascript/windows/tools/web/js/viewtree/niv_js.js +27 -0
  91. ascript/windows/tools/web/js/viewtree/vtree.js +1510 -0
  92. ascript/windows/tools/web/libs/bootstrap/css/bootstrap.min.css +6 -0
  93. ascript/windows/tools/web/libs/bootstrap/js/bootstrap.bundle.min.js +7 -0
  94. ascript/windows/tools/web/libs/bootstrap-icons/0-circle.svg +4 -0
  95. ascript/windows/tools/web/libs/bootstrap-icons/0-square.svg +4 -0
  96. ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.css +2078 -0
  97. ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.json +2052 -0
  98. ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.min.css +5 -0
  99. ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.scss +2090 -0
  100. ascript/windows/tools/web/libs/bootstrap-icons/font/fonts/bootstrap-icons.woff +0 -0
  101. ascript/windows/tools/web/libs/bootstrap-icons/font/fonts/bootstrap-icons.woff2 +0 -0
  102. ascript/windows/tools/web/libs/feather-icons/dist/feather.min.js +13 -0
  103. ascript/windows/tools/web/libs/feather-icons/dist/icons.json +1 -0
  104. ascript/windows/tools/web/libs/jquery/core.js +399 -0
  105. ascript/windows/tools/web/libs/jquery/jquery.js +10598 -0
  106. ascript/windows/tools/web/libs/jquery/jquery.min.js +4 -0
  107. ascript/windows/tools/web/libs/jquery/jquery.min.js.zip +0 -0
  108. ascript/windows/tools/web/libs/jquery/jquery.slim.js +8495 -0
  109. ascript/windows/tools/web/libs/jquery/jquery.slim.min.js +2 -0
  110. ascript/windows/tools/web/libs/jquery-menu/jquery.contextMenu.js +2134 -0
  111. ascript/windows/tools/web/libs/jquery-menu/jquery.contextMenu.min.css +16 -0
  112. ascript/windows/tools/web/libs/jquery-zTree/css/zTreeStyle.css +97 -0
  113. ascript/windows/tools/web/libs/jquery-zTree/img/diy/1_close.png +0 -0
  114. ascript/windows/tools/web/libs/jquery-zTree/img/diy/1_open.png +0 -0
  115. ascript/windows/tools/web/libs/jquery-zTree/img/diy/2.png +0 -0
  116. ascript/windows/tools/web/libs/jquery-zTree/img/diy/3.png +0 -0
  117. ascript/windows/tools/web/libs/jquery-zTree/img/diy/4.png +0 -0
  118. ascript/windows/tools/web/libs/jquery-zTree/img/diy/5.png +0 -0
  119. ascript/windows/tools/web/libs/jquery-zTree/img/diy/6.png +0 -0
  120. ascript/windows/tools/web/libs/jquery-zTree/img/diy/7.png +0 -0
  121. ascript/windows/tools/web/libs/jquery-zTree/img/diy/8.png +0 -0
  122. ascript/windows/tools/web/libs/jquery-zTree/img/diy/9.png +0 -0
  123. ascript/windows/tools/web/libs/jquery-zTree/img/line_conn.gif +0 -0
  124. ascript/windows/tools/web/libs/jquery-zTree/img/loading.gif +0 -0
  125. ascript/windows/tools/web/libs/jquery-zTree/img/tree-node-btn.png +0 -0
  126. ascript/windows/tools/web/libs/jquery-zTree/img/zTreeStandard.gif +0 -0
  127. ascript/windows/tools/web/libs/jquery-zTree/img/zTreeStandard.png +0 -0
  128. ascript/windows/tools/web/libs/jquery-zTree/js/jquery.ztree.all.min.js +3 -0
  129. ascript/windows/tools/web/libs/treeview/css/jquery.treeview.css +79 -0
  130. ascript/windows/tools/web/libs/treeview/img/file.png +0 -0
  131. ascript/windows/tools/web/libs/treeview/img/ico_loading.png +0 -0
  132. ascript/windows/tools/web/libs/treeview/img/icon4.png +0 -0
  133. ascript/windows/tools/web/libs/treeview/img/icon5.png +0 -0
  134. ascript/windows/tools/web/libs/treeview/img/icon6.png +0 -0
  135. ascript/windows/tools/web/libs/treeview/img/py.png +0 -0
  136. ascript/windows/tools/web/libs/treeview/img/treeview-black-line.gif +0 -0
  137. ascript/windows/tools/web/libs/treeview/img/treeview-black.gif +0 -0
  138. ascript/windows/tools/web/libs/treeview/img/treeview-default-line.gif +0 -0
  139. ascript/windows/tools/web/libs/treeview/img/treeview-default.gif +0 -0
  140. ascript/windows/tools/web/libs/treeview/img/treeview-famfamfam-line.gif +0 -0
  141. ascript/windows/tools/web/libs/treeview/img/treeview-famfamfam.gif +0 -0
  142. ascript/windows/tools/web/libs/treeview/img/treeview-gray-line.gif +0 -0
  143. ascript/windows/tools/web/libs/treeview/img/treeview-gray.gif +0 -0
  144. ascript/windows/tools/web/libs/treeview/img/treeview-red-line.gif +0 -0
  145. ascript/windows/tools/web/libs/treeview/img/treeview-red.gif +0 -0
  146. ascript/windows/tools/web/libs/treeview/js/jquery.treeview.edit.js +37 -0
  147. ascript/windows/tools/web/libs/treeview/js/jquery.treeview.js +250 -0
  148. ascript/windows/tools/web/license_window.html +255 -0
  149. ascript/windows/tools/web/plugs/a.html +653 -0
  150. ascript/windows/tools/web/plugs/demo.html +52 -0
  151. ascript/windows/tools/web/plugs/find_colors.html +629 -0
  152. ascript/windows/tools/web/plugs/find_images.html +699 -0
  153. ascript/windows/tools/web/plugs/rapidocr.html +954 -0
  154. ascript/windows/tools/web/vtree.html +496 -0
  155. ascript/windows/tools/webview/assets/index-HymBPl-I.css +1 -0
  156. ascript/windows/tools/webview/assets/index-PqA_m8tL.js +17 -0
  157. ascript/windows/tools/webview/index.html +13 -0
  158. ascript/windows/ui/__init__.py +6 -0
  159. ascript/windows/ui/app_store_window.py +272 -0
  160. ascript/windows/ui/draw_window.py +231 -0
  161. ascript/windows/ui/flot_test.py +297 -0
  162. ascript/windows/ui/flot_window.py +488 -0
  163. ascript/windows/ui/license_window.py +111 -0
  164. ascript/windows/ui/web_window.py +466 -0
  165. ascript/windows/utils/__init__.py +0 -0
  166. ascript/windows/utils/node_utils.py +20 -0
  167. ascript/windows/utils/screen_utils.py +280 -0
  168. ascript/windows/window/Selector.py +1015 -0
  169. ascript/windows/window/Window.py +747 -0
  170. ascript/windows/window/__init__.py +5 -0
  171. ascript/windows/window/launcher.py +213 -0
  172. ascript/windows/window/uia_runtime.py +26 -0
  173. ascript-1.3.27.dist-info/METADATA +41 -0
  174. ascript-1.3.27.dist-info/RECORD +177 -0
  175. ascript-1.3.27.dist-info/WHEEL +5 -0
  176. ascript-1.3.27.dist-info/entry_points.txt +2 -0
  177. ascript-1.3.27.dist-info/top_level.txt +1 -0
@@ -0,0 +1,391 @@
1
+ import sys
2
+ import eel
3
+
4
+ from ..system import R
5
+ from . import eel_api, config,plug_manager
6
+ from ..window import Window
7
+ from ..screen import Screen
8
+ import time
9
+ import ctypes
10
+ import threading
11
+ import bottle
12
+ import socket
13
+
14
+ from ..ui.web_window import WebWindow
15
+
16
+
17
+ _colors_web_window = None
18
+ _screenshot_lock = threading.Lock()
19
+
20
+
21
+ @eel.expose
22
+ def colors_tool_screenshot(hwnd):
23
+ """截取屏幕或指定窗口的截图,返回 base64 编码的图像数据。
24
+
25
+ 如果提供了窗口句柄,则截取该窗口;否则截取全屏。
26
+ 图色助手窗口由 Windows WDA_EXCLUDEFROMCAPTURE 排除,不需要最小化、
27
+ 隐藏或重新激活窗口,因此不会打断 WebView2 的焦点和合成状态。
28
+
29
+ Args:
30
+ hwnd: 目标窗口句柄。为 None 或空值时截取全屏。
31
+
32
+ Returns:
33
+ dict: 包含以下字段的字典:
34
+ - status (str): "success" 或 "error"
35
+ - data (str): base64 编码的图像数据
36
+ - save_info (dict): 保存信息,含 status 和 path
37
+ - message (str): 错误信息(如有)
38
+ """
39
+ if not _screenshot_lock.acquire(blocking=False):
40
+ return {
41
+ "status": "error",
42
+ "data": "",
43
+ "save_info": {"status": "error", "path": None},
44
+ "message": "已有截图任务正在执行,请稍后重试",
45
+ }
46
+
47
+ started_at = time.perf_counter()
48
+ my_file_temp = os.path.join(
49
+ config.file_capture_dir, str(int(time.time() * 1000)) + ".jpeg"
50
+ )
51
+ try:
52
+ print(
53
+ f"[colors] screenshot start hwnd={hwnd!r} path={my_file_temp}",
54
+ flush=True,
55
+ )
56
+ if hwnd:
57
+ result = eel_api.get_screenshot(
58
+ hwnd, my_file_temp, include_data=False
59
+ )
60
+ else:
61
+ image = Screen.capture(save_path=my_file_temp, format="pillow")
62
+ if image is None:
63
+ result = {
64
+ "status": "error",
65
+ "data": "",
66
+ "save_info": {"status": "error", "path": my_file_temp},
67
+ "message": "全屏截图失败",
68
+ }
69
+ else:
70
+ result = {
71
+ "status": "success",
72
+ "data": "",
73
+ "save_info": {"status": "success", "path": my_file_temp},
74
+ "message": "",
75
+ }
76
+ print(
77
+ f"[colors] screenshot done status={result.get('status')} "
78
+ f"elapsed={time.perf_counter() - started_at:.3f}s",
79
+ flush=True,
80
+ )
81
+ return result
82
+ except Exception as error:
83
+ print(f"[colors] screenshot error: {error!r}", flush=True)
84
+ return {
85
+ "status": "error",
86
+ "data": "",
87
+ "save_info": {"status": "error", "path": my_file_temp},
88
+ "message": f"截图失败: {error}",
89
+ }
90
+ finally:
91
+ _screenshot_lock.release()
92
+
93
+
94
+ import os
95
+ import base64
96
+ import io
97
+ from PIL import Image
98
+
99
+
100
+ @eel.expose
101
+ def ascript_get_image(file_path: str, max_side_size: int = 0):
102
+ """读取指定路径的图片,可选缩放后以 base64 格式返回。
103
+
104
+ 支持相对路径和绝对路径。相对路径会自动拼接截图目录。
105
+ 图片统一转为 RGB 模式输出 JPEG 格式。
106
+
107
+ Args:
108
+ file_path: 图片完整路径或文件名。若为相对路径,则从截图目录读取。
109
+ max_side_size: 缩放限制(像素)。0 表示不缩放;大于 0 则将长边限制在该像素内。
110
+
111
+ Returns:
112
+ dict: 包含以下字段的字典:
113
+ - status (str): "success" 或 "error"
114
+ - message (str): 操作结果描述
115
+ - data (str): base64 编码的图像数据(data URI 格式),失败时为空字符串
116
+ """
117
+ try:
118
+ # 1. 路径兼容性处理
119
+ if not os.path.isabs(file_path):
120
+ file_path = os.path.join(config.file_capture_dir, os.path.basename(file_path))
121
+
122
+ # 2. 检查文件是否存在
123
+ if not os.path.exists(file_path):
124
+ return {"status": "error", "message": f"找不到文件: {file_path}", "data": ""}
125
+
126
+ # 3. 处理图片
127
+ with Image.open(file_path) as img:
128
+ # 统一转为 RGB 模式以兼容 JPEG 格式
129
+ if img.mode != 'RGB':
130
+ img = img.convert('RGB')
131
+
132
+ img_byte_arr = io.BytesIO()
133
+
134
+ # 判断是否需要缩放
135
+ if max_side_size > 0:
136
+ # 使用 thumbnail 会保持宽高比,且仅在原图大于目标尺寸时缩小
137
+ img.thumbnail((max_side_size, max_side_size), Image.Resampling.LANCZOS)
138
+ # 缩略图可以使用较低的质量来节省空间
139
+ img.save(img_byte_arr, format='JPEG', quality=70, optimize=True)
140
+ else:
141
+ # 不缩放时,尽可能保持高质量输出
142
+ img.save(img_byte_arr, format='JPEG', quality=95)
143
+
144
+ img_data = img_byte_arr.getvalue()
145
+ img_base64 = base64.b64encode(img_data).decode()
146
+
147
+ return {
148
+ "status": "success",
149
+ "message": "读取成功" + ("并缩放" if max_side_size > 0 else ""),
150
+ "data": f"data:image/jpeg;base64,{img_base64}"
151
+ }
152
+
153
+ except Exception as e:
154
+ print(f"读取图片异常: {e}")
155
+ return {"status": "error", "message": str(e), "data": ""}
156
+
157
+
158
+
159
+
160
+
161
+
162
+
163
+ @eel.expose
164
+ def colors_tool_screenshot_files():
165
+ """获取截图目录下所有图片文件的绝对路径列表。
166
+
167
+ 扫描截图目录中的图片文件(支持 png、jpg、jpeg、bmp、gif 格式),
168
+ 按修改时间从新到旧排序返回。
169
+
170
+ Returns:
171
+ dict: 包含以下字段的字典:
172
+ - status (str): "success" 或 "error"
173
+ - message (str): 操作结果描述
174
+ - data (list): 图片文件绝对路径列表
175
+ - path (str): 截图目录路径(仅成功时包含)
176
+ """
177
+ try:
178
+ # 1. 获取配置中的目录路径
179
+ target_dir = config.file_capture_dir
180
+
181
+ # 2. 检查目录是否存在
182
+ if not os.path.exists(target_dir):
183
+ return {
184
+ "status": "success",
185
+ "message": "目录不存在",
186
+ "data": []
187
+ }
188
+
189
+ # 3. 定义支持的图片后缀名
190
+ valid_extensions = ('.png', '.jpg', '.jpeg', '.bmp', '.gif')
191
+
192
+ # 4. 获取目录下所有符合条件的文件,并转换为绝对路径
193
+ file_paths = []
194
+ for f in os.listdir(target_dir):
195
+ if f.lower().endswith(valid_extensions):
196
+ # 拼接成绝对路径
197
+ full_path = os.path.abspath(os.path.join(target_dir, f))
198
+ file_paths.append(full_path)
199
+
200
+ # 5. 排序:按文件修改时间从新到旧排列
201
+ # 注意:这里使用 os.path.getmtime 直接对绝对路径进行操作
202
+ file_paths.sort(key=lambda x: os.path.getmtime(x), reverse=True)
203
+
204
+ return {
205
+ "status": "success",
206
+ "message": f"成功获取 {len(file_paths)} 个文件路径",
207
+ "data": file_paths, # 现在的 data 里面是完整的绝对路径列表
208
+ "path": target_dir
209
+ }
210
+
211
+ except Exception as e:
212
+ print(f"获取图片路径列表失败: {e}")
213
+ return {
214
+ "status": "error",
215
+ "message": str(e),
216
+ "data": []
217
+ }
218
+
219
+ @eel.expose
220
+ def save_dropped_image(base64_str, filename):
221
+ """将前端拖拽上传的 base64 图片保存到截图目录。
222
+
223
+ 自动在文件名中添加时间戳以避免重名冲突。
224
+
225
+ Args:
226
+ base64_str: base64 编码的图片数据,支持 data URI 格式(如 "data:image/png;base64,...")。
227
+ filename: 原始文件名,用于保留文件扩展名。
228
+
229
+ Returns:
230
+ dict: 包含以下字段的字典:
231
+ - status (str): "success" 或 "error"
232
+ - path (str): 保存后的文件绝对路径(仅成功时包含)
233
+ - message (str): 错误信息(仅失败时包含)
234
+ """
235
+ try:
236
+ # 提取 base64 数据部分
237
+ # 格式通常为: "data:image/png;base64,iVBOR..."
238
+ if "," in base64_str:
239
+ base64_str = base64_str.split(",")[1]
240
+
241
+ img_data = base64.b64decode(base64_str)
242
+
243
+ # 为了防止文件名重复,加上时间戳
244
+ name, ext = os.path.splitext(filename)
245
+ save_name = f"{name}_{int(time.time())}{ext}"
246
+ save_path = os.path.abspath(os.path.join(config.file_capture_dir, save_name))
247
+
248
+ with open(save_path, "wb") as f:
249
+ f.write(img_data)
250
+
251
+ return {"status": "success", "path": save_path}
252
+ except Exception as e:
253
+ return {"status": "error", "message": str(e)}
254
+
255
+
256
+ # 1. 定义一个触发函数
257
+ def listen_win32_hotkey():
258
+ """监听 Win32 全局热键(Shift+S)并触发前端截图。
259
+
260
+ 注册 Shift+S 全局热键,当热键被按下时调用前端 JS 函数
261
+ triggerScreenshotUI() 触发截图操作。该函数应在独立线程中运行。
262
+ """
263
+ user32 = ctypes.windll.user32
264
+
265
+ HOTKEY_ID = 101
266
+
267
+ # 修改这里:使用 MOD_SHIFT (0x0004)
268
+ MOD_SHIFT = 0x0004
269
+ # 如果你想用 Ctrl + Shift + S,就写:MOD_CTRL_SHIFT = 0x0002 | 0x0004
270
+
271
+ VK_S = 0x53 # 'S' 键的虚拟键码
272
+
273
+ # 注册热键
274
+ if not user32.RegisterHotKey(None, HOTKEY_ID, MOD_SHIFT, VK_S):
275
+ print("❌ 无法注册 Shift + S,可能被占用")
276
+ return
277
+
278
+ # print("✅ 成功注册热键: Shift + S")
279
+
280
+ try:
281
+ msg = ctypes.wintypes.MSG()
282
+ while user32.GetMessageW(ctypes.byref(msg), None, 0, 0) != 0:
283
+ if msg.message == 0x0312: # WM_HOTKEY
284
+ # 触发 JS 截图逻辑
285
+ eel.triggerScreenshotUI()
286
+ user32.TranslateMessage(ctypes.byref(msg))
287
+ user32.DispatchMessageW(ctypes.byref(msg))
288
+ finally:
289
+ user32.UnregisterHotKey(None, HOTKEY_ID)
290
+
291
+
292
+ # 启动线程
293
+ from urllib.parse import unquote # 必须导入这个
294
+ @eel.btl.route('/external/<base64_path>/<filename:path>')
295
+ def server_external(base64_path, filename):
296
+ """提供外部文件的静态资源服务路由。
297
+
298
+ 通过 base64 编码的物理路径定位文件根目录,支持中文路径和 URL 编码。
299
+ 用于在 Eel Web 应用中访问本地文件系统中的图片等资源。
300
+
301
+ Args:
302
+ base64_path: base64 编码的物理目录路径(可能经过 URL 编码)。
303
+ filename: 相对于根目录的文件名路径。
304
+
305
+ Returns:
306
+ bottle.Response: 静态文件响应,或 500 错误响应。
307
+ """
308
+ try:
309
+ # 1. 先把 URL 里的 %2F 等符号转回正常字符
310
+ clean_base64 = unquote(base64_path)
311
+
312
+ # 2. Base64 解码并处理可能的中文编码
313
+ # 注意:这里增加 try-except 或直接解码
314
+ raw_path = base64.b64decode(clean_base64).decode('utf-8')
315
+
316
+ # 3. 再次 unquote 物理路径(因为 JS 端用了 encodeURIComponent)
317
+ actual_root = unquote(raw_path)
318
+
319
+ print(f"请求文件: {filename} | 物理根目录: {actual_root}") # 调试用
320
+
321
+ return bottle.static_file(filename, root=actual_root)
322
+ except Exception as e:
323
+ print(f"路径解析失败: {e}")
324
+ return bottle.HTTPError(500, f"Path Error: {str(e)}")
325
+
326
+ def start_colors(hwnd:str = None,window_title:str = None):
327
+ """启动图形处理(颜色工具)Web 应用。
328
+
329
+ 初始化 Eel 框架并打开颜色工具页面,支持通过窗口句柄或窗口标题
330
+ 指定目标窗口。自动检测可用浏览器(Chrome/Edge)。
331
+
332
+ Args:
333
+ hwnd: 目标窗口句柄字符串。优先级高于 window_title。
334
+ window_title: 目标窗口标题,用于自动查找窗口句柄。
335
+ """
336
+
337
+ if window_title:
338
+ temp_window = Window.find(window_title)
339
+ if temp_window:
340
+ hwnd = temp_window.hwnd
341
+
342
+ web_root = R.internal("windows", "tools", "web")
343
+ eel.init(web_root)
344
+
345
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as port_socket:
346
+ port_socket.bind(("127.0.0.1", 0))
347
+ port = port_socket.getsockname()[1]
348
+
349
+ server_error = []
350
+
351
+ def run_server():
352
+ try:
353
+ eel.start(
354
+ "colors.html",
355
+ mode=False,
356
+ host="127.0.0.1",
357
+ port=port,
358
+ block=True,
359
+ suppress_error=True,
360
+ )
361
+ except Exception as exc:
362
+ server_error.append(exc)
363
+
364
+ threading.Thread(target=run_server, daemon=True).start()
365
+
366
+ for _ in range(100):
367
+ if server_error:
368
+ raise RuntimeError(f"图色工具服务启动失败: {server_error[0]}")
369
+ try:
370
+ with socket.create_connection(("127.0.0.1", port), timeout=0.1):
371
+ break
372
+ except OSError:
373
+ time.sleep(0.05)
374
+ else:
375
+ raise RuntimeError("图色工具服务启动超时")
376
+
377
+ threading.Thread(target=listen_win32_hotkey, daemon=True).start()
378
+ global _colors_web_window
379
+ _colors_web_window = WebWindow(f"http://127.0.0.1:{port}/colors.html")
380
+ try:
381
+ return _colors_web_window.show(
382
+ title="图形处理 AScript",
383
+ width=1280,
384
+ height=820,
385
+ min_size=(980, 640),
386
+ background_color="#171a1c",
387
+ bring_to_front=True,
388
+ exclude_from_capture=True,
389
+ )
390
+ finally:
391
+ _colors_web_window = None
@@ -0,0 +1,26 @@
1
+ """工具模块配置文件。
2
+
3
+ 定义工具运行所需的临时目录路径(截图目录、临时数据目录),
4
+ 并在模块加载时自动创建所需的目录结构。
5
+
6
+ 模块属性:
7
+ file_root_path (str): 临时文件根目录,位于系统临时目录下的 ascript 子目录。
8
+ file_capture_dir (str): 截图保存目录。
9
+ file_data_temp (str): 临时数据目录。
10
+ """
11
+
12
+ import os
13
+ import tempfile
14
+
15
+ # 1. 定义路径
16
+ file_root_path = os.path.join(tempfile.gettempdir(), "ascript")
17
+ file_capture_dir = os.path.join(file_root_path, "capture")
18
+ file_data_temp = os.path.join(file_root_path, "temp")
19
+
20
+ # 2. 判断并创建文件夹
21
+ # 创建根目录及其子目录
22
+ # os.makedirs 会自动创建中间路径(递归创建)
23
+ os.makedirs(file_capture_dir, exist_ok=True)
24
+ os.makedirs(file_data_temp, exist_ok=True)
25
+
26
+ # print(f"路径已就绪: {file_capture_dir}")
@@ -0,0 +1,18 @@
1
+ from .tool_window import start_inspector
2
+
3
+ def start_vtree(hwnd: str = None, window_title: str = None):
4
+ """启动 UI 元素树(VTree)查看器 Web 应用。
5
+
6
+ 初始化 Eel 框架并打开 VTree 页面,用于查看和分析目标窗口的 UI 元素层级结构。
7
+ 支持通过窗口句柄或窗口标题指定目标窗口。自动检测可用浏览器(Chrome/Edge)。
8
+
9
+ Args:
10
+ hwnd: 目标窗口句柄字符串。优先级高于 window_title。
11
+ window_title: 目标窗口标题,用于自动查找窗口句柄。
12
+ """
13
+ if window_title:
14
+ from ..window import Window
15
+ temp_window = Window.find(window_title)
16
+ if temp_window:
17
+ hwnd = temp_window.hwnd
18
+ return start_inspector(hwnd=hwnd)