/// <summary> /// Register a delegate to be called the next time the user presses /// any hotkey. /// Used to create a new binding by listening for user input. /// </summary> /// <remarks> /// All hotkeys registered with AddHotKey will be blocked until after /// this delegate is called. /// When any keyboard combination is pressed, the delegate will be /// called containing the pressed hotkey. /// The client is then free to register a new binding with this hotkey /// using <c>AddHotKey</c>. /// If the rebinding fails, the delegate will be called with /// <c>wasRebindSuccessful</c> set to <c>false</c>. /// </remarks> /// <param name="handler">The handler for the next hotkey press.</param> public void ListenForRebind(HotKeyRebindDelegate handler) { if (rebindHandler != null) { rebindHandler(false, new HotKey()); } rebindHandler = handler; }
// Win32 system hook handler. private int HotKeyHook(int nCode, IntPtr wParam, IntPtr lParam) { // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms644985(v=vs.85).aspx // for info on Windows keyboard hooks. if (nCode == 0) { KBDLLHOOKSTRUCT keyboardData = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT)); Keys key = (Keys)keyboardData.vkCode; if (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN) { // If this was a modifier key press, then update the modifier state. switch (key) { case Keys.Control: case Keys.ControlKey: case Keys.LControlKey: case Keys.RControlKey: currentHotKey.isCtrl = true; break; case Keys.Shift: case Keys.ShiftKey: case Keys.LShiftKey: case Keys.RShiftKey: currentHotKey.isShift = true; break; case Keys.Menu: case Keys.LMenu: case Keys.RMenu: currentHotKey.isAlt = true; break; case Keys.LWin: case Keys.RWin: currentHotKey.isWindows = true; break; default: // If it was a normal key press, fire any associated bindings. currentHotKey.key = key; if (rebindHandler != null) { // We are listening for a rebind. // Fire the rebind handler and consume the input. rebindHandler(true, currentHotKey); rebindHandler = null; return(-1); } else { // Look for a matching binding and fire it. foreach (var binding in bindings) { if (binding.hotKey.Equals(currentHotKey)) { binding.handler(); } } } break; } } else if (wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP) { // If a modifier key is released, update modifier key state. switch (key) { case Keys.Control: case Keys.ControlKey: case Keys.LControlKey: case Keys.RControlKey: currentHotKey.isCtrl = false; break; case Keys.Shift: case Keys.ShiftKey: case Keys.LShiftKey: case Keys.RShiftKey: currentHotKey.isShift = false; break; case Keys.Menu: case Keys.LMenu: case Keys.RMenu: currentHotKey.isAlt = false; break; case Keys.LWin: case Keys.RWin: currentHotKey.isWindows = false; break; } } } return(CallNextHookEx(hHotKeyHook, nCode, wParam, lParam)); }