using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Windows.Forms; using System.Windows.Input; namespace ExternalHelpers { /// /// Taken and adapted from: https://stackoverflow.com/a/65412682 /// public class GlobalHotKey : IDisposable { /// /// Registers a global hotkey /// /// e.g. Alt + Shift + Control + Win + S /// Action to be called when hotkey is pressed /// true, if registration succeeded, otherwise false public static bool RegisterHotKey(string aKeyGestureString, Action aAction, bool repeat = false) { if (aKeyGestureString == "") return false; bool success = false; var c = new KeyGestureConverter(); foreach (var gesture in aKeyGestureString.Split(",")) { KeyGesture aKeyGesture = (KeyGesture)c.ConvertFrom(gesture); if (RegisterHotKey(aKeyGesture.Modifiers, aKeyGesture.Key, aAction, repeat)) success = true; } return success; } public static bool RegisterHotKey(ModifierKeys aModifier, Key aKey, Action aAction, bool repeat) { if (aModifier == ModifierKeys.None && false) { throw new ArgumentException("Modifier must not be ModifierKeys.None"); } if (aAction is null) { throw new ArgumentNullException(nameof(aAction)); } System.Windows.Forms.Keys aVirtualKeyCode = (System.Windows.Forms.Keys)KeyInterop.VirtualKeyFromKey(aKey); currentID = currentID + 1; bool aRegistered = RegisterHotKey(window.Handle, currentID, (uint)aModifier | (repeat ? MOD_NOREPEAT : 0), (uint)aVirtualKeyCode); if (aRegistered) { registeredHotKeys.Add(new HotKeyWithAction(aModifier, aKey, aAction)); } return aRegistered; } public void Dispose() { // unregister all the registered hot keys. for (int i = currentID; i > 0; i--) { UnregisterHotKey(window.Handle, i); } // dispose the inner native window. window.Dispose(); } static GlobalHotKey() { window.KeyPressed += (s, e) => { registeredHotKeys.ForEach(x => { if (e.Modifier == x.Modifier && e.Key == x.Key) { x.Action(); } }); }; } private static readonly InvisibleWindowForMessages window = new InvisibleWindowForMessages(); private static int currentID; private static uint MOD_NOREPEAT = 0x4000; private static List registeredHotKeys = new List(); private class HotKeyWithAction { public HotKeyWithAction(ModifierKeys modifier, Key key, Action action) { Modifier = modifier; Key = key; Action = action; } public ModifierKeys Modifier { get; } public Key Key { get; } public Action Action { get; } } // Registers a hot key with Windows. [DllImport("user32.dll")] private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); // Unregisters the hot key with Windows. [DllImport("user32.dll")] private static extern bool UnregisterHotKey(IntPtr hWnd, int id); private class InvisibleWindowForMessages : System.Windows.Forms.NativeWindow, IDisposable { public InvisibleWindowForMessages() { CreateHandle(new System.Windows.Forms.CreateParams()); } private static int WM_HOTKEY = 0x0312; protected override void WndProc(ref System.Windows.Forms.Message m) { base.WndProc(ref m); if (m.Msg == WM_HOTKEY) { var aWPFKey = KeyInterop.KeyFromVirtualKey(((int)m.LParam >> 16) & 0xFFFF); ModifierKeys modifier = (ModifierKeys)((int)m.LParam & 0xFFFF); if (KeyPressed != null) { KeyPressed(this, new HotKeyPressedEventArgs(modifier, aWPFKey)); } } } public class HotKeyPressedEventArgs : EventArgs { private ModifierKeys _modifier; private Key _key; internal HotKeyPressedEventArgs(ModifierKeys modifier, Key key) { _modifier = modifier; _key = key; } public ModifierKeys Modifier { get { return _modifier; } } public Key Key { get { return _key; } } } public event EventHandler KeyPressed; #region IDisposable Members public void Dispose() { this.DestroyHandle(); } #endregion } } }