Hotkeys Binding in C# Windows Application

At this time our team developing small desktop application which should improve productivity of QA by allowing them to post bugs with attached pictures in ‘one click’. The background idea of this app is that when QA Engineer found a bug he/she presses the special hotkey which starts our application, mark a bugplace, fill bug name/description and submit the bug. The application helps to avoid next typical actions of any QA engineer:

  • Press Ctrl + Print Screen
  • Open Paint
  • Ctrl + V into Paint
  • Mark a bug
  • Crop a bug
  • Save picture as (with selecting of folder of course…)
  • Create bug and attach there picture (browsing folders again!)

The problem is that C# does not have solution to bind hotkey through its API. Quick search in Internet allowed creating basic solution. Fist it is need to import two Win API functions to register/unregister Hotkeys in System.

[DllImport("user32.dll", SetLastError = true)]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, Keys vk);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

Since these functions requiring HWND we need add support of Windows Handle in our code.

  private IntPtr handle;
  public IntPtr Handle
  {
   get { return handle; }
   set { handle = value; }
  }

Now Hotkeys can be registered by calling

  RegisterHotKey(handle, id, modifier, key);

where id is unique identifier for hotkey for this thread.

We also need to handle windows message when hot will be pressed in our application. To do this we inheriting our class from IMessageFilter and creating handler of messages:

  public bool PreFilterMessage(ref Message m)
  {
   switch (m.Msg)
   {
    case WM_HOTKEY:
     // rise event from here
     return true;
   }
   return false;
  }

where WM_HOTKEY is 0x0312.

Finally our class will look like bellow. The class is created exclusively for one Hotkey assignment for whole application, however it may be easily expanded for any keys count.

 class HotKey : IMessageFilter
 {


  [DllImport("user32.dll", SetLastError = true)]
  private static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, Keys vk);
  [DllImport("user32.dll", SetLastError = true)]
  private static extern bool UnregisterHotKey(IntPtr hWnd, int id);


  public enum KeyModifiers
  {
   None = 0,
   Alt = 1,
   Control = 2,
   Shift = 4,
   Windows = 8
  }

  private const int WM_HOTKEY = 0x0312;
  private const int id = 100;


  private IntPtr handle;
  public IntPtr Handle
  {
   get { return handle; }
   set { handle = value; }
  }

  private event EventHandler HotKeyPressed;

  public HotKey(Keys key, KeyModifiers modifier, EventHandler hotKeyPressed)
  {
   HotKeyPressed = hotKeyPressed;
   RegisterHotKey(key, modifier);
   Application.AddMessageFilter(this);
  }

  ~HotKey()
  {
   Application.RemoveMessageFilter(this);
   UnregisterHotKey(handle, id);
  }


  private void RegisterHotKey(Keys key, KeyModifiers modifier)
  {
   if (key == Keys.None)
    return;

   bool isKeyRegisterd = RegisterHotKey(handle, id, modifier, key);
   if (!isKeyRegisterd)
    throw new ApplicationException("Hotkey allready in use");
  }



  public bool PreFilterMessage(ref Message m)
  {
   switch (m.Msg)
   {
    case WM_HOTKEY:
     HotKeyPressed(this, new EventArgs());
     return true;
   }
   return false;
  }

 }


Categories

Tags

Additional Resources