Skip to content

Instantly share code, notes, and snippets.

@KOZ60
Last active October 1, 2023 07:28
Show Gist options
  • Save KOZ60/ecba5a99c123410d983980c6239d4ea0 to your computer and use it in GitHub Desktop.
Save KOZ60/ecba5a99c123410d983980c6239d4ea0 to your computer and use it in GitHub Desktop.
Hotkey.vb
Imports System.Collections
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
<DefaultEvent("HotkeyPress")>
Public Class Hotkey
Inherits Component
Private Shared countId As Integer
Private ReadOnly catcher As InternalControl
Private ReadOnly entries As EntryCollcetion
Public Sub New()
catcher = New InternalControl(Me)
entries = New EntryCollcetion
End Sub
Public Sub New(container As IContainer)
Me.New()
If container Is Nothing Then
Throw New ArgumentNullException("container")
End If
container.Add(Me)
End Sub
Public Function Register(keys As Keys, modifiers As Modifiers) As Boolean
Dim entry As Entry = Nothing
If entries.TryGetValue(keys, modifiers, entry) Then
Return True
End If
If RegisterHotKey(catcher.Handle, countId, modifiers, keys) Then
entry = New Entry(countId, keys, modifiers)
entries.Add(entry)
countId += 1
Return True
Else
Return False
End If
End Function
Public Function UnRegister(keys As Keys, modifiers As Modifiers) As Boolean
Dim entry As Entry = Nothing
If Not entries.TryGetValue(keys, modifiers, entry) Then
Return False
End If
entries.Remove(entry)
Return UnregisterHotKey(catcher.Handle, entry.Id)
End Function
Private Sub OnHotkeyPressCaller(wParam As IntPtr)
Dim id = wParam.ToInt32()
Dim entry As Entry = Nothing
If entries.TryGetValue(id, entry) Then
OnHotkeyPress(entry)
End If
End Sub
Protected Overridable Sub OnHotkeyPress(e As HotkeyEventArgs)
If CanRaiseEvents Then
RaiseEvent HotkeyPress(Me, e)
End If
End Sub
Public Event HotkeyPress As EventHandler(Of HotkeyEventArgs)
<Flags>
Public Enum Modifiers
None = 0
Alt = &H1
Control = &H2
Shift = &H4
Winkey = &H8
End Enum
Public Class HotkeyEventArgs
Inherits EventArgs
Public ReadOnly Property Keys As Keys
Public ReadOnly Property Modifiers As Modifiers
Public Sub New(keys As Keys, modifiers As Modifiers)
Me.Keys = keys
Me.Modifiers = modifiers
End Sub
Public Overrides Function ToString() As String
Return $"{Modifiers} + {Keys}"
End Function
End Class
Private Class Entry
Inherits HotkeyEventArgs
Public ReadOnly Property Id As Integer
Public Sub New(id As Integer, keys As Keys, modifiers As Modifiers)
MyBase.New(keys, modifiers)
Me.Id = id
End Sub
End Class
Private Class EntryCollcetion
Implements IEnumerable(Of Entry)
Private ReadOnly dicKey As New Dictionary(Of Tuple(Of Keys, Modifiers), Entry)
Private ReadOnly dicId As New Dictionary(Of Integer, Entry)
Public Sub Clear()
dicKey.Clear()
dicId.Clear()
End Sub
Public Function TryGetValue(id As Integer, ByRef entry As Entry) As Boolean
Return dicId.TryGetValue(id, entry)
End Function
Public Function TryGetValue(keys As Keys, modifiers As Modifiers, ByRef entry As Entry) As Boolean
Dim key = CreateKey(keys, modifiers)
Return dicKey.TryGetValue(key, entry)
End Function
Public Sub Add(ent As Entry)
Dim key = CreateKey(ent.Keys, ent.Modifiers)
dicKey.Add(key, ent)
dicId.Add(ent.Id, ent)
End Sub
Public Sub Remove(ent As Entry)
Dim key = CreateKey(ent.Keys, ent.Modifiers)
dicKey.Remove(key)
dicId.Remove(ent.Id)
End Sub
Private Shared Function CreateKey(keys As Keys, modifiers As Modifiers) As Tuple(Of Keys, Modifiers)
Return New Tuple(Of Keys, Modifiers)(keys, modifiers)
End Function
Public Iterator Function GetEnumerator() As IEnumerator(Of Entry) Implements IEnumerable(Of Entry).GetEnumerator
For Each kp In dicKey
Yield kp.Value
Next
End Function
Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return GetEnumerator()
End Function
End Class
Private Const WM_HOTKEY As Integer = &H312
Private Class InternalControl
Inherits Control
Private ReadOnly Owner As Hotkey
Public Sub New(owner As Hotkey)
Me.Owner = owner
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = WM_HOTKEY Then
Owner.OnHotkeyPressCaller(m.WParam)
Else
MyBase.WndProc(m)
End If
End Sub
End Class
<DllImport("user32", CharSet:=CharSet.Auto)>
Private Shared Function RegisterHotKey(
hwnd As IntPtr, id As Integer,
fsModifiers As Modifiers, vk As Keys) As Boolean
End Function
<DllImport("user32", CharSet:=CharSet.Auto)>
Private Shared Function UnregisterHotKey(hwnd As IntPtr, id As Integer) As Boolean
End Function
Private disposedValue As Boolean
Protected Overrides Sub Dispose(disposing As Boolean)
If Not disposedValue Then
disposedValue = True
If disposing Then
For Each entry In entries
UnregisterHotKey(catcher.Handle, entry.Id)
Next
entries.Clear()
catcher.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
End Class
@KOZ60
Copy link
Author

KOZ60 commented Oct 1, 2023

How to use:
Paste it on form.

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Hotkey1.Register(Keys.C, Hotkey.Modifiers.Control)
    End Sub

    Private Sub Hotkey1_HotkeyPress(sender As Object, e As Hotkey.HotkeyEventArgs) Handles Hotkey1.HotkeyPress
        TextBox1.AppendText(Now & " " & e.ToString() & vbCrLf)
    End Sub

End Class

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