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:
youpaishidifu
2026-07-29 14:23:47 +08:00
parent c243549169
commit 47bd990f76
+13 -7
View File
@@ -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)