Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save kirsbo/3b01a1412311e7a1d565 to your computer and use it in GitHub Desktop.
Save kirsbo/3b01a1412311e7a1d565 to your computer and use it in GitHub Desktop.
VB.NET - How to add global hotkeys to applications in VB.NET

Authored in 2010

When you want to make your application do things by the user pressing a hotkey / key combination, even when your application does not have focus, you will need a so called global hotkey. A global hotkey is a form of "keyboard hook" which is a low level way of monitoring the computer for a certain key combination, aka hotkey. Below is a simple class, which let's you register a hotkey and define what code should execute, once the hotkey is pressed.

    Public Class Hotkey

#Region "Declarations - WinAPI, Hotkey constant and Modifier Enum"
        ''' <summary>
        ''' Declaration of winAPI function wrappers. The winAPI functions are used to register / unregister a hotkey
        ''' </summary>
        Private Declare Function RegisterHotKey Lib "user32" _
        (ByVal hwnd As IntPtr, ByVal id As Integer, ByVal fsModifiers As Integer, ByVal vk As Integer) As Integer

        Private Declare Function UnregisterHotKey Lib "user32" (ByVal hwnd As IntPtr, ByVal id As Integer) As Integer

        Public Const WM_HOTKEY As Integer = &H312

        Enum KeyModifier
            None = 0
            Alt = &H1
            Control = &H2
            Shift = &H4
            Winkey = &H8
        End Enum 'This enum is just to make it easier to call the registerHotKey function: The modifier integer codes are replaced by a friendly "Alt","Shift" etc.
#End Region


#Region "Hotkey registration, unregistration and handling"
        Public Shared Sub registerHotkey(ByRef sourceForm As Form, ByVal triggerKey As String, ByVal modifier As KeyModifier)
            RegisterHotKey(sourceForm.Handle, 1, modifier, Asc(triggerKey.ToUpper))
        End Sub
        Public Shared Sub unregisterHotkeys(ByRef sourceForm As Form)
            UnregisterHotKey(sourceForm.Handle, 1)  'Remember to call unregisterHotkeys() when closing your application.
        End Sub
        Public Shared Sub handleHotKeyEvent(ByVal hotkeyID As IntPtr)
            MsgBox("The hotkey was pressed")
        End Sub
#End Region

    End Class

To register a hotkey, you need to call the registerHotkey function of the class Hotkey. If you for example want to register ALT+Q, you can do the following:

Hotkey.RegisterHotKey(Me, "W", Hotkey.KeyModifier.Alt)

The first parameter is the sourceform, essentially your main form. The second parameter is a number ID for the hotkey registration, this can be any integer though with some limitations. Next parameter is the key that needs to be pressed, and the fourth and final is the modifier (alt, shift, control, winkey) if any. For this to work, you will need to add one piece of code to your source form:

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = Hotkey.WM_HOTKEY Then
Hotkey.handleHotKeyEvent(m.WParam)
End If
MyBase.WndProc(m)
End Sub 'System wide hotkey event handling

The above sub captures and sends keyboard messages from the WinAPI to the handleHotKey method in the Hotkey class.

Once you have called Hotkey.RegisterHotkey from your code, the hotkey is registered, and will trigger the code in the Hotkey.handleHotKeyEvent, every time the user presses that specific hotkey.

Note Hotkeys with special keys such as F1-F12, space and similar requires a slightly different approach. The methods are essentially the same, but you will need to retrieve the "virtual key code" of the special key, and use it as a parameter in the Hotkey.registerHotkey method instead of the Asc(triggerKey.toUpper) parameter. Googling "virtual key codes" will get you a list of the codes.

Multiple hotkeys

In the above, we assume only one hotkey is needed. Sometimes you need more than one hotkey. In this case we need a few, small changes to the above code. If you examine our "registerHotkey" method in the Hotkey class, you will notice that the second parameter is a number, in our case "1":

Public Shared Sub registerHotkey(ByRef sourceForm As Form, ByVal triggerKey As String, ByVal modifier As KeyModifier)
            RegisterHotKey(sourceForm.Handle, 1, modifier, Asc(triggerKey.ToUpper))
End Sub

This is an ID for the hotkey we are registering. To add multiple hotkeys we simply need to specify another ID. Let's change our method, so it is possible to manually supply an ID:

Public Shared Sub registerHotkey(ByRef sourceForm As Form, ByVal hotkeyID As Integer, ByVal triggerKey As String, ByVal modifier As KeyModifier)
            RegisterHotKey(sourceForm.Handle, hotkeyID, modifier, Asc(triggerKey.ToUpper))
End Sub

Now, when you call the registerHotkey method in the Hotkey class, you will have to supply a hotkeyID of type integer. This allows you to register multiple hotkeys, using a different ID for each. To register three different hotkeys, you might now use the following method call outside the Hotkey class (for example inside a button.click event:

Private Sub btnRegHotkey_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRegHotkey.Click
        Hotkey.RegisterHotKey(Me, "W", 1, Hotkey.KeyModifier.Alt)
        Hotkey.RegisterHotKey(Me, "E", 2, Hotkey.KeyModifier.Alt)
        Hotkey.RegisterHotKey(Me, "R", 3, Hotkey.KeyModifier.Alt)
End Sub

The above will register both ALT+W, ALT+E and ALT+R as hotkeys. Next, we need to add a little more code to the Hotkey class, in order to handle these different hotkeys. We will handle this using a simple Select Case statement on the hotkey ID. Open the Hotkey class and change the "handleHotKeyEvent" method to reflect the following:

    Public Shared Sub handleHotKeyEvent(ByVal hotkeyID As IntPtr)
Select Case hotkeyID
            Case 1
                MsgBox("The hotkey ALT+W (ID: 1) was pressed")
            Case 2
                MsgBox("The hotkey ALT+E (ID: 2) was pressed")
            Case 3
                MsgBox("The hotkey ALT+R (ID: 3) was pressed")
        End Select
    End Sub

To unregister the hotkeys, when closing your application you'd just change the "unregisterHotkeys" method with all the registered hotkey ID's:

        Public Shared Sub unregisterHotkeys(ByRef sourceForm As Form)
            UnregisterHotKey(sourceForm.Handle, 1)  'Remember to call unregisterHotkeys() when closing your application.
            UnregisterHotKey(sourceForm.Handle, 2) 
            UnregisterHotKey(sourceForm.Handle, 3)
        End Sub

Those relative minor changes is all there is to handling multiple hotkeys in your .NET application.

@nikomonese
Copy link

Thanks for this, really aprecciate it.

If I need to use more than one KeyModifiers like Ctrl Shift Enter, what do I need to change?

@kirsbo
Copy link
Author

kirsbo commented Apr 4, 2020

Hi,

Multiple modifiers are actually just modifiers added together. For example, Alt is &H1 and Control is &H2. If you want both Alt and Control, they can be added together, i.e. &H1 + &H2 = &H3.

For ease of use, we can expand the KeyModifier enum to look like this:

Enum KeyModifier
None = 0
Alt = &H1
Control = &H2
AltAndControl = &H3
Shift = &H4
ShiftAndAlt = &H5
ShiftAndControl = &H6
Winkey = &H8
WinkeyAndAlt = &H9
WinkeyAndControl = &H10
WinkeyAndShift = &H12
End Enum

Hope it helps.

@nikomonese
Copy link

nikomonese commented Apr 4, 2020

Hi,

Multiple modifiers are actually just modifiers added together. For example, Alt is &H1 and Control is &H2. If you want both Alt and Control, they can be added together, i.e. &H1 + &H2 = &H3.

For ease of use, we can expand the KeyModifier enum to look like this:

Enum KeyModifier
None = 0
Alt = &H1
Control = &H2
AltAndControl = &H3
Shift = &H4
ShiftAndAlt = &H5
ShiftAndControl = &H6
Winkey = &H8
WinkeyAndAlt = &H9
WinkeyAndControl = &H10
WinkeyAndShift = &H12
End Enum

Hope it helps.

Thanks you kirsbo, whats represent &H1, &H2, etc?
And what about the INTRO key?
In other side, which is the correct implementation of -virtual keys- that you mention above. I just have to replace the -Asc(triggerKey.ToUpper)- with for example VK_RETURN?

@dcw400
Copy link

dcw400 commented Dec 13, 2022

Hi,

What if what RegisterHotKey adds is the Oemcomma key on the keyboard. Why when I press the key, sendkeys.send doesn't work outputting commas? check out this script

'########

Public Shared Sub registerHotkey(ByRef sourceForm As Form, ByVal triggerKey As Keys, ByVal hotkeyID As Integer, ByVal modifier As KeyModifier)
        RegisterHotKey(sourceForm.Handle, hotkeyID, modifier, triggerKey)
End Sub

Public Shared Sub handleHotKeyEvent(ByVal hotkeyID As IntPtr)
        Select Case hotkeyID
            Case 1
                MsgBox("The hotkey Oemcomma (ID: 1) was pressed")
                SendKeys.Send(",")
            Case 2
                MsgBox("The hotkey Oemcomma+Shift (ID: 2) was pressed")
                SendKeys.Send("<")
        End Select
End Sub

'########

Public Class Form1
    Protected Overrides Sub WndProc(ByRef m As Message)
        If m.Msg = Hotkey.WM_HOTKEY Then
            Hotkey.handleHotKeyEvent(m.WParam) 'Boleh pakai ini atau tidak usah, kalai tidak usah berarti function bernama "handleHotKeyEvent" pada Class "HotKey" tidak perlu di isi
        End If
        MyBase.WndProc(m)
    End Sub 'System wide hotkey event handling

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.KeyPreview = True

        Hotkey.registerHotkey3(Me, Keys.Oemcomma, 1, Hotkey.KeyModifier.None)
        Hotkey.registerHotkey3(Me, Keys.Oemcomma, 2, Hotkey.KeyModifier.Shift)
    End Sub
End Class

Please help

@fng2
Copy link

fng2 commented Feb 7, 2024

What if you don't want this bound to a form? for example I have a visio addin with a lot of forms, but no "main". I want the hotkey to work whether or not a form is visible. Can I simply register using something like "Hotkey.RegisterHotKey(globals.thisaddin.application, "W", Hotkey.KeyModifier.Alt)" ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment