using System; using System.Windows.Forms; namespace SystemTrayMenu.Helper { public sealed class KeyboardHook : IDisposable { /// /// Represents the window that is used internally to get the messages. /// private class Window : NativeWindow, IDisposable { private const int WM_HOTKEY = 0x0312; public Window() { // create the handle for the window. CreateHandle(new CreateParams()); } /// /// Overridden to get the notifications. /// /// protected override void WndProc(ref Message m) { base.WndProc(ref m); // check if we got a hot key pressed. if (m.Msg == WM_HOTKEY) { // get the keys. Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF); KeyboardHookModifierKeys modifier = (KeyboardHookModifierKeys)((int)m.LParam & 0xFFFF); // invoke the event to notify the parent. if (KeyPressed != null) { KeyPressed(this, new KeyPressedEventArgs(modifier, key)); } } } public event EventHandler KeyPressed; #region IDisposable Members public void Dispose() { DestroyHandle(); } #endregion } private readonly Window _window = new Window(); private int _currentId; public KeyboardHook() { // register the event of the inner native window. _window.KeyPressed += delegate (object sender, KeyPressedEventArgs args) { KeyPressed?.Invoke(this, args); }; } /// /// Registers a hot key in the system. /// /// The modifiers that are associated with the hot key. /// The key itself that is associated with the hot key. internal void RegisterHotKey(KeyboardHookModifierKeys modifier, Keys key) { _currentId = _currentId + 1; if (!DllImports.NativeMethods.User32RegisterHotKey(_window.Handle, _currentId, (uint)modifier, (uint)key)) { #pragma warning disable CA1303 // Do not pass literals as localized parameters throw new InvalidOperationException("Couldn’t register the hot key."); #pragma warning restore CA1303 //=> Exceptions not translated in logfile => OK } } /// /// A hot key has been pressed. /// internal event EventHandler KeyPressed; #region IDisposable Members public void Dispose() { // unregister all the registered hot keys. for (int i = _currentId; i > 0; i--) { DllImports.NativeMethods.User32UnregisterHotKey(_window.Handle, i); } // dispose the inner native window. _window.Dispose(); } #endregion } /// /// Event Args for the event that is fired after the hot key has been pressed. /// internal class KeyPressedEventArgs : EventArgs { private readonly KeyboardHookModifierKeys _modifier; private readonly Keys _key; internal KeyPressedEventArgs(KeyboardHookModifierKeys modifier, Keys key) { _modifier = modifier; _key = key; } internal KeyboardHookModifierKeys Modifier => _modifier; internal Keys Key => _key; } /// /// The enumeration of possible modifiers. /// [Flags] internal enum KeyboardHookModifierKeys : uint { Alt = 1, Control = 2, Shift = 4, Win = 8 } }