Sometimes, it is useful to be able to track windows events even when your application doesn't have focus. In order to accomplish this, you can use the function SetWindowsHookEx. Below is an example of using this API in .NET and then wrapping the events with managed mouse and keyboard events. The code is not production strength, but hopefully, it will give you a good start. Let me know if you have suggestions for improvements, and I'll update the post. Here are two other sources on the subject:
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Public Class GlobalHook : Implements IDisposable
Public Event MouseDown As MouseEventHandler
Public Event MouseMove As MouseEventHandler
Public Event MouseUp As MouseEventHandler
Public Event MouseWheel As MouseEventHandler
Public Event KeyDown As KeyEventHandler
Public Event KeyPress As KeyPressEventHandler
Public Event KeyUp As KeyEventHandler
#Region " CTOR/DTOR "
Public Sub New()
InstallHooks()
End Sub
Protected Overrides Sub Finalize()
Dispose()
MyBase.Finalize()
Public Sub Dispose() Implements System.IDisposable.Dispose
RemoveHooks()
#End Region
#Region " PROTECTED OnXXXX SUBS "
Protected Overridable Sub OnMouseDown(ByVal e As MouseEventArgs)
'Debug.WriteLine("OnMouseDown")
RaiseEvent MouseDown(Me, e)
Protected Overridable Sub OnMouseMove(ByVal e As MouseEventArgs)
'Debug.WriteLine("OnMouseMove")
RaiseEvent MouseMove(Me, e)
Protected Overridable Sub OnMouseUp(ByVal e As MouseEventArgs)
'Debug.WriteLine("OnMouseUp")
RaiseEvent MouseUp(Me, e)
Protected Overridable Sub OnMouseWheel(ByVal e As MouseEventArgs)
'Debug.WriteLine("OnMouseWheel")
RaiseEvent MouseWheel(Me, e)
Protected Overridable Sub OnKeyDown(ByVal e As KeyEventArgs)
'Debug.WriteLine("OnKeyDown")
For Each handler As KeyEventHandler In KeyDownEvent.GetInvocationList
handler.Invoke(Me, e)
If e.Handled Then
Exit For
End If
Next
Protected Overridable Sub OnKeyUp(ByVal sender As Object, ByVal e As KeyEventArgs)
'Debug.WriteLine("OnKeyUp")
For Each handler As KeyEventHandler In KeyUpEvent.GetInvocationList
Protected Overridable Sub OnKeyPress(ByVal sender As Object, ByVal e As KeyPressEventArgs)
'Debug.WriteLine("OnKeyPress")
For Each handler As KeyPressEventHandler In KeyPressEvent.GetInvocationList
Private Shared hMouseHook As Integer = 0
Private Shared hKeyboardHook As Integer = 0
Private MouseHookProcedure As Win32.HookProc
Private KeyboardHookProcedure As Win32.HookProc
Public Sub InstallHooks()
If hMouseHook = 0 Then
MouseHookProcedure = New Win32.HookProc(AddressOf MouseHookProc)
hMouseHook = Win32.SetWindowsHookEx( _
Win32.WH.WH_MOUSE_LL, _
MouseHookProcedure, _
Marshal.GetHINSTANCE(Reflection.Assembly.GetExecutingAssembly().GetModules()(0)), _
0)
If hMouseHook = 0 Then 'SetWindowsHookEx failed
Throw New Exception("SetWindowsHookEx failed.")
If hKeyboardHook = 0 Then ' install Keyboard hook
KeyboardHookProcedure = New Win32.HookProc(AddressOf KeyboardHookProc)
hKeyboardHook = Win32.SetWindowsHookEx( _
Win32.WH.WH_KEYBOARD_LL, _
KeyboardHookProcedure, _
If (hKeyboardHook = 0) Then 'SetWindowsHookEx failed
Public Sub RemoveHooks()
Dim mouseResult As Boolean = True
Dim keyboardResult As Boolean = True
If hMouseHook <> 0 Then
mouseResult = Win32.UnhookWindowsHookEx(hMouseHook)
hMouseHook = 0
If hKeyboardHook <> 0 Then
keyboardResult = Win32.UnhookWindowsHookEx(hKeyboardHook)
hKeyboardHook = 0
If Not (mouseResult And keyboardResult) Then 'UnhookWindowsHookEx failed
Throw New Exception("UnhookWindowsHookEx failed.")
Private Function MouseHookProc(ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As Integer
If nCode >= 0 Then
Select Case wParam
Case _
Win32.WM.WM_LBUTTONDOWN, _
Win32.WM.WM_LBUTTONDBLCLK, _
Win32.WM.WM_MBUTTONDOWN, _
Win32.WM.WM_MBUTTONDBLCLK, _
Win32.WM.WM_RBUTTONDOWN, _
Win32.WM.WM_RBUTTONDBLCLK, _
Win32.WM.WM_XBUTTONDOWN, _
Win32.WM.WM_XBUTTONDBLCLK
If MouseDownEvent Is Nothing Then
Win32.CallNextHookEx(hMouseHook, nCode, wParam, lParam)
Exit Function
Win32.WM.WM_LBUTTONUP, _
Win32.WM.WM_MBUTTONUP, _
Win32.WM.WM_RBUTTONUP, _
Win32.WM.WM_XBUTTONUP
If MouseUpEvent Is Nothing Then
Case Win32.WM.WM_MOUSEWHEEL
If MouseWheelEvent Is Nothing Then
Case Win32.WM.WM_MOUSEMOVE
If MouseMoveEvent Is Nothing Then
End Select
Dim clickCount As Integer = 0
Dim buttons As MouseButtons = MouseButtons.None
Dim mhs As New Win32.MSLLHOOKSTRUCT
Dim hiWord As Integer
Dim delta As Integer = 0
Marshal.PtrToStructure(lParam, mhs)
hiWord = Win32.HIWORD(mhs.mouseData)
Select Case (wParam)
Win32.WM.WM_LBUTTONDBLCLK
buttons = MouseButtons.Left
Case Win32.WM.WM_MBUTTONDOWN, _
Win32.WM.WM_MBUTTONDBLCLK
buttons = MouseButtons.Middle
Case Win32.WM.WM_RBUTTONDOWN, _
Win32.WM.WM_RBUTTONDBLCLK
buttons = MouseButtons.Right
Win32.WM.WM_XBUTTONUP, _
Win32.WM.WM_XBUTTONDBLCLK, _
Win32.WM.WM_NCXBUTTONDOWN, _
Win32.WM.WM_NCXBUTTONUP, _
Win32.WM.WM_NCXBUTTONDBLCLK
If hiWord = 1 Then
buttons = MouseButtons.XButton1
ElseIf hiWord = 2 Then
buttons = MouseButtons.XButton2
delta = hiWord
If buttons <> MouseButtons.None Then