Skip to content

Commit e109484

Browse files
Added LocalKeyboardHook class.
1 parent 4935359 commit e109484

File tree

6 files changed

+318
-12
lines changed

6 files changed

+318
-12
lines changed

InputHelper Library/InputHelper .NET 3.5/InputHelper.vb

Lines changed: 157 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
'| |'
88
'| === COPYRIGHT LICENSE === |'
99
'| |'
10-
'| Copyright (c) 2016-2018, Vincent Bengtsson |'
10+
'| Copyright (c) 2016-2019, Vincent Bengtsson |'
1111
'| All rights reserved. |'
1212
'| |'
1313
'| Redistribution and use in source and binary forms, with or without |'
@@ -465,6 +465,10 @@ Public NotInheritable Class InputHelper
465465
Return New KeyboardHookEventArgs(KeyCode, ScanCode, Extended, If(KeyDown, KeyState.Down, KeyState.Up), Me.Modifiers)
466466
End Function
467467

468+
''' <summary>
469+
''' Initializes a new instance of the KeyboardHook class.
470+
''' </summary>
471+
''' <remarks></remarks>
468472
Public Sub New()
469473
hHook = NativeMethods.SetWindowsHookEx(NativeMethods.HookType.WH_KEYBOARD_LL, HookProcedureDelegate, NativeMethods.GetModuleHandle(Nothing), 0)
470474
If hHook = IntPtr.Zero Then
@@ -507,6 +511,133 @@ Public NotInheritable Class InputHelper
507511
End Class
508512
#End Region
509513

