• (2 Pages)
  • +
  • 1
  • 2

Global Hotkeys Register a hotkey that is triggered even when form isn't focused.

#1 Curtis Rutland  Icon User is online

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4422
  • View blog
  • Posts: 7,690
  • Joined: 08-June 10

Posted 06 July 2010 - 10:27 AM

*
POPULAR

Edit: Hi all, I've updated my examples and library since this tutorial was written. For the latest version, please check my github project. It has an example as well. This tutorial is still valid, to show you how to use the hotkeys, but if you want a more complete library, check out my repo.

Sometimes, your form may need to respond to a hotkey even when it is not focused. There is no built in .NET functionality that allows for this, but it is built into the Win32 API. Today we'll learn to write a library to allow us to use this feature.

First, how do you call a method from the Win32 API? It's not written in .NET, but C/C++. Well, .NET provides a way to call methods defined in non-native libraries: Platform Invocation.

The methods we are interested are defined in the user32.dll. RegisterHotKey and UnregisterHotKey.

I've provided the source in both C# and VB.NET projects, zipped and attached. Download them if you want to follow along.

Let's start by creating a new Class Library called Hotkeys. In this library, create a public class called GlobalHotkey. Add a reference to System.Windows.Forms, and add the following using statements at the top:
using System.Windows.Forms;
using System.Runtime.InteropServices;


Now define the important methods: the external hotkey methods:
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);

[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);


Note that you're not providing a method body. The method is defined in user32.dll, you're just adding a way for your application to directly call that method. FYI, hWnd refers to the window handle (we will pass our form's handle), id is the unique identifier of the hotkey, fsModifiers is the integer representation of the modifier keys (shift/alt/ctrl/win) that you want pressed with your key, and vk is the virtual key code for the hotkey.

Now, we can start building the class around these methods. First, lets add the fields we want in the class:
private int modifier;
private int key;
private IntPtr hWnd;
private int id;


Now the constructor:
public GlobalHotkey(int modifier, Keys key, Form form)
{
    this.modifier = modifier;
    this.key = (int)key;
    this.hWnd = form.Handle;
    id = this.GetHashCode();
}

In the constructor, we set all our fields to their proper values. Note that we are requiring that the caller pass in a reference to a System.Windows.Form. That is so we can grab the handle from that form. Also, we are calling GetHashCode to create the unique id. But we must override this method to make it useful to us:
public override int GetHashCode()
{
    return modifier ^ key ^ hWnd.ToInt32();
}

What we're doing here is combining the fields via XOR as suggested by the MSDN.

Now we create the two public methods. We want the user to be able to register and unregister these hotkeys whenever they want, so that's why we make them public methods:
public bool Register()
{
    return RegisterHotKey(hWnd, id, modifier, key);
}

public bool Unregiser()
{
    return UnregisterHotKey(hWnd, id);
}


And that's basically it. Your library is ready to use as is. Your code file should look like this. But for simplicity's sake, let's add a Constants class to make it easier to use:
namespace Hotkeys
{
    public static class Constants
    {
        //modifiers
        public const int NOMOD = 0x0000;
        public const int ALT = 0x0001;
        public const int CTRL = 0x0002;
        public const int SHIFT = 0x0004;
        public const int WIN = 0x0008;

        //windows message id for hotkey
        public const int WM_HOTKEY_MSG_ID = 0x0312;
    }
}


This file defines some useful values that we will need to actually define and use hotkeys.

=================USAGE============================

Now, let's use the library we just created in a Windows Forms application. Add a new project to your solution, and call it HotkeysWin. Add a reference to your library in the forms project. You should be able to see your library in the "Projects" tab of the Add Reference dialog.

Add handlers for your form's Load and FormClosing events. You can do this by clicking the lightning bold in the properties window, and double-clicking the appropriate entries.

Add a multiline TextBox to your form.

Now for the codebehind:
using System;
using System.Windows.Forms;
using Hotkeys;

namespace HotkeyWin
{
    public partial class Form1 : Form
    {
        private Hotkeys.GlobalHotkey ghk;

        public Form1()
        {
            InitializeComponent();
            ghk = new Hotkeys.GlobalHotkey(Constants.ALT + Constants.SHIFT, Keys.O, this);
        }

        private void HandleHotkey()
        {
            WriteLine("Hotkey pressed!");
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == Hotkeys.Constants.WM_HOTKEY_MSG_ID)
                HandleHotkey();
            base.WndProc(ref m);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            WriteLine("Trying to register SHIFT+ALT+O");
            if (ghk.Register())
                WriteLine("Hotkey registered.");
            else
                WriteLine("Hotkey failed to register");
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!ghk.Unregiser())
                MessageBox.Show("Hotkey failed to unregister!");
        }

        private void WriteLine(string text)
        {
            textBox1.Text += text + Environment.NewLine;
        }
    }
}


Notice in the constructor how we create a new hotkey:
ghk = new Hotkeys.GlobalHotkey(Constants.ALT + Constants.SHIFT, Keys.O, this);

You add modifiers to your hotkey by adding their values. So if you wanted to declare one that used CTRL+ALT+F, you would use it like this:
ghk = new Hotkeys.GlobalHotkey(Constants.CTRL + Constants.ALT, Keys.F, this);

To declare one with only one modifier, just use the value without adding it to anything. To use no modifier key, do this:
ghk = new Hotkeys.GlobalHotkey(Constants.NOMOD, Keys.O, this);

But be careful when doing this. If you bind your form to a hotkey that is just a letter key, it may interfere with the operation of other applications.

Also notice that we override the WndProc method. This is the method that is called to handle all windows messages. We've defined the ID of the message we're looking for in Hotkeys.Constants.WM_HOTKEY_MSG_ID. So we specifically want to take action when that message comes through.

I hope this has been enlightening. Look out for the VB.NET version, coming soon. I'll add a link when it is up.

Attached File(s)



Is This A Good Question/Topic? 9
  • +

Replies To: Global Hotkeys

#2 reaper4334  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 16
  • View blog
  • Posts: 107
  • Joined: 01-November 09

Posted 11 July 2010 - 08:37 AM

Great tutorial!
After using this I decided to port one of my previous key-shortcut apps that worked using a global key hook, and it worked great following this tutorial.

Also, I thought it might be helpful to add:

It is possible to have multiple hotkey hook in the same application, and if you try it you may notice they all fire the same event as they all give the same Message.
The way to tell them apart is to determine which key was pressed (not including modifiers such as Ctrl, Alt, Shift. Just the key e.g. A) using the "high-order word" of the LParam property of the Message.

My code to do this:

private Keys GetKey(IntPtr LParam)
{
    return (Keys)((LParam.ToInt32()) >> 16); // not all of the parenthesis are needed, I just found it easier to see what's happening
}



so this would be used in the WndProc override like so:

protected override void WndProc(ref Message m)
        {
            if (m.Msg == Constants.WM_HOTKEY_MSG_ID)
            {
                switch (GetKey(m.lParam))
                {
                    case Keys.A:
                        // the hotkey key is A
                        break;
            }
            base.WndProc(ref m);
        }



(I just typed that without debugging so it might not be 100% correct, but you should get the idea)
Was This Post Helpful? 4
  • +
  • -

#3 Guest_supersniper*


Reputation:

Posted 07 September 2010 - 07:25 AM

I can't get this to work for more than one hotkey

under hotkey handle
i try to make an if statement to specify each function for the hotkey but i simply cannot get it work because it's not a bool type.
Was This Post Helpful? 0

#4 hassankahrizy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 21-March 11

Posted 21 March 2011 - 04:22 AM

In The Name Of God
hi
Thanks

I want to determin this key code by User Not in My Code
But I need to select Ctrl Or Alt Or Shift . How to detect this
thanks
Was This Post Helpful? 0
  • +
  • -

#5 Curtis Rutland  Icon User is online

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4422
  • View blog
  • Posts: 7,690
  • Joined: 08-June 10

Posted 21 March 2011 - 07:36 AM

I'm not sure what you mean. Can you clarify your question?
Was This Post Helpful? 0
  • +
  • -

#6 hassankahrizy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 21-March 11

Posted 21 March 2011 - 06:02 PM

View PostinsertAlias, on 21 March 2011 - 07:36 AM, said:

I'm not sure what you mean. Can you clarify your question?

In The Name Of God
Hi to everyone
In Your Good tutorial, "It is not possible to have multiple hotkey hook in the same application"
"reaper4334" write code for "multiple hotkey in the same application" .But code's "reaper4334" can't detect modifiers Keys.
How detect Modifier Keys in code's "reaper4334"

HGetKey(m.lParam)
Was This Post Helpful? 0
  • +
  • -

#7 Curtis Rutland  Icon User is online

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4422
  • View blog
  • Posts: 7,690
  • Joined: 08-June 10

Posted 21 March 2011 - 07:41 PM

Here's the WndProc method I've used in another application that gets both the key and the modifier:

        protected override void WndProc(ref Message m) {
            if (m.Msg == Constants.HotkeyWMId) {
                Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);
                int modifier = (int)m.LParam & 0xFFFF;
                if (modifier == Constants.NoMod)
                    CaptureAll();
                else if (modifier == Constants.Alt)
                    CaptureActiveWindow();
                else if (modifier == Constants.Ctrl)
                    //CaptureRange();
                    CaptureRange();
            }
            base.WndProc(ref m);
        }


In this, I'm not testing the key, since I've only registered one, but I am testing the modifier. But I've extracted both (key and modifier). You can test both to see if they match what you want.
Was This Post Helpful? 1
  • +
  • -

#8 hassankahrizy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 21-March 11

Posted 21 March 2011 - 08:09 PM

In The Name Of God
Hi to everyone
I write program for that
thanks

Attached File(s)


