Vb Net - Low Level Keyboard Hook (Global)
Installing a Low Level Keyboard Hook
KeyBoardHookYeah!
Below is the basic class you need in order to Hook the Keyboard:
Private Class KeyboardHook
”Constants
Private Const HC_ACTION As Integer = 0
Private Const WH_KEYBOARD_LL As Integer = 13
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Private Const WM_SYSKEYDOWN = &H104
Private Const WM_SYSKEYUP = &H105
”Keypress Structure
Public Structure KBDLLHOOKSTRUCT
Public vkCode As Integer
Public scancode As Integer
Public flags As Integer
Public time As Integer
Public dwExtraInfo As Integer
End Structure
”API Functions
Private Declare Function SetWindowsHookEx Lib “user32″ Alias “SetWindowsHookExA” (ByVal idHook As Integer, ByVal lpfn As KeyboardProcDelegate, ByVal hmod As Integer, ByVal dwThreadId As Integer) As Integer
Private Declare Function CallNextHookEx Lib “user32″ (ByVal hHook As Integer, ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As KBDLLHOOKSTRUCT) As Integer
Private Declare Function UnhookWindowsHookEx Lib “user32″ (ByVal hHook As Integer) As Integer
”Our Keyboard Delegate
Private Delegate Function KeyboardProcDelegate(ByVal nCode As Integer, ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As Integer
”The KeyPress event
Public Shared Event KeyDown(ByVal vkCode As Integer)
Public Shared Event KeyUp(ByVal vkCode As Integer)
”The identifyer for our KeyHook
Private Shared KeyHook As Integer
”KeyHookDelegate
Private Shared KeyHookDelegate As KeyboardProcDelegate
Public Sub New()
”Installs a Low Level Keyboard Hook
KeyHookDelegate = New KeyboardProcDelegate(AddressOf KeyboardProc)
KeyHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyHookDelegate, Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0)).ToInt32, 0)
End Sub
Private Shared Function KeyboardProc(ByVal nCode As Integer, ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As Integer
”If it is a keypress
If (nCode = HC_ACTION) Then
Select Case wParam
”If it is a Keydown Evend
Case WM_KEYDOWN, WM_SYSKEYDOWN
”Activates the KeyDown event in Form 1
RaiseEvent KeyDown(lParam.vkCode)
Case WM_KEYUP, WM_SYSKEYUP
”Activates the KeyUp event in Form 1
RaiseEvent KeyUp(lParam.vkCode)
End Select
End If
”Next
Return CallNextHookEx(KeyHook, nCode, wParam, lParam)
End Function
Protected Overrides Sub Finalize()
”On close it UnHooks the Hook
UnhookWindowsHookEx(KeyHook)
MyBase.Finalize()
End Sub
End Class
The important part to notice is in the KeyboardProc:
Select Case wParam
”If it is a Keydown Evend
Case WM_KEYDOWN, WM_SYSKEYDOWN
”Activates the KeyDown event in Form 1
RaiseEvent KeyDown(lParam.vkCode)
Case WM_KEYUP, WM_SYSKEYUP
”Activates the KeyUp event in Form 1
RaiseEvent KeyUp(lParam.vkCode)
End Select
This is the code that will fire up the KeyDown or KeyUp events, in these two subs:
Private Shadows Sub KeyUp(ByVal KeyCode As Integer) Handles KeyHook.KeyUp
Dim cha As Char = ChrW(KeyCode)
My.Computer.FileSystem.WriteAllText(“logU.txt”, cha, True)
End Sub
Private Shadows Sub KeyDown(ByVal KeyCode As Integer) Handles KeyHook.KeyDown
Dim cha As Char = ChrW(KeyCode)
My.Computer.FileSystem.WriteAllText(“logD.txt”, cha, True)
End Sub
This will basically convert the key that was pressed to its char equivalent, and then save it to a log file, however this isn’t suitable for all the keys (E.g. space, ctrl, alt, shift, etc) as they do not have char characters.
Now, I thought for a while about what the best way to create a proper log would be, and I kind of gave up of doing it a clever way, so I replaced the code inside of the two events with:
Dim str As String = “”
If KeyCode = 27 Then
str = “{Esc}”
ElseIf KeyCode = &H3 Then
str = “{Cancel}”
ElseIf KeyCode = &H8 Then
str = “{Backspace}”
ElseIf KeyCode = &H9 Then
str = “{Tab}”
ElseIf KeyCode = &HC Then
str = “{Clear}”
ElseIf KeyCode = &HD Then
str = “{Enter}” & vbNewLine
ElseIf KeyCode = &H10 Then
str = “{Shift}”
ElseIf KeyCode = &H11 Then
str = “{Ctrl}”
ElseIf KeyCode = &H12 Then
str = “{Menu}”
ElseIf KeyCode = &H13 Then
str = “{Pause}”
ElseIf KeyCode = &H14 Then
str = “{Caps Lock}”
ElseIf KeyCode = &H20 Then
str = ” “
ElseIf KeyCode = &H21 Then
str = “{Page Up}”
ElseIf KeyCode = &H22 Then
str = “{Page Down}”
ElseIf KeyCode = &H23 Then
str = “{End}”
ElseIf KeyCode = &H24 Then
str = “{Home}”
ElseIf KeyCode = &H25 Then
str = “{Left}”
ElseIf KeyCode = &H26 Then
str = “{Up}”
ElseIf KeyCode = &H27 Then
str = “{Right}”
ElseIf KeyCode = &H28 Then
str = “{Down}”
ElseIf KeyCode = &H29 Then
str = “{Select}”
ElseIf KeyCode = &H2A Then
str = “{Prt Scr}”
ElseIf KeyCode = &H2B Then
str = “{Excecute}”
ElseIf KeyCode = &H2C Then
str = “{Snapshot}”
ElseIf KeyCode = &H2D Then
str = “{Insert}”
ElseIf KeyCode = &H2E Then
str = “{Delete}”
ElseIf KeyCode = &H2F Then
str = “{Help}”
ElseIf KeyCode = &H90 Then
str = “{Num Lock}”
ElseIf KeyCode = &H60 Then
str = “[0]“
ElseIf KeyCode = &H61 Then
str = “[1]“
ElseIf KeyCode = &H62 Then
str = “[2]“
ElseIf KeyCode = &H63 Then
str = “[3]“
ElseIf KeyCode = &H64 Then
str = “[4]“
ElseIf KeyCode = &H65 Then
str = “[5]“
ElseIf KeyCode = &H66 Then
str = “[6]“
ElseIf KeyCode = &H67 Then
str = “[7]“
ElseIf KeyCode = &H68 Then
str = “[8]“
ElseIf KeyCode = &H69 Then
str = “[9]“
ElseIf KeyCode = &H6A Then
str = “*”
ElseIf KeyCode = &H6C Then
str = “{[Enter]}” & vbNewLine
ElseIf KeyCode = &H6D Then
str = “-”
ElseIf KeyCode = &H6E Then
str = “.”
ElseIf KeyCode = &H6F Then
str = “/”
ElseIf KeyCode = &H70 Then
str = “{F1}”
ElseIf KeyCode = &H71 Then
str = “{F2}”
ElseIf KeyCode = &H72 Then
str = “{F3}”
ElseIf KeyCode = &H73 Then
str = “{F4}”
ElseIf KeyCode = &H74 Then
str = “{F5}”
ElseIf KeyCode = &H75 Then
str = “{F6}”
ElseIf KeyCode = &H76 Then
str = “{F7}”
ElseIf KeyCode = &H77 Then
str = “{F8}”
ElseIf KeyCode = &H78 Then
str = “{F9}”
ElseIf KeyCode = &H79 Then
str = “{F10}”
ElseIf KeyCode = &H7A Then
str = “{F11}”
ElseIf KeyCode = &H7B Then
str = “{F12}”
ElseIf KeyCode = &H7C Then
str = “{F13}”
ElseIf KeyCode = &H7D Then
str = “{F14}”
ElseIf KeyCode = &H7E Then
str = “{F15}”
ElseIf KeyCode = &H7F Then
str = “{F16}”
ElseIf KeyCode = 145 Then
str = “{Scroll Lock}”
ElseIf KeyCode = 223 Then
str = “`”
ElseIf KeyCode = 219 Then
str = “["
ElseIf KeyCode = 221 Then
str = "]“
ElseIf KeyCode = 160 Then
str = “{LShift}”
ElseIf KeyCode = 162 Then
str = “{LCtrl}”
ElseIf KeyCode = 91 Then
str = “{LWinKey}”
ElseIf KeyCode = 164 Then
str = “{Alt}”
ElseIf KeyCode = 186 Then
str = “;”
ElseIf KeyCode = 192 Then
str = “‘”
ElseIf KeyCode = 222 Then
str = “#”
ElseIf KeyCode = 165 Then
str = “{Alt Gr}”
ElseIf KeyCode = 92 Then
str = “{RWinKey}”
ElseIf KeyCode = 93 Then
str = “{Context Menu}”
ElseIf KeyCode = 163 Then
str = “{RCtrl}”
ElseIf KeyCode = 161 Then
str = “{RShift}”
ElseIf KeyCode = 107 Then
str = “+”
ElseIf KeyCode = 181 Then
str = “{Media}”
ElseIf KeyCode = 179 Then
str = “{Play/Pause}”
ElseIf KeyCode = 173 Then
str = “{Mute}”
ElseIf KeyCode = 174 Then
str = “{VolDown}”
ElseIf KeyCode = 175 Then
str = “{VolUp}”
ElseIf KeyCode = 171 Then
str = “{Favorites}”
ElseIf KeyCode = 180 Then
str = “{Email}”
ElseIf KeyCode = 172 Then
str = “{Internet}”
ElseIf KeyCode = Keys.OemBackslash Then
str = “\”
ElseIf KeyCode = Keys.OemCloseBrackets Then
str = “)”
ElseIf KeyCode = Keys.OemOpenBrackets Then
str = “(”
ElseIf KeyCode = Keys.Oemcomma Then
str = “,”
ElseIf KeyCode = Keys.OemMinus Then
str = “-”
ElseIf KeyCode = Keys.OemPeriod Then
str = “.”
ElseIf KeyCode = Keys.OemPipe Then
str = “|”
ElseIf KeyCode = Keys.Oemplus Then
str = “+”
ElseIf KeyCode = Keys.OemQuestion Then
str = “?”
ElseIf KeyCode = Keys.OemQuotes Then
str = ControlChars.Quote
Else
str = ChrW(KeyCode)
str = str.ToLower
End If
My.Computer.FileSystem.WriteAllText(“log.txt”, str, True)
Now that was a lot of Ifs but I couldn’t see a better way to do it than that…
(Oh and for the record, I didn’t type it out by hand; I made a program to do it for meJ)
This will save a log file that looks something like this…
{LShift}this is a test of i{LShift}—h4x’s global hook.{Enter}{LShift}i know that the underscores didnt work… but y{Backspace}hey the rest does{LShift}1
And that in proper English would be:
This is a test of i__h4x’s global hook.
I know that the underscores didn’t work… but hey the rest does!
You could easily just edit the Key events, to add in a modifiers option or add some global Booleans to check if the keys are down, then instead of printing {LShift}1 you would get !
Anyway, back to the code…
Just add the code below to your main forms class, along with the two Key event subs:
Private WithEvents KeyHook As KeyboardHook
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
”Hooks The KeyBoard
KeyHook = New KeyboardHook
End Sub
Next post will be a global mouse hook! Or maybe a more advanced version of this, with some actual practical use?