514+
#Region "Local keyboard hook"
515+
''' <summary>
516+
''' A local keyboard hook that raises events when a key is pressed or released in a specific thread.
517+
''' </summary>
518+
''' <remarks></remarks>
519+
Public Class LocalKeyboardHook
520+
Implements IDisposable
521+
522+
''' <summary>
523+
''' Occurs when a key is pressed or held down.
524+
''' </summary>
525+
''' <remarks></remarks>
526+
Public Event KeyDown As EventHandler(Of KeyboardHookEventArgs)
527+
528+
''' <summary>
529+
''' Occurs when a key is released.
530+
''' </summary>
531+
''' <remarks></remarks>
532+
Public Event KeyUp As EventHandler(Of KeyboardHookEventArgs)
533+
534+
Private hHook As IntPtr = IntPtr.Zero
535+
Private HookProcedureDelegate As New NativeMethods.KeyboardProc(AddressOf HookCallback)
536+
537+
Private Modifiers As ModifierKeys = ModifierKeys.None
538+
539+
Private Function HookCallback(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
540+
Dim Block As Boolean = False
541+
542+
If nCode >= NativeMethods.HookCode.HC_ACTION Then
543+
Dim KeyCode As Keys = CType(wParam.ToInt32(), Keys)
544+
Dim KeyFlags As New NativeMethods.DWORD(lParam.ToInt64())
545+
Dim ScanCode As Byte = BitConverter.GetBytes(KeyFlags)(2) 'The scan code is the third byte in the integer (bits 16-23).
546+
Dim Extended As Boolean = (KeyFlags.High And NativeMethods.KeyboardFlags.KF_EXTENDED) = NativeMethods.KeyboardFlags.KF_EXTENDED
547+
Dim AltDown As Boolean = (KeyFlags.High And NativeMethods.KeyboardFlags.KF_ALTDOWN) = NativeMethods.KeyboardFlags.KF_ALTDOWN
548+
Dim KeyUp As Boolean = (KeyFlags.High And NativeMethods.KeyboardFlags.KF_UP) = NativeMethods.KeyboardFlags.KF_UP
549+
550+
'Set the ALT modifier if the KF_ALTDOWN flag is set.
551+
If AltDown = True _
552+
AndAlso InputHelper.IsModifier(KeyCode, ModifierKeys.Alt) = False _
553+
AndAlso (Me.Modifiers And ModifierKeys.Alt) <> ModifierKeys.Alt Then
554+
555+
Me.Modifiers = Me.Modifiers Or ModifierKeys.Alt
556+
End If
557+
558+
'Raise KeyDown/KeyUp event.
559+
If KeyUp = False Then
560+
Dim HookEventArgs As New KeyboardHookEventArgs(KeyCode, ScanCode, Extended, KeyState.Down, Me.Modifiers)
561+
562+
If InputHelper.IsModifier(KeyCode, ModifierKeys.Control) = True Then Me.Modifiers = Me.Modifiers Or ModifierKeys.Control
563+
If InputHelper.IsModifier(KeyCode, ModifierKeys.Shift) = True Then Me.Modifiers = Me.Modifiers Or ModifierKeys.Shift
564+
If InputHelper.IsModifier(KeyCode, ModifierKeys.Alt) = True Then Me.Modifiers = Me.Modifiers Or ModifierKeys.Alt
565+
If InputHelper.IsModifier(KeyCode, ModifierKeys.Windows) = True Then Me.Modifiers = Me.Modifiers Or ModifierKeys.Windows
566+
567+
RaiseEvent KeyDown(Me, HookEventArgs)
568+
Block = HookEventArgs.Block
569+
Else
570+
'Must be done before creating the HookEventArgs during KeyUp.
571+
If InputHelper.IsModifier(KeyCode, ModifierKeys.Control) = True Then Me.Modifiers = Me.Modifiers And Not ModifierKeys.Control
572+
If InputHelper.IsModifier(KeyCode, ModifierKeys.Shift) = True Then Me.Modifiers = Me.Modifiers And Not ModifierKeys.Shift
573+
If InputHelper.IsModifier(KeyCode, ModifierKeys.Alt) = True Then Me.Modifiers = Me.Modifiers And Not ModifierKeys.Alt
574+
If InputHelper.IsModifier(KeyCode, ModifierKeys.Windows) = True Then Me.Modifiers = Me.Modifiers And Not ModifierKeys.Windows
575+
576+
Dim HookEventArgs As New KeyboardHookEventArgs(KeyCode, ScanCode, Extended, KeyState.Up, Me.Modifiers)
577+
578+
RaiseEvent KeyUp(Me, HookEventArgs)
579+
Block = HookEventArgs.Block
580+
End If
581+
End If
582+
583+
Return If(Block, New IntPtr(1), NativeMethods.CallNextHookEx(hHook, nCode, wParam, lParam))
584+
End Function
585+
586+
''' <summary>
587+
''' Initializes a new instance of the LocalKeyboardHook class attached to the current thread.
588+
''' </summary>
589+
''' <remarks></remarks>
590+
Public Sub New()
591+
Me.New(NativeMethods.GetCurrentThreadId())
592+
End Sub
593+
594+
''' <summary>
595+
''' Initializes a new instance of the LocalKeyboardHook class attached to the specified thread.
596+
''' </summary>
597+
''' <param name="ThreadID">The thread to attach the hook to.</param>
598+
''' <remarks></remarks>
599+
Public Sub New(ByVal ThreadID As UInteger)
600+
hHook = NativeMethods.SetWindowsHookEx(NativeMethods.HookType.WH_KEYBOARD, HookProcedureDelegate, IntPtr.Zero, ThreadID)
601+
If hHook = IntPtr.Zero Then
602+
Dim Win32Error As Integer = Marshal.GetLastWin32Error()
603+
Throw New Win32Exception(Win32Error, "Failed to create local keyboard hook! (" & Win32Error & ")")
604+
End If
605+
End Sub
606+
607+
#Region "IDisposable Support"
608+
Private disposedValue As Boolean ' To detect redundant calls
609+
610+
' IDisposable
611+
Protected Overridable Sub Dispose(disposing As Boolean)
612+
If Not Me.disposedValue Then
613+
If disposing Then
614+
' TODO: dispose managed state (managed objects).
615+
End If
616+
617+
' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
618+
' TODO: set large fields to null.
619+
If hHook <> IntPtr.Zero Then NativeMethods.UnhookWindowsHookEx(hHook)
620+
End If
621+
Me.disposedValue = True
622+
End Sub
623+
624+
Protected Overrides Sub Finalize()
625+
' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
626+
Dispose(False)
627+
MyBase.Finalize()
628+
End Sub
629+
630+
' This code added by Visual Basic to correctly implement the disposable pattern.
631+
Public Sub Dispose() Implements IDisposable.Dispose
632+
' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
633+
Dispose(True)
634+
GC.SuppressFinalize(Me)
635+
End Sub
636+
#End Region
637+
638+
End Class
639+
#End Region
640+
510641
#Region "Mouse hook"
511642
''' <summary>
512643
''' A global low-level mouse hook that raises events when a mouse event occurs.
@@ -669,6 +800,10 @@ Public NotInheritable Class InputHelper
669800
Return If(Block, New IntPtr(1), NativeMethods.CallNextHookEx(hHook, nCode, wParam, lParam))
670801
End Function
671802

803+
''' <summary>
804+
''' Initializes a new instance of the MouseHook clas.
805+
''' </summary>
806+
''' <remarks></remarks>
672807
Public Sub New()
673808
hHook = NativeMethods.SetWindowsHookEx(NativeMethods.HookType.WH_MOUSE_LL, HookProcedureDelegate, NativeMethods.GetModuleHandle(Nothing), 0)
674809
If hHook = IntPtr.Zero Then
@@ -1563,18 +1698,27 @@ Public NotInheritable Class InputHelper
15631698
#End Region
15641699

15651700
#Region "WinAPI P/Invokes"
1566-
Private NotInheritable Class NativeMethods
1701+
''' <summary>
1702+
''' A class containing all the native WinAPI methods, structures, declarations, etc. used by InputHelper.
1703+
''' </summary>
1704+
''' <remarks></remarks>
1705+
Public NotInheritable Class NativeMethods
15671706
Private Sub New()
15681707
End Sub
15691708

15701709
#Region "Delegates"
1710+
Public Delegate Function KeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
15711711
Public Delegate Function LowLevelKeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
15721712
Public Delegate Function LowLevelMouseProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
15731713
#End Region
15741714

15751715
#Region "Methods"
15761716

15771717
#Region "Hook methods"
1718+
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
1719+
Public Shared Function SetWindowsHookEx(ByVal idHook As HookType, ByVal lpfn As KeyboardProc, ByVal hMod As IntPtr, ByVal dwThreadId As UInteger) As IntPtr
1720+
End Function
1721+
15781722
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
15791723
Public Shared Function SetWindowsHookEx(ByVal idHook As HookType, ByVal lpfn As LowLevelKeyboardProc, ByVal hMod As IntPtr, ByVal dwThreadId As UInteger) As IntPtr
15801724
End Function
@@ -1693,6 +1837,15 @@ Public NotInheritable Class InputHelper
16931837
HC_NOREMOVE = 3
16941838
End Enum
16951839

1840+
Public Enum KeyboardFlags As UInteger
1841+
KF_EXTENDED = &H100
1842+
KF_DLGMODE = &H800
1843+
KF_MENUMODE = &H1000
1844+
KF_ALTDOWN = &H2000
1845+
KF_REPEAT = &H4000
1846+
KF_UP = &H8000
1847+
End Enum
1848+
16961849
Public Enum LowLevelKeyboardHookFlags As UInteger
16971850
LLKHF_EXTENDED = &H1
16981851
LLKHF_LOWER_IL_INJECTED = &H2
@@ -1970,8 +2123,8 @@ Public NotInheritable Class InputHelper
19702123
Public y As Integer
19712124

19722125
Public Sub New(ByVal X As Integer, ByVal Y As Integer)
1973-
Me.X = X
1974-
Me.Y = Y
2126+
Me.x = X
2127+
Me.y = Y
19752128
End Sub
19762129
End Structure
19772130
#End Region

InputHelper Library/InputHelper .NET 3.5/LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
| |
88
| === COPYRIGHT LICENSE === |
99
| |
10-
| Copyright (c) 2016-2018, Vincent Bengtsson |
10+
| Copyright (c) 2016-2019, Vincent Bengtsson |
1111
| All rights reserved. |
1212
| |
1313
| Redistribution and use in source and binary forms, with or without |

InputHelper Library/InputHelper .NET 3.5/My Project/AssemblyInfo.vb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Imports System.Runtime.InteropServices
1414
<Assembly: AssemblyDescription("A .NET friendly library for simulating mouse and keyboard input.")>
1515
<Assembly: AssemblyCompany("My DOOM site")>
1616
<Assembly: AssemblyProduct("InputHelper")>
17-
<Assembly: AssemblyCopyright("Copyright © Vincent Bengtsson 2016-2018")>
17+
<Assembly: AssemblyCopyright("Copyright © Vincent Bengtsson 2016-2019")>
1818
<Assembly: AssemblyTrademark("")>
1919

2020
<Assembly: ComVisible(False)>

0 commit comments

Comments
 (0)