From 47bd990f7676262358ccc9f97554329ace46c173 Mon Sep 17 00:00:00 2001 From: youpaishidifu Date: Wed, 29 Jul 2026 14:23:47 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=80=A5=E5=81=9CWH=5FKEYBOARD=5FLL?= =?UTF-8?q?=E9=92=A9=E5=AD=90=E4=B8=A4=E4=B8=AA=E8=87=B4=E5=91=BDbug?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. hmod参数必须为NULL: GetModuleHandleW(None)返回Python.exe模块句柄≠NULL, 导致SetWindowsHookExW静默失败,钩子从未安装成功。改用None(0)。 2. 安装钩子前先创建消息队列: PeekMessageW强制创建线程消息队列, WH_KEYBOARD_LL回调通过GetMessage投递,无消息队列则回调永远不到达。 新增启动成功日志: [急停] 底层键盘钩子安装成功,ESC 急停已激活 --- monitor.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/monitor.py b/monitor.py index 88eb661..84c0600 100644 --- a/monitor.py +++ b/monitor.py @@ -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)