Archive for May 5th, 2008

Vb Net - Low Level Mouse Hook (Global)

Installing a Low Level Mouse Hook

MouseHookYeah!

This hook is basically the same as the Keyboard hook, just, with a mouse and a few extra things…

Below is the basic class that you need:

Private Class MouseHook

”Constants

Private Const HC_ACTION As Integer = 0

Private Const WH_MOUSE_LL As Integer = 14

Private Const WM_MOUSEMOVE As Integer = &H200

Private Const WM_LBUTTONDOWN As Integer = &H201

Private Const WM_LBUTTONUP As Integer = &H202

Private Const WM_LBUTTONDBLCLK As Integer = &H203

Private Const WM_RBUTTONDOWN As Integer = &H204

Private Const WM_RBUTTONUP As Integer = &H205

Private Const WM_RBUTTONDBLCLK As Integer = &H206

Private Const WM_MBUTTONDOWN As Integer = &H207

Private Const WM_MBUTTONUP As Integer = &H208

Private Const WM_MBUTTONDBLCLK As Integer = &H209

Private Const WM_MOUSEWHEEL As Integer = &H20A

”Mouse Structures

Public Structure POINT

Private x As Integer

Private y As Integer

End Structure

Private Structure MSLLHOOKSTRUCT

Private pt As POINT

Private mouseData As Integer

Private flags As Integer

Private time As Integer

Private dwExtraInfo As Integer

End Structure

”API Functions

Private Declare Function SetWindowsHookEx Lib “user32″ Alias “SetWindowsHookExA” (ByVal idHook As Integer, ByVal lpfn As MouseProcDelegate, 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 MSLLHOOKSTRUCT) As Integer

Private Declare Function UnhookWindowsHookEx Lib “user32″ (ByVal hHook As Integer) As Integer

”Our Mouse Delegate

Private Delegate Function MouseProcDelegate(ByVal nCode As Integer, ByVal wParam As Integer, ByRef lParam As MSLLHOOKSTRUCT) As Integer

”The Mouse events

Public Shared Event MouseMove()

Public Shared Event MouseEvent(ByVal mEvent As Integer)

”The identifyer for our MouseHook

Private Shared MouseHook As Integer

”MouseHookDelegate

Private Shared MouseHookDelegate As MouseProcDelegate

Public Sub New()

”Installs a Low Level Mouse Hook

MouseHookDelegate = New MouseProcDelegate(AddressOf MouseProc)

MouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookDelegate, Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0)).ToInt32, 0)

End Sub

Private Shared Function MouseProc(ByVal nCode As Integer, ByVal wParam As Integer, ByRef lParam As MSLLHOOKSTRUCT) As Integer

”If it is a Mouse event

If (nCode = HC_ACTION) Then

If wParam = WM_MOUSEMOVE Then

”If it is the mouse moving

RaiseEvent MouseMove()

ElseIf wParam = WM_LBUTTONDOWN Or wParam = WM_LBUTTONUP Or wParam = WM_LBUTTONDBLCLK Or wParam = WM_RBUTTONDOWN Or wParam = WM_RBUTTONUP Or wParam = WM_RBUTTONDBLCLK Or wParam = WM_MBUTTONDOWN Or wParam = WM_MBUTTONUP Or wParam = WM_MBUTTONDBLCLK Or wParam = WM_MOUSEWHEEL Then

”If it is a different mouse event

RaiseEvent MouseEvent(wParam)

End If

End If

”Next

Return CallNextHookEx(MouseHook, nCode, wParam, lParam)

End Function

Protected Overrides Sub Finalize()

”On close it UnHooks the Hook

UnhookWindowsHookEx(MouseHook)

MyBase.Finalize()

End Sub

End Class

The important part this time is in the MouseProc function

If (nCode = HC_ACTION) Then

If wParam = WM_MOUSEMOVE Then

”If it is the mouse moving

RaiseEvent MouseMove()

ElseIf wParam = WM_LBUTTONDOWN Or wParam = WM_LBUTTONUP Or wParam = WM_LBUTTONDBLCLK Or wParam = WM_RBUTTONDOWN Or wParam = WM_RBUTTONUP Or wParam = WM_RBUTTONDBLCLK Or wParam = WM_MBUTTONDOWN Or wParam = WM_MBUTTONUP Or wParam = WM_MBUTTONDBLCLK Or wParam = WM_MOUSEWHEEL Then

”If it is a different mouse event

RaiseEvent MouseEvent(wParam)

End If

End If

This raises one of the two events: MouseMove or MouseEvent

Private Shadows Sub MouseMove() Handles MHook.MouseMove

”This keeps the form on top, and sets it so that it moves with the cursor

Me.BringToFront()

Me.Location = New Point(Windows.Forms.Cursor.Position.X - (Me.Width / 2), Windows.Forms.Cursor.Position.Y - (Me.Height / 2))

End Sub

That’s just a basic sub that moves the form’s centre to the location of the mouse cursor, whenever the mouse is moved it follows it around.

Private Sub MouseEvent(ByVal mEvent As Integer) Handles MHook.MouseEvent

”Saves a basic log of the mouse events

Dim x As Integer = Windows.Forms.Cursor.Position.X

Dim y As Integer = Windows.Forms.Cursor.Position.Y

If mEvent = 513 Then

Log &= Now & ” - Left Down - (” & x & “, “ & y & “)” & vbNewLine

ElseIf mEvent = 514 Then

Log &= Now & ” - Left Up - (” & x & “, “ & y & “)” & vbNewLine

ElseIf mEvent = &H203 Then

Log &= Now & ” - Left Double Click - (” & x & “, “ & y & “)” & vbNewLine

ElseIf mEvent = &H204 Then

Log &= Now & ” - Right Down - (” & x & “, “ & y & “)” & vbNewLine

ElseIf mEvent = &H205 Then

Log &= Now & ” - Right Up - (” & x & “, “ & y & “)” & vbNewLine

ElseIf mEvent = &H206 Then

Log &= Now & ” - Right Double Click - (” & x & “, “ & y & “)” & vbNewLine

ElseIf mEvent = &H207 Then

Log &= Now & ” - Middle Down - (” & x & “, “ & y & “)” & vbNewLine

ElseIf mEvent = &H208 Then

Log &= Now & ” - Middle Up - (” & x & “, “ & y & “)” & vbNewLine

ElseIf mEvent = &H209 Then

Log &= Now & ” - Middle Double Click - (” & x & “, “ & y & “)” & vbNewLine

ElseIf mEvent = &H20A Then

Log &= Now & ” - Mouse Scroll - (” & x & “, “ & y & “)” & vbNewLine

”Displays the log

MsgBox(Log)

End If

End Sub

That has a little more to it, it determines what the event was, then saves a log accordingly.

Now, in order to make this function, just add the MouseHook class, and the two subs to your form along with this:

Private WithEvents MHook As MouseHook

Dim Log As String

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

”Hooks The Mouse

MHook = New MouseHook

End Sub

Which makes the whole thing work J

Oh, and just for the record, either run this program OUTSIDE the IDE or:

In solution explorer, click on My Project

Go to Debug

Uncheck ‘Enable the Visual Studio hosting process’

Same goes with the keyboard hook.

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?