#if WINDOWS using System.Runtime.InteropServices; using WinRT.Interop; using MauiWindow = Microsoft.Maui.Controls.Window; namespace Hua.Todo.Maui.Services.Platforms { /// /// Windows 平台全局热键服务实现类 /// 使用 Windows API 实现全局热键功能 /// public class WindowsGlobalHotKeyService : IGlobalHotKeyService { private const int HOTKEY_ID = 9000; private const int WM_HOTKEY = 0x0312; private const int GWL_WNDPROC = -4; public const uint MOD_ALT = 0x0001; public const uint MOD_CONTROL = 0x0002; public const uint MOD_SHIFT = 0x0004; public const uint MOD_WIN = 0x0008; [DllImport("user32.dll")] private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); [DllImport("user32.dll")] private static extern bool UnregisterHotKey(IntPtr hWnd, int id); private IntPtr _windowHandle; private MauiWindow? _window; private Action? _callback; private bool _isRegistered; private uint _currentModifiers; private uint _currentKey; private IntPtr _originalWndProc; private WndProcDelegate? _wndProc; /// /// Windows 平台支持全局热键 /// public bool IsSupported => true; /// /// 注册全局热键 /// public void RegisterHotKey(string modifiers, string key, Action callback) { if (_window == null) { _window = Microsoft.Maui.Controls.Application.Current?.Windows.FirstOrDefault(); if (_window == null) return; } if (_window.Handler?.PlatformView is not Microsoft.UI.Xaml.Window platformWindow) return; _windowHandle = WindowNative.GetWindowHandle(platformWindow); if (_windowHandle == IntPtr.Zero) return; _callback = callback; _currentModifiers = ParseModifiers(modifiers); _currentKey = ParseKey(key); if (_isRegistered) { UnregisterHotKey(); } if (RegisterHotKey(_windowHandle, HOTKEY_ID, _currentModifiers, _currentKey)) { _isRegistered = true; EnsureWndProcHook(); } else { System.Diagnostics.Debug.WriteLine("Failed to register hotkey"); } } /// /// 注销全局热键 /// public void UnregisterHotKey() { if (_isRegistered) { UnregisterHotKey(_windowHandle, HOTKEY_ID); _isRegistered = false; } if (_originalWndProc != IntPtr.Zero && _windowHandle != IntPtr.Zero) { SetWindowProc(_windowHandle, GWL_WNDPROC, _originalWndProc); _originalWndProc = IntPtr.Zero; _wndProc = null; } } /// /// 更新热键配置 /// public void UpdateHotKey(string modifiers, string key) { if (_callback != null) { RegisterHotKey(modifiers, key, _callback); } } private void EnsureWndProcHook() { if (_originalWndProc != IntPtr.Zero) return; if (_windowHandle == IntPtr.Zero) return; _wndProc = WndProc; var newWndProcPtr = Marshal.GetFunctionPointerForDelegate(_wndProc); _originalWndProc = SetWindowProc(_windowHandle, GWL_WNDPROC, newWndProcPtr); } private IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { if (msg == WM_HOTKEY && wParam == (IntPtr)HOTKEY_ID) { _callback?.Invoke(); } if (_originalWndProc != IntPtr.Zero) { return CallWindowProc(_originalWndProc, hWnd, msg, wParam, lParam); } return DefWindowProc(hWnd, msg, wParam, lParam); } /// /// 解析修饰键字符串 /// private uint ParseModifiers(string modifiers) { uint mod = 0; if (string.IsNullOrEmpty(modifiers)) return mod; var parts = modifiers.Split(','); foreach (var part in parts) { var p = part.Trim(); if (p.Equals("Control", StringComparison.OrdinalIgnoreCase)) mod |= MOD_CONTROL; if (p.Equals("Alt", StringComparison.OrdinalIgnoreCase)) mod |= MOD_ALT; if (p.Equals("Shift", StringComparison.OrdinalIgnoreCase)) mod |= MOD_SHIFT; if (p.Equals("Windows", StringComparison.OrdinalIgnoreCase)) mod |= MOD_WIN; } return mod; } /// /// 解析主键 /// private uint ParseKey(string key) { if (key.Length == 1) { char c = char.ToUpper(key[0]); if (c >= 'A' && c <= 'Z') return (uint)c; if (c >= '0' && c <= '9') return (uint)c; } return 0x58; // Default 'X' } private delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll", EntryPoint = "SetWindowLongPtrW")] private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong); [DllImport("user32.dll", EntryPoint = "SetWindowLongW")] private static extern IntPtr SetWindowLong32(IntPtr hWnd, int nIndex, IntPtr dwNewLong); private static IntPtr SetWindowProc(IntPtr hWnd, int nIndex, IntPtr newProc) { return IntPtr.Size == 8 ? SetWindowLongPtr64(hWnd, nIndex, newProc) : SetWindowLong32(hWnd, nIndex, newProc); } [DllImport("user32.dll")] private static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll")] private static extern IntPtr DefWindowProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); } } #endif