using System.Runtime.InteropServices; using System.Windows; using System.Windows.Input; using System.Windows.Interop; namespace TaskbarLauncher.Services; public sealed class HotkeyService : IDisposable { private const int WmHotkey = 0x0312; private const int HotkeyId = 9001; private HwndSource? source; private Window? window; public event EventHandler? Pressed; public void Register(string hotkey) { Unregister(); window = new Window { Width = 0, Height = 0, ShowInTaskbar = false, WindowStyle = WindowStyle.None, AllowsTransparency = true, Opacity = 0, Left = -10000, Top = -10000 }; window.SourceInitialized += (_, _) => { var helper = new WindowInteropHelper(window); source = HwndSource.FromHwnd(helper.Handle); source?.AddHook(WndProc); ParseHotkey(hotkey, out uint modifiers, out uint key); RegisterHotKey(helper.Handle, HotkeyId, modifiers, key); }; window.Show(); window.Hide(); } public void Unregister() { if (window is not null) { var helper = new WindowInteropHelper(window); if (helper.Handle != IntPtr.Zero) { UnregisterHotKey(helper.Handle, HotkeyId); } } source?.RemoveHook(WndProc); source = null; window?.Close(); window = null; } public void Dispose() { Unregister(); } private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg == WmHotkey && wParam.ToInt32() == HotkeyId) { Pressed?.Invoke(this, EventArgs.Empty); handled = true; } return IntPtr.Zero; } private static void ParseHotkey(string hotkey, out uint modifiers, out uint key) { modifiers = 0; key = (uint)KeyInterop.VirtualKeyFromKey(Key.Space); foreach (string part in hotkey.Split('+', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)) { if (part.Equals("Ctrl", StringComparison.OrdinalIgnoreCase) || part.Equals("Control", StringComparison.OrdinalIgnoreCase)) { modifiers |= 0x0002; } else if (part.Equals("Alt", StringComparison.OrdinalIgnoreCase)) { modifiers |= 0x0001; } else if (part.Equals("Shift", StringComparison.OrdinalIgnoreCase)) { modifiers |= 0x0004; } else if (part.Equals("Win", StringComparison.OrdinalIgnoreCase)) { modifiers |= 0x0008; } else if (Enum.TryParse(part, true, out Key parsedKey)) { key = (uint)KeyInterop.VirtualKeyFromKey(parsedKey); } } } [DllImport("user32.dll", SetLastError = true)] private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); [DllImport("user32.dll", SetLastError = true)] private static extern bool UnregisterHotKey(IntPtr hWnd, int id); }