在 WPF / C# 中使用全局键盘钩子 (WH_KEYBOARD_LL)
提供的代码旨在使用 WH_KEYBOARD_LL 钩子建立一个全局键盘钩子捕获并处理键盘事件。虽然实现基本上实现了其预期功能,但出现了一个关键问题:在持续击键一段时间后,事件处理突然停止。
此行为表明存在潜在的线程问题。为了解决这个问题,我们需要确保只要钩子就位,回调委托就保持活动状态。
问题分析
回调委托 HookCallback 是在 SetHook 方法中内联定义。因此,一旦方法退出,委托就有资格进行垃圾回收。发生这种情况时,挂钩将停止接收回调,从而导致观察到事件处理终止。
解决方案
要纠正此问题,我们需要保留对委托并确保其生命周期与钩子的存在一致。以下是解决该问题的修订后的代码:
using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Windows.Input; namespace MYCOMPANYHERE.WPF.KeyboardHelper { public class KeyboardListener : IDisposable { private static IntPtr hookId = IntPtr.Zero; private InterceptKeys.LowLevelKeyboardProc callback; public KeyboardListener() { callback = HookCallback; hookId = InterceptKeys.SetHook(callback); } [MethodImpl(MethodImplOptions.NoInlining)] private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { try { return HookCallbackInner(nCode, wParam, lParam); } catch { Console.WriteLine("There was some error somewhere..."); } return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam); } private IntPtr HookCallbackInner(int nCode, IntPtr wParam, IntPtr lParam) { // ... (original code here) return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam); } // ... (rest of the class) } }
在此更新的代码中,LowLevelKeyboardProc 委托(回调)现在是 KeyboardListener 类的一个字段。通过维护此引用,我们确保委托在钩子的整个生命周期中保持活动状态并可用于回调调用。
通过以这种方式解决线程问题,全局键盘钩子将继续可靠地捕获和处理键盘事件,即使在无情的击键情况下也是如此。
以上是为什么 C# 中的全局键盘挂钩在持续击键后停止工作?的详细内容。更多信息请关注PHP中文网其他相关文章!