Was This Post Helpful? 0
  • +
  • -

#9 robat7  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 03-August 11

Posted 03 August 2011 - 09:51 AM

Hi there,
I used to use this code when I was debugging my codes in Win 32 bit, now I have to use this code in my application in Win 64 bit, but it does not work.
Any idea?
I have a class (HotKeys) See below
I define below variables in my form
Hotkeys ghk;
Hotkeys ghk1;
Hotkeys ghk2;
in constructor I define keys
            ghk = new Hotkeys(Hotkeys.Constants.CTRL, Keys.NumPad1, this);
            ghk1 = new Hotkeys(Hotkeys.Constants.CTRL + Hotkeys.Constants.ALT, Keys.M, this);
            ghk2 = new Hotkeys(Hotkeys.Constants.CTRL + Hotkeys.Constants.ALT, Keys.D, this);

in Form load I register keys
            ghk.Register();
            ghk1.Register();
            ghk2.Register();

=============== class Hotkeys ==========================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace xyz
{
    class Hotkeys
    {
        //http://www.dreamincode.net/forums/topic/180436-global-hotkeys/
        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);

        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);


        private int modifier;
        private int key;
        private IntPtr hWnd;
        private int id;

        public static class Constants
        {
            //modifiers
            public const int NOMOD = 0x0000;
            public const int ALT = 0x0001;
            public const int CTRL = 0x0002;
            public const int SHIFT = 0x0004;
            public const int WIN = 0x0008;

            //windows message id for hotkey
            public const int WM_HOTKEY_MSG_ID = 0x0312;
        }

        public Hotkeys(int modifier, Keys key, Form form)
        {
            this.modifier = modifier;
            this.key = (int)key;
            this.hWnd = form.Handle;
            id = this.GetHashCode();
        }
        public override int GetHashCode()
        {
            return modifier ^ key ^ hWnd.ToInt32();
        }
        public bool Register()
        {
            return RegisterHotKey(hWnd, id, modifier, key);
        }

        public bool Unregiser()
        {
            return UnregisterHotKey(hWnd, id);
        }

    }
}



Mod edit - Please
:code:

This post has been edited by Curtis Rutland: 26 June 2013 - 02:19 PM

Was This Post Helpful? 0
  • +
  • -

#10 mikkeljr  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 04-April 12

Posted 04 April 2012 - 02:42 PM

Hi great tutorial
got quick question
Why can i not change this line
ghk = new Hotkeys.GlobalHotkey(Constants.CTRL + Constants.ALT, Keys.F, this);


into this where its triggered by left mouse button
ghk = new Hotkeys.GlobalHotkey(Constants.CTRL, Keys.LButton, this);


it dosnt come with an error it just completly ignore the mouse click
Was This Post Helpful? 0
  • +
  • -

#11 Curtis Rutland  Icon User is online

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4422
  • View blog
  • Posts: 7,690
  • Joined: 08-June 10

Posted 05 April 2012 - 04:54 AM

Well, I'm not an expert, but it's likely that mouse events don't send the WM_HOTKEY message. You might try a different message. Look my name up (curtisrutland) on GitHub, and check my Low Level Hooks project out. It might be more what you're looking for.
Was This Post Helpful? 0
  • +
  • -

#12 Curtis Rutland  Icon User is online

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4422
  • View blog
  • Posts: 7,690
  • Joined: 08-June 10

Posted 11 May 2012 - 03:42 PM

I've updated and added my code to my LowLevelHooks project on GitHub:

https://github.com/c...d/LowLevelHooks

It's in the GlobalHotkey and GlobalHotkey.Test projects!
Was This Post Helpful? 0
  • +
  • -

#13 EagleEye  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 25-April 12

Posted 23 May 2012 - 05:23 AM

Hi great tutorial Curtis,

But i have some trouble when i try to open the project file in the 'GlobalHotkeys.Test' folder.

I get this error below.
Warning 3 The referenced component 'GlobalHotkeys' could not be found.

What am i missing?
Was This Post Helpful? 0
  • +
  • -

#14 Curtis Rutland  Icon User is online

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4422
  • View blog
  • Posts: 7,690
  • Joined: 08-June 10

Posted 23 May 2012 - 06:05 AM

Well, first start by opening the solution file rather than the project file. And if it doesn't work, try re-adding the references. Last resort, delete the Test project, since the important code is in the GlobalHotkeys project.
Was This Post Helpful? 0
  • +
  • -

#15 EagleEye  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 25-April 12

Posted 23 May 2012 - 07:19 AM

View PostCurtis Rutland, on 23 May 2012 - 06:05 AM, said:

Well, first start by opening the solution file rather than the project file. And if it doesn't work, try re-adding the references. Last resort, delete the Test project, since the important code is in the GlobalHotkeys project.


Thanks Curtis,

I works fine when i open the solution file in Visual Studio 2010. (I used Visual C# 2008). I will try to see if i can finds out how to use it in my application.

Thanks!
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2