HotkeyManager

Posts 1–5 of 5 · Page 1 of 1
HotkeyManager
Meh, was bored tonight so I whipped up a class to manage your hotkeys.

Straight up, here's the raw source, I'll do some explaining in a sec:

Code:
Imports System.Runtime.InteropServices

Public NotInheritable Class HotkeyManager
    '**************** [Delegates] **************
    Public Delegate Sub HotkeyCallback(ByVal pParams As Object())
    Private Delegate Function HookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
    '************** [End Delegates] ************

    Private Const WH_KEYBOARD_LL As Integer = &HD 'constant for a low-level keyboard hook.

    '********* [Windows API Functions] *********

    <DllImport("user32.dll", CallingConvention:=CallingConvention.Winapi)> _
    Private Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal pHook As HookProc, ByVal hMod As IntPtr, ByVal dwThreadId As UInteger) As IntPtr
    End Function

    <DllImport("user32.dll", CallingConvention:=CallingConvention.Winapi)> _
    Private Shared Function UnhookWindowsHookEx(ByVal hHook As IntPtr) As Integer
    End Function

    <DllImport("user32.dll", CallingConvention:=CallingConvention.Winapi)> _
    Private Shared Function CallNextHookEx(ByVal hhk As IntPtr, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
    End Function
    '******* [End Windows API Functions] *******

    '*********** [Instance Variables] **********
    Private Shared __hhook As IntPtr
    Private Shared __hotkeys As Dictionary(Of Integer, Hotkey)
    Private Shared __ishk As Boolean

    Public Shared Property IsHooked() As Boolean
        Get
            Return HotkeyManager.__ishk
        End Get
        Private Set(ByVal value As Boolean)
            HotkeyManager.__ishk = value
        End Set
    End Property
    '********* [End Instance Variables] ********

    ' Initialize the hook if it isn't already. This has to be called before the hook will work.
    Public Shared Sub Initialize()
        If Not HotkeyManager.IsHooked Then 'check if the hook has already been initialized.
            Dim pBaseModule As ProcessModule = Process.GetCurrentProcess().MainModule
            Dim pBaseAddress As IntPtr = CType(If(pBaseModule IsNot Nothing, pBaseModule.BaseAddress, New IntPtr(0)), IntPtr)

            HotkeyManager.__hhook = SetWindowsHookEx(WH_KEYBOARD_LL, New HookProc(AddressOf KeyboardCallback), pBaseAddress, 0)'attempt to set the hook.
            HotkeyManager.IsHooked = (HotkeyManager.__hhook <> IntPtr.Zero)
            If HotkeyManager.__hotkeys Is Nothing Then
                'if need be, initialize the dictionary for use.
                HotkeyManager.__hotkeys = New Dictionary(Of Integer, Hotkey)()
            End If
        End If
    End Sub

    'turn the manager off, to turn it back on just call Initialize again.
    Public Shared Sub Disable()
        HotkeyManager.IsHooked = (UnhookWindowsHookEx(HotkeyManager.__hhook) <> 0)
    End Sub

    'Unset the hook and reset the key list.
    Public Shared Sub Destroy()
        HotkeyManager.__hotkeys = Nothing
        HotkeyManager.IsHooked = (UnhookWindowsHookEx(HotkeyManager.__hhook) <> 0)
    End Sub

    'internal callback method. Will trigger a hotkey event only when the key is pressed down.
    Private Shared Function KeyboardCallback(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
        Dim l_param As Integer = Marshal.ReadInt32(lParam) 'read the keycode.
        If wParam.ToInt32() = &H100 AndAlso HotkeyManager.__hotkeys.ContainsKey(l_param) Then 'check if this is a keydown, and if the hotkey is internally registered.
            Dim hCallback As HotkeyCallback = HotkeyManager.__hotkeys(l_param).Callback
            hCallback(HotkeyManager.__hotkeys(l_param).Paramet  ers)
        End If
        Return CallNextHookEx(HotkeyManager.__hhook, nCode, wParam, lParam)
    End Function

    'register a hotkey if it doesn't already exist with a provided callback.
    Public Shared Sub RegisterHotkey(ByVal key As Integer, ByVal hkproc As HotkeyCallback, ByVal oParams As Object())
        If Not HotkeyManager.__hotkeys.ContainsKey(key) AndAlso hkproc IsNot Nothing Then
            HotkeyManager.__hotkeys.Add(key, New Hotkey() With {.Callback = hkproc, .Parameters = oParams})
        End If
    End Sub

    'Clear an existing hotkey if it exists.
    Public Shared Sub UnregisterHotkey(ByVal key As Integer)
        If HotkeyManager.__hotkeys.ContainsKey(key) Then
            HotkeyManager.__hotkeys.Remove(key)
        End If
    End Sub

    Private Structure Hotkey
        Public Callback As HotkeyCallback
        Public Parameters As Object()
    End Structure
End Class
Okay, that class encapsulates everything you need for a basic hotkey trigger. Basically the class is a singleton (i.e you can't instantiate it a dickload of times and clog the message queue), which sets a system-wide, low-level hook which monitors the keypresses of the system. You don't really need to know the inner workings of the class but the code's there if you wanna study it and figure out what it does, pretty simple shit.

The main thing you need to know is how to use it.

Because this is a static (shared) class, you don't need to construct it. However, you do need to initialize it at some point to originally set the hook.

Code:
HotkeyManager.Initialize()
And that's it, your HotkeyManager is now active until you call
Code:
HotkeyManager.Destroy() 'this will clear all your registered hotkeys as well as turn off the manager.
'or
HotkeyManager.Disable() 'this will just turn the hotkey manager off, but still retain all your registered hotkeys for the next time you call Initialize()
The next thing you need to know is how to add a new hotkey to the manager. This is fairly simple, all you need is a callback method.
A quick explanation: A callback is a function that is invoked by the HotkeyManager when your hotkey is pressed. The callback method signature must match the following

Code:
<access modifier> Sub <function name>(ByVal <parameter name> As Object())
End Sub
For example:
Code:
Private Sub E_KeyPressed(ByVal params As Object())
End Sub
Is a valid method signature for your callback. The "params" argument is an array of objects that you elect to be passed to your callback when the hotkey is pressed. This is the most generic way I could devise the callback to operate so you can fill in as many parameters as you want of any type.

Okay, now you have a callback function in place, so when the user presses a given key (in my case, "E"), the function "E_KeyPressed" will be called. All that's left to do is register the hotkey with the HotkeyManager

Code:
HotkeyManager.Initialize()
Dim my_key As Integer = CType(Keys.E, Integer) 'I will be using the "E" key as my hotkey.
Dim my_callback As HotkeyManager.HotkeyCallback = new HotkeyManager.HotkeyCallback(AddressOf E_KeyPressed) 'create a new Callback delegate.
Dim my_parameters As String() = {"this", "is", "an", "example"} 'these will be the parameters I pass to E_KeyPressed whenever it's called
HotkeyManager.RegisterHotkey(my_key, my_callback, my_parameters) 'now the hotkey is registered. Press 'E' and the function will be called.
Now, here's a very basic "E_KeyPressed" function:
Code:
Private Sub E_KeyPressed(ByVal params As Object())
    For Each o As Object in params
        Debug.WriteLine(o.ToString())
    Next o
End Sub
Which will basically just print each parameter to the Output window to make sure everything was passed correctly. How you implement your callback is up to you. You don't have to specify any parameters if you aren't going to use them, just put "Nothing" as the argument in RegisterHotkey.

If you have any questions, feel free to ask.

EDIT: New vid.
Like The Usual Epic Tut's By Epic Man !!!
Added a video tutorial. I rendered it in 720p but youtube fucked the quality pretty bad.
Very Nice Jas.
Nice Job bro.
Posts 1–5 of 5 · Page 1 of 1

Post a Reply

Tags for this Thread

None

Talk with us