How to register a global hotkey to say CTRL + SHIFT + (LETTER) using WPF and .NET 3.5?

I am building a C # application using WPF. How can I bind some keys?

Also, how can I bind to a Windows key ?

+44
c # windows wpf hotkeys
Sep 08 '08 at 0:35
source share
11 answers

I'm not sure what you mean by “global” here, but here it goes (I assume that you mean a command at the application level, for example, “Save All,” which can be run from anywhere on Ctrl + Shift + S. )

You will find a global UIElement of your choice, for example, a top-level window that is the parent of all the controls in which you need this binding. Due to the "bubble" of WPF events, events in the children will bubble to the root of the control tree.

Now first you need

  • to bind Key-Combo using a command using InputBinding like this
  • you can attach a command to your handler (for example, the code that SaveAll calls) via CommandBinding .

For a Windows key , you use the right Key enumerated element, Key.LWin or Key.RWin

  public WindowMain() { InitializeComponent(); // Bind Key InputBinding ib = new InputBinding( MyAppCommands.SaveAll, new KeyGesture(Key.S, ModifierKeys.Shift | ModifierKeys.Control)); this.InputBindings.Add(ib); // Bind handler CommandBinding cb = new CommandBinding( MyAppCommands.SaveAll); cb.Executed += new ExecutedRoutedEventHandler( HandlerThatSavesEverthing ); this.CommandBindings.Add (cb ); } private void HandlerThatSavesEverthing (object obSender, ExecutedRoutedEventArgs e) { // Do the Save All thing here. } 
+26
Sep 08 '08 at 4:36
source share

This is a complete working solution, hope this helps ...

Using:

 _hotKey = new HotKey(Key.F9, KeyModifier.Shift | KeyModifier.Win, OnHotKeyHandler); 

...

 private void OnHotKeyHandler(HotKey hotKey) { SystemHelper.SetScreenSaverRunning(); } 

Grade:

 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.Mime; using System.Runtime.InteropServices; using System.Text; using System.Windows; using System.Windows.Input; using System.Windows.Interop; namespace UnManaged { public class HotKey : IDisposable { private static Dictionary<int, HotKey> _dictHotKeyToCalBackProc; [DllImport("user32.dll")] private static extern bool RegisterHotKey(IntPtr hWnd, int id, UInt32 fsModifiers, UInt32 vlc); [DllImport("user32.dll")] private static extern bool UnregisterHotKey(IntPtr hWnd, int id); public const int WmHotKey = 0x0312; private bool _disposed = false; public Key Key { get; private set; } public KeyModifier KeyModifiers { get; private set; } public Action<HotKey> Action { get; private set; } public int Id { get; set; } // ****************************************************************** public HotKey(Key k, KeyModifier keyModifiers, Action<HotKey> action, bool register = true) { Key = k; KeyModifiers = keyModifiers; Action = action; if (register) { Register(); } } // ****************************************************************** public bool Register() { int virtualKeyCode = KeyInterop.VirtualKeyFromKey(Key); Id = virtualKeyCode + ((int)KeyModifiers * 0x10000); bool result = RegisterHotKey(IntPtr.Zero, Id, (UInt32)KeyModifiers, (UInt32)virtualKeyCode); if (_dictHotKeyToCalBackProc == null) { _dictHotKeyToCalBackProc = new Dictionary<int, HotKey>(); ComponentDispatcher.ThreadFilterMessage += new ThreadMessageEventHandler(ComponentDispatcherThreadFilterMessage); } _dictHotKeyToCalBackProc.Add(Id, this); Debug.Print(result.ToString() + ", " + Id + ", " + virtualKeyCode); return result; } // ****************************************************************** public void Unregister() { HotKey hotKey; if (_dictHotKeyToCalBackProc.TryGetValue(Id, out hotKey)) { UnregisterHotKey(IntPtr.Zero, Id); } } // ****************************************************************** private static void ComponentDispatcherThreadFilterMessage(ref MSG msg, ref bool handled) { if (!handled) { if (msg.message == WmHotKey) { HotKey hotKey; if (_dictHotKeyToCalBackProc.TryGetValue((int)msg.wParam, out hotKey)) { if (hotKey.Action != null) { hotKey.Action.Invoke(hotKey); } handled = true; } } } } // ****************************************************************** // Implement IDisposable. // Do not make this method virtual. // A derived class should not be able to override this method. public void Dispose() { Dispose(true); // This object will be cleaned up by the Dispose method. // Therefore, you should call GC.SupressFinalize to // take this object off the finalization queue // and prevent finalization code for this object // from executing a second time. GC.SuppressFinalize(this); } // ****************************************************************** // Dispose(bool disposing) executes in two distinct scenarios. // If disposing equals true, the method has been called directly // or indirectly by a user code. Managed and unmanaged resources // can be _disposed. // If disposing equals false, the method has been called by the // runtime from inside the finalizer and you should not reference // other objects. Only unmanaged resources can be _disposed. protected virtual void Dispose(bool disposing) { // Check to see if Dispose has already been called. if (!this._disposed) { // If disposing equals true, dispose all managed // and unmanaged resources. if (disposing) { // Dispose managed resources. Unregister(); } // Note disposing has been done. _disposed = true; } } } // ****************************************************************** [Flags] public enum KeyModifier { None = 0x0000, Alt = 0x0001, Ctrl = 0x0002, NoRepeat = 0x4000, Shift = 0x0004, Win = 0x0008 } // ****************************************************************** } 
+48
Feb 17 2018-12-17T00:
source share

If you are going to mix Win32 and WPF, here is how I did it:

 using System; using System.Runtime.InteropServices; using System.Windows.Interop; using System.Windows.Media; using System.Threading; using System.Windows; using System.Windows.Input; namespace GlobalKeyboardHook { public class KeyboardHandler : IDisposable { public const int WM_HOTKEY = 0x0312; public const int VIRTUALKEYCODE_FOR_CAPS_LOCK = 0x14; [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool UnregisterHotKey(IntPtr hWnd, int id); private readonly Window _mainWindow; WindowInteropHelper _host; public KeyboardHandler(Window mainWindow) { _mainWindow = mainWindow; _host = new WindowInteropHelper(_mainWindow); SetupHotKey(_host.Handle); ComponentDispatcher.ThreadPreprocessMessage += ComponentDispatcher_ThreadPreprocessMessage; } void ComponentDispatcher_ThreadPreprocessMessage(ref MSG msg, ref bool handled) { if (msg.message == WM_HOTKEY) { //Handle hot key kere } } private void SetupHotKey(IntPtr handle) { RegisterHotKey(handle, GetType().GetHashCode(), 0, VIRTUALKEYCODE_FOR_CAPS_LOCK); } public void Dispose() { UnregisterHotKey(_host.Handle, GetType().GetHashCode()); } } } 

You can get the virtual key code for the hotkey that you want to register here: http://msdn.microsoft.com/en-us/library/ms927178.aspx

Maybe the best way, but this is what I still have.

Hurrah!

+17
Dec 25 '09 at 0:05
source share

Registering OS-level shortcuts is unlikely to ever be good: users don’t want you to mess with your OS.

However, WPF is much simpler and more convenient to use if you are okay with a hotkey that works only in the application (i.e. as long as your WPF application has focus):

In App.xaml.cs:

 protected override void OnStartup(StartupEventArgs e) { EventManager.RegisterClassHandler(typeof(Window), Window.PreviewKeyUpEvent, new KeyEventHandler(OnWindowKeyUp)); } private void OnWindowKeyUp(object source, KeyEventArgs e)) { //Do whatever you like with e.Key and Keyboard.Modifiers } 

It's simple

+16
01 Oct '12 at 16:05
source share

I'm not sure about WPF, but that might help. I used the solution described in RegisterHotKey (user32) (of course, it was changed for me) for a C # Windows Forms application to assign CTRL-KEY on Windows to create a C # form, and it worked perfectly (even on Windows Vista). Hope this helps and good luck!

+1
Sep 08 '08 at 0:48
source share

Although RegisterHotKey is sometimes exactly what you want, in most cases you probably do not want to use system-wide hotkeys. I ended up using the code as follows:

 using System.Windows;
 using System.Windows.Interop;

 namespace WpfApp
 {
     public partial class MainWindow: Window
     {
         const int WM_KEYUP = 0x0101;

         const int VK_RETURN = 0x0D;
         const int VK_LEFT = 0x25;  

         public MainWindow ()
         {
             this.InitializeComponent ();

             ComponentDispatcher.ThreadPreprocessMessage + = 
                 ComponentDispatcher_ThreadPreprocessMessage;
         }

         void ComponentDispatcher_ThreadPreprocessMessage (
             ref msg msg, ref bool handled)
         {
             if (msg.message == WM_KEYUP)
             {
                 if ((int) msg.wParam == VK_RETURN)
                     MessageBox.Show ("RETURN was pressed");

                 if ((int) msg.wParam == VK_LEFT)
                     MessageBox.Show ("LEFT was pressed");
             }
         }
     }
 }
+1
Apr 15 '10 at 7:20
source share

I found Global Hotkeys in a WPF project on codeproject.com that does this job for me. This is relatively recent, does not require a link to System.Windows.Forms and works "globally" in terms of responding to hotkey presses, even if "your" application is not an active window.

+1
Jun 14 2018-12-12T00:
source share

This is similar to the answers that have already been given, but I find it cleaner:

 using System; using System.Windows.Forms; namespace GlobalHotkeyExampleForm { public partial class ExampleForm : Form { [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk); [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern bool UnregisterHotKey(IntPtr hWnd, int id); enum KeyModifier { None = 0, Alt = 1, Control = 2, Shift = 4, WinKey = 8 } public ExampleForm() { InitializeComponent(); int id = 0; // The id of the hotkey. RegisterHotKey(this.Handle, id, (int)KeyModifier.Shift, Keys.A.GetHashCode()); // Register Shift + A as global hotkey. } protected override void WndProc(ref Message m) { base.WndProc(ref m); if (m.Msg == 0x0312) { /* Note that the three lines below are not needed if you only want to register one hotkey. * The below lines are useful in case you want to register multiple keys, which you can use a switch with the id as argument, or if you want to know which key/modifier was pressed for some particular reason. */ Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF); // The key of the hotkey that was pressed. KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF); // The modifier of the hotkey that was pressed. int id = m.WParam.ToInt32(); // The id of the hotkey that was pressed. MessageBox.Show("Hotkey has been pressed!"); // do something } } private void ExampleForm_FormClosing(object sender, FormClosingEventArgs e) { UnregisterHotKey(this.Handle, 0); // Unregister hotkey with id 0 before closing the form. You might want to call this more than once with different id values if you are planning to register more than one hotkey. } } } 

I found it on fluxbytes.com .

+1
Nov 19 '15 at 7:10
source share

RegisterHotKey() suggested by John can work - the only catch is that it requires HWND (using PresentationSource.FromVisual() and returning the result in HwndSource).

However, you will also need to respond to the WM_HOTKEY message - I'm not sure if there is a way to access WndProc from a WPF window or not (which can be done for Windows Forms windows).

0
Sep 08 '08 at 3:03
source share

An employee wrote a sample on how to create a low-level keyboard hook for use with WPF.

http://blogs.vertigo.com/personal/ralph/Blog/Lists/Posts/Post.aspx?ID=8

0
Sep 12 '08 at 7:01
source share

Baboon's solution works best because you may have multiple windows. I made it, so it uses PreviewKeyDownEvent instead of PreviewKeyUpEvent to handle keystrokes.

I would advise you to refuse to register at the OS level if you are not writing something like a tool for a cut or application for recording sound, as this will allow you to access functions when the window is not focused.

0
Mar 26 '13 at 19:42
source share



All Articles