Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Simple steps to enable Hotkey and ShortcutInput user control

0.00/5 (No votes)
21 Jan 2004 2  
Follow these simple steps to enable a hotkey for your Windows Form. Use this user control to allow the user to specify their desired hotkey.

Introduction

I wanted to include a Hotkey facility in one of my tray applications - which I had been putting off for some time, since I didn't want to get dirty with Win32 API calls etc. When I finally tackled it, it proved to be a lot simpler than I thought. I also chucked together a little user control that I hope some of you will find useful. The control allows the user to specify their desired Hotkey, and has useful properties that will get you Hotkey-ing in no time.

Background

This article [^] is an alternative way to implement Hotkeys - it's a helper class which is totally separate to your form. However, it uses the Shortcut enum, as opposed to the Keys enum (which supports 3 simultaneous modifiers). Also I'm hoping to show that you can easily add Hotkeys to your form yourself.

Adding a Hotkey to your form in a 4 simple steps

  1. Import the Interop namespace, since we have to call a Win32 API function to register the Hotkey.
    using System.Runtime.InteropServices;
    
  2. Add these static external methods to your form (or a separate class if you prefer).
    [DllImport("user32.dll")]
    public static extern bool RegisterHotKey(IntPtr hWnd,
      int id,int fsModifiers,int vlc);
    [DllImport("user32.dll")]
    public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
    
  3. Listen for the Hotkey windows message, by examining all windows messages passed to the form. Replace this.Activate() with your desired response to the Hotkey (eg: show the form, if you have a tray application).
    protected override void WndProc(ref Message m)
    {
       if (m.Msg == 0x0312)
          this.Activate();
       base.WndProc(ref m);
    }
    
  4. Now register your Hotkey. The first argument is the handle to this form (window). The second is, as far as I can make out, a code to identify your Hotkey. The third argument specifies which modifier keys to register (just add up the numbers in the comments depending on your desired combination). The fourth argument is the character code of the alphanumeric key (or even other keys). If you are specifying a letter, it must be uppercase.
    // Alt = 1, Ctrl = 2, Shift = 4, Win = 8
    
    FrmStartup.RegisterHotKey(this.Handle, 
      this.GetType().GetHashCode(), 3, (int)'J');
    

Note that the RegisterHotKey Win32 API call returns true/false depending on the success of the call. It will fail if another application has already registered that Hotkey, or if you register the same Hotkey twice for your application.

Unregistering a Hotkey

Assuming you followed the steps above, just call:

FrmStartup.UnregisterHotKey(this.Handle, this.GetType().GetHashCode());

No need to specify the key combination, that's what the identifier is for. As far as I can tell, you don't strictly need to unregister the Hotkey when your application closes. There was no difference in my testing, but to be safe you probably should.

The ShortcutInput user control

This user control provides some useful functionality not just for allowing the user to specify their desired shortcut key, but also getting the modifier total and character code (required for registering a Hotkey) from a Keys enumeration instance. The handy thing about the Keys enum is that it is essentially just an integer, which can easily be saved in a config or text file.

Features

  • Allows combination of 3 modifier keys (Shift, Control, Alt)
  • You can set the minimum number of modifiers you require the use to check, and then access the IsValid property to validate.
  • Just set the Keys property and the checkboxes and dropdownlist are automatically selected. Now since the Keys enum is basically an integer, that just leaves you to store/retrieve that number for a file and register the Hotkey.

Limitations

  • The main limitation is that this control does not allow the user to actually press their key combination to specify it. This input type is offered by a lot of applications, and is something I may attempt in the future.
  • Character can only be alphanumeric (i.e. no support for multimedia keys etc)
  • No Win key support. There are a few reasons for this: 1) The Keys enum has an LWin & RWin but they are not modifier keys and so cannot be combined with other keys. 2) usability: even though most keyboards now have this key, the labeling is not standardized (for example mine says "Start"), and you would have to explain to the user what the Win key is. 3) three modifiers are sufficient.
  • I coded a pretty rudimentary method to extract the character code from a Keys enum instance. I wouldn't go so far as to call it a "hack" since it will work fine for alphanumeric keys - which is all I needed for this control. But theoretically I should be using bit masks etc. to separate the modifiers and the key character properly.

Using ShortcutInput user control

Add the user control to your toolbox like you normally would. If you're not sure how to do this, here is one way: copy the user control source file to your application, rebuild. Right-click the toolbox, select Add/Remove Items. Browse to your just-rebuilt assembly, and select it. The user control should then appear at the bottom of your toolbox.

When you load your form you'll need to register your Hotkey, since it does not persist after you close your application.

int val = GetHotkeySetting();
Keys k = (Keys) val;
bool success = FrmMain.RegisterHotKey(this.Handle, 
               this.GetType().GetHashCode(),
               ShortcutInput.Win32ModifiersFromKeys(k),
               ShortcutInput.CharCodeFromKeys(k));

val would be the integer you stored in your settings file. Then you'll notice the two static methods of ShortcutInput that are called to return the modifiers total separately from the character code.

Now when the user needs to change their Hotkey, on your settings form, place the control using the designer as you normally would, then at runtime your form would have to set the Keys property as follows:

int val = GetSerializedInteger();
Keys k = (Keys) val;
ShortcutInput1.Keys = k;

Setting the Keys property will then select the correct checkboxes and the dropdownlist.

Then when the user clicks Apply, you'll need to register the new Hotkey based on the user's selection:

bool success = FrmMain.RegisterHotKey(this.Handle, 
              this.GetType().GetHashCode(),
              ShortcutInput1.Win32Modifiers,
              ShortcutInput1.CharCode);

I think the properties accessed here are self-explanatory.

Then I'll just demonstrate using the minimum modifiers validation, so you can require the user to, say, select at least 2 modifiers:

ShortcutInput1.MinModifiers = 2;

Then check the validity:

bool valid = ShortcutInput1.IsValid;

For completeness, I'll list the remaining 3 minor properties. They return whether each modifier was selected.

bool one = ShortcutInput1.Shift;
bool two = ShortcutInput1.Control;
bool three = ShortcutInput1.Alt;

Some notes about the Keys enum

As I mentioned I used a rudimentary solution to get the character codes from a Keys enum instance. The .NET documentation says: "The four right digits of a key value contain modifier bits for the SHIFT, CONTROL, and ALT keys". Well since the ALT value is 262144, and is more than 4 digits, this is a bit confusing. The conclusion that I've come to (but haven't investigated) is that the first 2 bytes hold the modifiers, and the last 2 bytes hold the key character. Can someone confirm whether this is the case?

So what I did was use the ToString() return value to get the character code. For example: "A, Alt" = A key, "D1, Shift, Control" = digit 1 key etc. Here are some values of key combinations. The first column is the C# code, the second is the ToString() value, and the third is the integer value.

Keys.A | Keys.Alt  // -  A, Alt  -  262209

Keys.D1 | Keys.Control | Keys.Shift  // -  D1, Shift, Control  -  196657

Keys.LWin | Keys.Alt  // -  LWin, Alt  -  262235

Keys.A | Keys.B  // -  C  -  67

Keys.Z | Keys.LWin  // -  LWin  -  91

Keys.ControlKey  // -  ControlKey  -  17

Keys.BrowserBack  // -  BrowserBack  -  166

Line 4 shows that you cannot combine character keys. Line 5 shows that the Windows Key is not a modifier key

Points of Interest

This is my first article on CP. Feedback & comments are welcome.

History

  • 21 Jan 2004 - Original article

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here