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)