autoxkit 2.4.4__tar.gz → 2.4.8__tar.gz

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 (35) hide show
  1. {autoxkit-2.4.4 → autoxkit-2.4.8}/PKG-INFO +1 -7
  2. {autoxkit-2.4.4 → autoxkit-2.4.8}/README.md +0 -6
  3. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/hook/event.py +4 -2
  4. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/hook/hook_listener.py +4 -24
  5. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/mousekey/mouse.py +15 -3
  6. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/window/window_match.py +18 -8
  7. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit.egg-info/PKG-INFO +1 -7
  8. {autoxkit-2.4.4 → autoxkit-2.4.8}/pyproject.toml +1 -1
  9. {autoxkit-2.4.4 → autoxkit-2.4.8}/LICENSE.txt +0 -0
  10. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/__init__.py +0 -0
  11. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/android/__init__.py +0 -0
  12. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/android/adb.py +0 -0
  13. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/android/binary.py +0 -0
  14. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/android/client.py +0 -0
  15. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/android/control.py +0 -0
  16. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/android/control_backup.py +0 -0
  17. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/android/models.py +0 -0
  18. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/android/streams.py +0 -0
  19. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/constants.py +0 -0
  20. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/hook/__init__.py +0 -0
  21. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/hook/hotkey_listener.py +0 -0
  22. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/match/__init__.py +0 -0
  23. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/match/match.py +0 -0
  24. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/mousekey/__init__.py +0 -0
  25. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/mousekey/input.py +0 -0
  26. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/mousekey/keyboard.py +0 -0
  27. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/utils.py +0 -0
  28. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/window/__init__.py +0 -0
  29. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/window/window.py +0 -0
  30. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit/window/window_action.py +0 -0
  31. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit.egg-info/SOURCES.txt +0 -0
  32. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit.egg-info/dependency_links.txt +0 -0
  33. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit.egg-info/requires.txt +0 -0
  34. {autoxkit-2.4.4 → autoxkit-2.4.8}/autoxkit.egg-info/top_level.txt +0 -0
  35. {autoxkit-2.4.4 → autoxkit-2.4.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autoxkit
3
- Version: 2.4.4
3
+ Version: 2.4.8
4
4
  Summary: Python library for Windows automation and Android device screen casting and control
5
5
  Author-email: YorickFin <1582456060@qq.com>
6
6
  License: GPL-3.0-or-later
@@ -91,17 +91,11 @@ def mouse_up(event: MouseEvent):
91
91
  return False
92
92
 
93
93
 
94
- def mouse_move(event: MouseEvent):
95
- print(event.action, event.button, event.position)
96
- return False
97
-
98
-
99
94
  hook_listener = HookListener()
100
95
  hook_listener.add_handler('keydown', key_down)
101
96
  hook_listener.add_handler('keyup', key_up)
102
97
  hook_listener.add_handler('mousedown', mouse_down)
103
98
  hook_listener.add_handler('mouseup', mouse_up)
104
- hook_listener.add_handler('mousemove', mouse_move)
105
99
  hook_listener.start()
106
100
 
107
101
  print("当前鼠标位置:", hook_listener.get_mouse_position())
@@ -68,17 +68,11 @@ def mouse_up(event: MouseEvent):
68
68
  return False
69
69
 
70
70
 
71
- def mouse_move(event: MouseEvent):
72
- print(event.action, event.button, event.position)
73
- return False
74
-
75
-
76
71
  hook_listener = HookListener()
77
72
  hook_listener.add_handler('keydown', key_down)
78
73
  hook_listener.add_handler('keyup', key_up)
79
74
  hook_listener.add_handler('mousedown', mouse_down)
80
75
  hook_listener.add_handler('mouseup', mouse_up)
81
- hook_listener.add_handler('mousemove', mouse_move)
82
76
  hook_listener.start()
83
77
 
84
78
  print("当前鼠标位置:", hook_listener.get_mouse_position())
@@ -1,5 +1,8 @@
1
1
  from ..constants import Hex_Key_Code
2
2
 
3
+ # 预构建 vkCode → name 反向字典
4
+ _VK_TO_NAME = {v: k for k, v in Hex_Key_Code.items()}
5
+
3
6
  class KeyEvent:
4
7
  """
5
8
  键盘事件
@@ -14,8 +17,7 @@ class KeyEvent:
14
17
  def __init__(self, action, vk_code):
15
18
  self.action = action
16
19
  self.key_code = vk_code
17
- name = next((k for k, v in Hex_Key_Code.items() if v == vk_code), None)
18
- self.key_name = name if name else str(vk_code)
20
+ self.key_name = _VK_TO_NAME.get(vk_code, str(vk_code))
19
21
 
20
22
  class MouseEvent:
21
23
  """
@@ -8,9 +8,6 @@ from ..constants import Hex_Hook_Code
8
8
 
9
9
  HHC = Hex_Hook_Code
10
10
 
11
- # 消息泵空闲轮询间隔(秒),无消息时休眠此时间以释放 CPU
12
- MSG_POLL_INTERVAL = 0.001
13
-
14
11
  # ---------- 结构体定义 ----------
15
12
  class KBDLLHOOKSTRUCT(Structure):
16
13
  _fields_ = [
@@ -80,7 +77,6 @@ class HookListener:
80
77
  self._on_keyup = []
81
78
  self._on_mousedown = []
82
79
  self._on_mouseup = []
83
- self._on_mousemove = []
84
80
 
85
81
  # 钩子与线程状态
86
82
  self._thread = None
@@ -115,8 +111,6 @@ class HookListener:
115
111
  self._on_mousedown.append(func)
116
112
  elif event_type == "mouseup":
117
113
  self._on_mouseup.append(func)
118
- elif event_type == "mousemove":
119
- self._on_mousemove.append(func)
120
114
  else:
121
115
  raise ValueError("unknown event_type: " + str(event_type))
122
116
 
@@ -140,8 +134,6 @@ class HookListener:
140
134
  target = self._on_mousedown
141
135
  elif event_type == "mouseup":
142
136
  target = self._on_mouseup
143
- elif event_type == "mousemove":
144
- target = self._on_mousemove
145
137
  else:
146
138
  raise ValueError("unknown event_type: " + str(event_type))
147
139
  try:
@@ -201,17 +193,7 @@ class HookListener:
201
193
  ms = ctypes.cast(lParam, POINTER(MSLLHOOKSTRUCT)).contents
202
194
  x, y = ms.pt.x, ms.pt.y
203
195
 
204
- if wParam == 0x0200: # WM_MOUSEMOVE
205
- event = MouseEvent("MouseMove", None, x, y)
206
- for cb in self._on_mousemove:
207
- try:
208
- result = cb(event)
209
- if result is True:
210
- return 1 # 截断事件传播
211
- except Exception as e:
212
- print(f"[hook_listener] Exception in mousemove callback: {e}", file=__import__('sys').stderr)
213
-
214
- elif wParam in (HHC["MLeftDown"], HHC["MRightDown"], HHC["MiddleDown"], HHC["XDown"]):
196
+ if wParam in (HHC["MLeftDown"], HHC["MRightDown"], HHC["MiddleDown"], HHC["XDown"]):
215
197
  button = self._get_mouse_button(wParam, ms.mouseData)
216
198
  event = MouseEvent("MouseDown", button, x, y)
217
199
  for cb in self._on_mousedown:
@@ -315,7 +297,7 @@ class HookListener:
315
297
  self._stop_event.set()
316
298
  # 发送 WM_QUIT 消息唤醒 GetMessageW 阻塞
317
299
  if self._thread and self._thread.is_alive():
318
- user32.PostThreadMessageW(self._thread.ident, 0x0012, 0, 0)
300
+ user32.PostThreadMessageW(self._thread.ident, 0x0012, 0, 0) # WM_QUIT
319
301
  self._thread.join(timeout=1.0)
320
302
  # 尝试取消钩子(若尚未取消)
321
303
  if self.keyboard_hook:
@@ -346,11 +328,9 @@ class HookListener:
346
328
  self._stop_event.set()
347
329
  return
348
330
 
331
+ # 消息泵循环:ctypes 调用 GetMessageW 期间会释放 GIL
349
332
  msg = wintypes.MSG()
350
- while True:
351
- ret = user32.GetMessageW(byref(msg), 0, 0, 0)
352
- if ret <= 0:
353
- break
333
+ while user32.GetMessageW(byref(msg), None, 0, 0) > 0:
354
334
  user32.TranslateMessage(byref(msg))
355
335
  user32.DispatchMessageW(byref(msg))
356
336
 
@@ -10,8 +10,9 @@ SendInput = user32.SendInput
10
10
 
11
11
  class Mouse:
12
12
 
13
- def __init__(self):
13
+ def __init__(self, compat=False):
14
14
  """初始化鼠标控制器"""
15
+ self.compat = compat
15
16
  self.mouse_point = tuple()
16
17
  self.screen_width = user32.GetSystemMetrics(0)
17
18
  self.screen_height = user32.GetSystemMetrics(1)
@@ -23,14 +24,25 @@ class Mouse:
23
24
  4: [HMC["XDown"], HMC["XUp"], HMC["MSide2"]],
24
25
  }
25
26
 
26
- def _mouse_action(self, flags, x=0, y=0, data=0):
27
- """执行鼠标动作的底层函数"""
27
+ def _mouse_action_compat(self, flags, x=0, y=0, data=0):
28
+ """执行鼠标动作的底层函数(兼容模式,使用 mouse_event API)"""
29
+ user32.mouse_event(flags, x, y, data, 0)
30
+
31
+ def _mouse_action_input(self, flags, x=0, y=0, data=0):
32
+ """执行鼠标动作的底层函数(SendInput 模式)"""
28
33
  extra = ctypes.c_ulong(0)
29
34
  ii_ = Input_I()
30
35
  ii_.mi = MouseInput(x, y, data, flags, 0, ctypes.pointer(extra))
31
36
  input_struct = Input(ctypes.c_ulong(0), ii_)
32
37
  SendInput(1, ctypes.pointer(input_struct), ctypes.sizeof(input_struct))
33
38
 
39
+ def _mouse_action(self, flags, x=0, y=0, data=0):
40
+ """执行鼠标动作的底层函数"""
41
+ if self.compat:
42
+ self._mouse_action_compat(flags, x, y, data)
43
+ else:
44
+ self._mouse_action_input(flags, x, y, data)
45
+
34
46
  def _verify_mouse_point(self, x: int=None, y: int=None):
35
47
  """验证鼠标坐标是否在屏幕范围内"""
36
48
  if x is None or y is None:
@@ -169,8 +169,13 @@ class WindowMatch:
169
169
  bmi.bmiHeader.biClrUsed = 0
170
170
  bmi.bmiHeader.biClrImportant = 0
171
171
 
172
- # 分配内存
173
- buffer_size = width * height * 3
172
+ # GDI 要求位图每行字节数(stride)必须是 4 的倍数(DWORD 对齐)
173
+ # 若直接用 width * height * 3,当 width * 3 不是 4 的倍数时,
174
+ # 每行末尾会被 GDI 填充字节,导致 reshape 后行数据错位、图像倾斜。
175
+ stride = ((width * 3 + 3) // 4) * 4
176
+
177
+ # 分配内存(按 stride 对齐)
178
+ buffer_size = stride * height
174
179
  buffer = ctypes.create_string_buffer(buffer_size)
175
180
 
176
181
  # 获取位图数据
@@ -178,8 +183,9 @@ class WindowMatch:
178
183
  hdc_mem, hbitmap, 0, height, buffer, ctypes.byref(bmi), 0
179
184
  )
180
185
 
181
- # 转换为numpy数组
182
- img_array = np.frombuffer(buffer, dtype=np.uint8).reshape(height, width, 3)
186
+ # 转换为numpy数组:先按 stride 展开,再丢弃每行末尾的填充字节
187
+ img_array = np.frombuffer(buffer, dtype=np.uint8).reshape(height, stride)
188
+ img_array = img_array[:, :width * 3].reshape(height, width, 3)
183
189
 
184
190
  # 转为RGB格式数组
185
191
  img_array = self.data_header.image_to_numpy(img_array, to_rgb=True)
@@ -266,8 +272,11 @@ class WindowMatch:
266
272
  bmi.bmiHeader.biClrUsed = 0
267
273
  bmi.bmiHeader.biClrImportant = 0
268
274
 
269
- # 分配内存
270
- buffer_size = window_width * window_height * 3
275
+ # GDI 要求位图每行字节数(stride)必须是 4 的倍数(DWORD 对齐)
276
+ stride = ((window_width * 3 + 3) // 4) * 4
277
+
278
+ # 分配内存(按 stride 对齐)
279
+ buffer_size = stride * window_height
271
280
  buffer = ctypes.create_string_buffer(buffer_size)
272
281
 
273
282
  # 获取位图数据
@@ -275,8 +284,9 @@ class WindowMatch:
275
284
  hdc_mem, hbitmap, 0, window_height, buffer, ctypes.byref(bmi), 0
276
285
  )
277
286
 
278
- # 转换为numpy数组
279
- img_array = np.frombuffer(buffer, dtype=np.uint8).reshape(window_height, window_width, 3)
287
+ # 转换为numpy数组:先按 stride 展开,再丢弃每行末尾的填充字节
288
+ img_array = np.frombuffer(buffer, dtype=np.uint8).reshape(window_height, stride)
289
+ img_array = img_array[:, :window_width * 3].reshape(window_height, window_width, 3)
280
290
 
281
291
  # 转为RGB格式数组
282
292
  img_array = self.data_header.image_to_numpy(img_array, to_rgb=True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autoxkit
3
- Version: 2.4.4
3
+ Version: 2.4.8
4
4
  Summary: Python library for Windows automation and Android device screen casting and control
5
5
  Author-email: YorickFin <1582456060@qq.com>
6
6
  License: GPL-3.0-or-later
@@ -91,17 +91,11 @@ def mouse_up(event: MouseEvent):
91
91
  return False
92
92
 
93
93
 
94
- def mouse_move(event: MouseEvent):
95
- print(event.action, event.button, event.position)
96
- return False
97
-
98
-
99
94
  hook_listener = HookListener()
100
95
  hook_listener.add_handler('keydown', key_down)
101
96
  hook_listener.add_handler('keyup', key_up)
102
97
  hook_listener.add_handler('mousedown', mouse_down)
103
98
  hook_listener.add_handler('mouseup', mouse_up)
104
- hook_listener.add_handler('mousemove', mouse_move)
105
99
  hook_listener.start()
106
100
 
107
101
  print("当前鼠标位置:", hook_listener.get_mouse_position())
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "autoxkit"
7
- version = "2.4.4"
7
+ version = "2.4.8"
8
8
  description = "Python library for Windows automation and Android device screen casting and control"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
File without changes
File without changes
File without changes
File without changes
File without changes