An updated version of MouseHunter project with Mouse Wheel Direction detection support is available to download here: Download MouseHunter_1.1.zip.
Introduction
Maybe sometimes you needed to track the system wide mouse events from your application. But is it possible to steal a mouse event from the system? Also can your application get notified by events about which system event has occurred? If you want to know the secret of system wide mouse events detection and event stealing, the article below is for you.
Background
I got many samples on the Internet about hooking. But I always wanted a mouse hooking solution that will notify me with OnMouseClick
types of events in my application if a MouseClick
occurred anywhere in the system. Here exactly I have created one. It is a VB6 ActiveX DLL project. It can trace all the required mouse events you will be interested in and also it can raise events to your application using the library about the corresponding events occurring in the system. You'll be able to get the Caption (if any) of the window under your mouse, you can get the window handle (hWnd
) under your mouse, also the x and y coordinates of the mouse on your computer screen. Finally, one more interesting thing is that, you'll be able to intercept any of the mouse events in the system supported by this library. It means, for example, you can decide not to pass the "Mouse right button down" event to the system, instead YOU will handle this within your application.
I have named the DLL project as MouseHunter
. It has one class module named Tracer
and one general module named modHook
. The code of the Tracer
class is given below:
Option Explicit
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" _
(ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, _
ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, _
ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function IsWindow Lib "user32" (ByVal hwnd&) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
(ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function WindowFromPoint Lib "user32" _
(ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Type POINTAPI
X As Long
Y As Long
End Type
Private point As POINTAPI
Private Const WM_MOUSEMOVE As Long = &H200
Private Const WM_MOUSEWHEEL As Long = &H20A
Private Const WM_LBUTTONDOWN As Long = &H201
Private Const WM_LBUTTONUP As Long = &H202
Private Const WM_RBUTTONDOWN As Long = &H204
Private Const WM_RBUTTONUP As Long = &H205
Private Const WM_MBUTTONDOWN As Long = &H207
Private Const WM_MBUTTONUP As Long = &H208
Private Const WH_MOUSE_LL As Long = 14
Private mlngMouseHook As Long
Private mstrWindowCaption As String
Public Type EventThief
LEFT_DOWN As Boolean
LEFT_UP As Boolean
RIGHT_DOWN As Boolean
RIGHT_UP As Boolean
MIDDLE_DOWN As Boolean
MIDDLE_UP As Boolean
WHEEL As Boolean
MOVE As Boolean
End Type
Private mtypEventThief As EventThief
Private Const HC_ACTION = 0
Private Type MOUSELLHOOKSTRUCT
point As POINTAPI
data As Long
flags As Long
time As Long
extra As Long
End Type
Private mousedata As MOUSELLHOOKSTRUCT
Public Event OnSystemMouseMove()
Public Event OnSystemMouseWheel()
Public Event OnSystemMouseLeftDown()
Public Event OnSystemMouseLeftUp()
Public Event OnSystemMouseRightDown()
Public Event OnSystemMouseRightUp()
Public Event OnSystemMouseMiddleDown()
Public Event OnSystemMouseMiddleUp()
Public Property Get StealMouseEvents() As EventThief
StealMouseEvents = mtypEventThief
End Property
Public Property Let StealMouseEvents(typEventThief As EventThief)
mtypEventThief = typEventThief
End Property
Public Property Get CoordinateX() As Long
CoordinateX = point.X
End Property
Public Property Get CoordinateY() As Long
CoordinateY = point.Y
End Property
Public Property Get WindowTextUnderMouse() As String
WindowTextUnderMouse = GetWindowTitle(point.X, point.Y)
End Property
Public Property Get WindowHandleUnderMouse() As Long
WindowHandleUnderMouse = GetWindowHandle(point.X, point.Y)
End Property
Public Sub StartMouseTracing(ByVal hwnd As Long)
If IsWindow(hwnd) Then
glnghWnd = hwnd
If GetProp(hwnd, "MouseHook") Then
Exit Sub
End If
If SetProp(hwnd, ByVal "MouseHook", ObjPtr(Me)) Then
mlngMouseHook = SetWindowsHookEx(WH_MOUSE_LL, AddressOf modHook.MouseProc, _
App.hInstance, 0)
End If
End If
End Sub
Public Sub StopMouseTracing()
If mlngMouseHook <> 0 Then
RemoveProp glnghWnd, "MouseHook"
UnhookWindowsHookEx mlngMouseHook
End If
End Sub
Private Sub Class_Terminate()
StopMouseTracing
End Sub
Friend Function MouseProc(ByVal nCode As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
If (nCode = HC_ACTION) Then
CopyMemory mousedata, ByVal lParam, Len(mousedata)
Select Case wParam
Case WM_MOUSEMOVE
GetCursorPos point
RaiseEvent OnSystemMouseMove
If mtypEventThief.MOVE Then
MouseProc = -1
Else
MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End If
Case WM_MOUSEWHEEL
RaiseEvent OnSystemMouseWheel
If mtypEventThief.WHEEL Then
MouseProc = -1
Else
MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End If
Case WM_LBUTTONDOWN
RaiseEvent OnSystemMouseLeftDown
If mtypEventThief.LEFT_DOWN Then
MouseProc = -1
Else
MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End If
Case WM_LBUTTONUP
RaiseEvent OnSystemMouseLeftUp
If mtypEventThief.LEFT_UP Then
MouseProc = -1
Else
MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End If
Case WM_RBUTTONDOWN
RaiseEvent OnSystemMouseRightDown
If mtypEventThief.RIGHT_DOWN Then
MouseProc = -1
Else
MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End If
Case WM_RBUTTONUP
RaiseEvent OnSystemMouseRightUp
If mtypEventThief.RIGHT_UP Then
MouseProc = -1
Else
MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End If
Case WM_MBUTTONDOWN
RaiseEvent OnSystemMouseMiddleDown
If mtypEventThief.MIDDLE_DOWN Then
MouseProc = -1
Else
MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End If
Case WM_MBUTTONUP
RaiseEvent OnSystemMouseMiddleUp
If mtypEventThief.MIDDLE_UP Then
MouseProc = -1
Else
MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End If
Case Else
End Select
End If
End Function
Private Function GetWindowTitle(CoordX As Long, CoordY As Long) As String
Dim strTitle As String
strTitle = String(255, Chr$(0))
GetWindowText WindowFromPoint(CoordX, CoordY), strTitle, 255
strTitle = Left$(strTitle, InStr(strTitle, Chr$(0)) - 1)
GetWindowTitle = strTitle
End Function
Private Function GetWindowHandle(CoordX As Long, CoordY As Long) As Long
GetWindowHandle = WindowFromPoint(CoordX, CoordY)
End Function
Here is the code of the general module modHook
:
Option Explicit
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(Destination As Any, Source As Any, ByVal Length As Long)
Public Declare Function GetProp Lib "user32" Alias "GetPropA" _
(ByVal hwnd As Long, ByVal lpString As String) As Long
Public Declare Function SetProp Lib "user32" Alias "SetPropA" _
(ByVal hwnd As Long, ByVal lpString As String, ByVal hData As Long) As Long
Public Declare Function RemoveProp Lib "user32" Alias "RemovePropA" _
(ByVal hwnd&, ByVal lpString$) As Long
Global glnghWnd As Long
Public Function MouseProc(ByVal nCode As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
MouseProc = TracerFromMemory(glnghWnd).MouseProc(nCode, wParam, lParam)
End Function
Private Function TracerFromMemory(ByVal hwnd As Long) As Tracer
Dim MsgHookEx As Tracer
Dim ptrObject As Long
ptrObject = GetProp(glnghWnd, ByVal "MouseHook")
CopyMemory MsgHookEx, ptrObject, Len(ptrObject)
Set TracerFromMemory = MsgHookEx
CopyMemory MsgHookEx, 0&, Len(ptrObject)
End Function
Using the Code
You can use the library from any COM compatible high level language. I have created a sample VB6 standard EXE application that shows the use of this library. There is only one form named frmMain
and it has two labels named lblWindowTitle
& lblEvents
. Just one thing to remember about this test application is that, don't close it from the Stop button in the VB IDE. Instead, use the Form's cross icon to close the application. Here is the code below:
Option Explicit
Private WithEvents MyMouseHunter As MouseHunter.Tracer
Private Sub Form_Load()
Dim EventStealingInfo As EventThief
lblWindowTitle.Caption = ""
lblEvents.Caption = ""
Set MyMouseHunter = New MouseHunter.Tracer
With EventStealingInfo
.RIGHT_DOWN = True
.RIGHT_UP = True
End With
MyMouseHunter.StealMouseEvents = EventStealingInfo
MyMouseHunter.StartMouseTracing Me.hWnd
End Sub
Private Sub Form_Unload(Cancel As Integer)
MyMouseHunter.StopMouseTracing
End Sub
Private Sub MyMouseHunter_OnSystemMouseMove()
& MyMouseHunter.CoordinateY
lblWindowTitle.Caption = MyMouseHunter.WindowTextUnderMouse
lblEvents.Caption = "Moving..."
End Sub
Private Sub MyMouseHunter_OnSystemMouseLeftDown()
lblEvents.Caption = "Left Down"
End Sub
Private Sub MyMouseHunter_OnSystemMouseLeftUp()
lblEvents.Caption = "Left Up"
End Sub
Private Sub MyMouseHunter_OnSystemMouseRightDown()
lblEvents.Caption = "Right Down"
End Sub
Private Sub MyMouseHunter_OnSystemMouseRightUp()
lblEvents.Caption = "Right Up"
End Sub
Private Sub MyMouseHunter_OnSystemMouseMiddleDown()
lblEvents.Caption = "Middle Down"
End Sub
Private Sub MyMouseHunter_OnSystemMouseMiddleUp()
lblEvents.Caption = "Middle Up"
End Sub
Private Sub MyMouseHunter_OnSystemMouseWheel()
lblEvents.Caption = "Wheel..."
End Sub
Points of Interest
Using this library, the system wide mouse events tracing will be very easy for you. Hope you'll enjoy the code.
History
- Uploaded by Zakir Hossain on 27th September, 2008 at 6:46 PM (+6 GMT)