C# MAUI桌面程序后台捕获按键的实现方案咨询
在MAUI Windows平台实现全局键盘钩子
问题原因
MAUI Windows基于WinUI 3,其消息循环机制和WPF存在差异。原代码中SetWindowsHookEx传入IntPtr.Zero作为模块句柄,在MAUI环境下无法正确完成钩子注册;另外需要确保钩子回调的委托不会被垃圾回收(你的代码已通过类成员_proc保持强引用,这部分无需调整)。
修改现有GlobalKeyboardHook类
以下是适配MAUI Windows的修改版本:
using System; using System.Runtime.InteropServices; using System.Diagnostics; class GlobalKeyboardHook { private const int WH_KEYBOARD_LL = 13; private const int WM_KEYUP = 0x0101; private delegate int LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool UnhookWindowsHookEx(IntPtr hhk); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr GetModuleHandle(string lpModuleName); private IntPtr _hookID = IntPtr.Zero; private LowLevelKeyboardProc _proc; // 用事件替代硬编码逻辑,提升灵活性 public event Action<int> KeyReleased; public GlobalKeyboardHook() { _proc = HookCallback; } public void Hook() { // 获取当前进程主模块句柄,替代原代码的IntPtr.Zero using var currentProcess = Process.GetCurrentProcess(); using var currentModule = currentProcess.MainModule; var moduleHandle = GetModuleHandle(currentModule.ModuleName); _hookID = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, moduleHandle, 0); // 检查钩子是否注册成功,失败则抛出异常 if (_hookID == IntPtr.Zero) { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } } public void Unhook() { if (_hookID != IntPtr.Zero) { UnhookWindowsHookEx(_hookID); _hookID = IntPtr.Zero; } } private int HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP) { int vkCode = Marshal.ReadInt32(lParam); KeyReleased?.Invoke(vkCode); } return (int)CallNextHookEx(_hookID, nCode, wParam, lParam); } }
使用方式
在MAUI的Windows平台特定代码中注册钩子,比如在App.xaml.cs中:
#if WINDOWS private GlobalKeyboardHook _keyboardHook; protected override void OnLaunched(LaunchActivatedEventArgs args) { base.OnLaunched(args); _keyboardHook = new GlobalKeyboardHook(); _keyboardHook.KeyReleased += vkCode => { if (vkCode == 9) // 检测Tab键释放 { Global.Initiate_server?.SendMessage(Global.TrepCserver.Takescreenshot); } }; try { _keyboardHook.Hook(); } catch (Exception ex) { Debug.WriteLine($"钩子注册失败: {ex.Message}"); } } // 应用退出时务必取消钩子,避免内存泄漏 protected override void OnClosed(WindowClosedEventArgs args) { _keyboardHook?.Unhook(); base.OnClosed(args); } #endif
第三方库选项
如果不想手动实现钩子逻辑,可以使用NuGet上的GlobalHotkey库。它支持MAUI Windows平台,专门用于全局热键检测,只需安装包后注册热键并订阅事件即可。注意该库仅支持检测特定热键组合(如Ctrl+Tab),若需要捕获所有按键操作,自定义钩子仍是更合适的选择。
内容的提问来源于stack exchange,提问作者Toballz Ibot
相关产品推荐
相关产品推荐

