fix: 急停WH_KEYBOARD_LL钩子两个致命bug修复
1. hmod参数必须为NULL: GetModuleHandleW(None)返回Python.exe模块句柄≠NULL, 导致SetWindowsHookExW静默失败,钩子从未安装成功。改用None(0)。 2. 安装钩子前先创建消息队列: PeekMessageW强制创建线程消息队列, WH_KEYBOARD_LL回调通过GetMessage投递,无消息队列则回调永远不到达。 新增启动成功日志: [急停] 底层键盘钩子安装成功,ESC 急停已激活
This commit is contained in:
+13
-7
@@ -370,9 +370,15 @@ class MessageMonitor:
|
||||
# 引用保持(防止 GC 回收回调 → 系统崩溃)
|
||||
self._esc_hook_proc = _HOOKPROC(_ll_hook)
|
||||
|
||||
hInstance = ctypes.windll.kernel32.GetModuleHandleW(None)
|
||||
# ⭐ 步骤1: 先创建线程消息队列(PeekMessage 强制创建)
|
||||
# WH_KEYBOARD_LL 要求安装线程有消息队列,否则钩子回调无法投递
|
||||
_msg = wintypes.MSG()
|
||||
ctypes.windll.user32.PeekMessageW(ctypes.byref(_msg), None, 0, 0, 0) # PM_NOREMOVE
|
||||
|
||||
# ⭐ 步骤2: 安装钩子 — hmod 必须为 NULL (0)
|
||||
# GetModuleHandleW(None) 返回 Python.exe 的模块句柄 ≠ NULL → 钩子静默失败!
|
||||
hook_handle = ctypes.windll.user32.SetWindowsHookExW(
|
||||
_WH_KEYBOARD_LL, self._esc_hook_proc, hInstance, 0
|
||||
_WH_KEYBOARD_LL, self._esc_hook_proc, None, 0 # hmod = NULL
|
||||
)
|
||||
if not hook_handle:
|
||||
err = ctypes.windll.kernel32.GetLastError()
|
||||
@@ -380,15 +386,15 @@ class MessageMonitor:
|
||||
"[急停] 底层键盘钩子安装失败 (err=%d) — ESC 急停不可用", err
|
||||
)
|
||||
return
|
||||
logger.info("[急停] 底层键盘钩子安装成功,ESC 急停已激活")
|
||||
|
||||
# ⭐ 消息泵:WH_KEYBOARD_LL 通过 GetMessage 分发钩子回调
|
||||
msg = wintypes.MSG()
|
||||
# ⭐ 步骤3: 消息泵 — WH_KEYBOARD_LL 通过 GetMessage 分发钩子回调
|
||||
while self._running:
|
||||
ret = ctypes.windll.user32.GetMessageW(ctypes.byref(msg), None, 0, 0)
|
||||
ret = ctypes.windll.user32.GetMessageW(ctypes.byref(_msg), None, 0, 0)
|
||||
if ret <= 0:
|
||||
break # WM_QUIT 或出错
|
||||
ctypes.windll.user32.TranslateMessage(ctypes.byref(msg))
|
||||
ctypes.windll.user32.DispatchMessageW(ctypes.byref(msg))
|
||||
ctypes.windll.user32.TranslateMessage(ctypes.byref(_msg))
|
||||
ctypes.windll.user32.DispatchMessageW(ctypes.byref(_msg))
|
||||
|
||||
# 线程退出 → 卸载钩子
|
||||
ctypes.windll.user32.UnhookWindowsHookEx(hook_handle)
|
||||
|
||||
Reference in New Issue
Block a user