[WPF] Declare global hotkeys in XAML with NHotkey

A common requirement for desktop applications is to handle system-wide hotkeys, in order to intercept keyboard shortcuts even when they don’t have focus. Unfortunately, there is no built-in feature in the .NET framework to do it.

Of course, this is not a new issue, and there are quite a few open-source libraries that address it (e.g. VirtualInput). Most of them rely on a global system hook, which allow them to intercept all keystrokes, even the ones you’re not interested in. I used some of those libraries before, but I’m not really happy with them:

they’re often tied to a specific UI framework (usually Windows Forms), which makes them a bit awkward to use in another UI framework (like WPF)

I don’t really like the approach of intercepting all keystrokes. It usually means that you end up with a big method with lots of if/else if to decide what to do based on which keys were pressed.

A better option, in my opinion, is to listen only to the keys you’re interested in, and declare what to do for each of those. The approach used in WPF for key bindings is quite elegant:

The library takes advantage of the RegisterHotkey function. Because it also supports Windows Forms, it is split into 3 parts, so that you don’t need to reference the WinForms assembly from a WPF app or vice versa:

The core library, which handles the hotkey registration itself, independently of any specific UI framework. This library is not directly usable, but is used by the other two.

The WinForms-specific API, which uses the Keys enumeration from System.Windows.Forms

The WPF-specific API, which uses the Key and ModifierKeys enumerations from System.Windows.Input, and supports global key bindings in XAML.

13 thoughts on “[WPF] Declare global hotkeys in XAML with NHotkey”

System.Windows.Markup.XamlParseException was unhandled
HResult=-2146233087
Message=’Set property ‘NHotkey.Wpf.HotkeyManager.RegisterGlobalHotkey’ threw an exception.’ Line number ’19’ and line position ’61’.

Yes, my solution is based on Win32; the RegisterHotkey function registers global hotkeys, so the key combination has to be unique. If you don’t need the hotkeys to be global, you don’t need my solution at all… just use the normal WPF input bindings.

You can’t define global hotkeys without a modifier (see https://github.com/thomaslevesque/NHotkey/issues/9), so I don’t know how you managed to define a hotkey for ²…
When you define a global hotkey with a modifier, only your app receives it; the focused app doesn’t receive the keystroke.