65.9K
CodeProject 正在变化。 阅读更多。
Home

检测系统范围的鼠标事件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (8投票s)

2008年9月27日

CPOL

2分钟阅读

viewsIcon

83499

downloadIcon

3247

如何在你的应用程序中检测系统范围的鼠标事件

包含鼠标滚轮方向检测支持的 MouseHunter 项目的更新版本可在此下载:下载 MouseHunter_1.1.zip

引言

有时你可能需要在你的应用程序中跟踪系统范围内的鼠标事件。但是,是否可以从系统“窃取”鼠标事件? 你的应用程序是否可以被通知系统事件何时发生? 如果你想了解系统范围内的鼠标事件检测和事件“窃取”的秘密,那么下面的文章就是为你准备的。

背景

我在互联网上找到很多关于钩子的示例。但我一直想要一个鼠标钩子解决方案,如果系统中的任何地方发生鼠标点击,它都会在我的应用程序中通过 OnMouseClick 类型事件通知我。在这里,我恰好创建了一个。它是一个 VB6 ActiveX DLL 项目。它可以跟踪你感兴趣的所有必需的鼠标事件,并且可以使用该库向你的应用程序引发关于系统中发生的相应事件。你将能够获取鼠标下方的窗口标题(如果有的话),你可以获取鼠标下方的窗口句柄(hWnd),以及计算机屏幕上鼠标的 x 和 y 坐标。最后,还有一件有趣的事情,你将能够拦截此库支持的系统中的任何鼠标事件。这意味着,例如,你可以决定不将“鼠标右键按下”事件传递给系统,而是由你自己在应用程序中处理。

我将 DLL 项目命名为 MouseHunter。它有一个名为 Tracer 的类模块和一个名为 modHook 的通用模块。 Tracer 类的代码如下

Option Explicit
  
'* The SetWindowsHookEx function installs an application-defined hook 
'procedure into a hook chain. You would install a hook procedure to monitor 
'the system for certain types of events. These events are associated either 
'with a specific thread or with all threads in the system.
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
'* The UnhookWindowsHookEx function removes a hook procedure installed in a hook chain 
'by the SetWindowsHookEx function.
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
'* The CallNextHookEx function passes the hook information to the next hook procedure 
'in the current hook chain. A hook procedure can call this function either 
'before or after processing the hook information.
Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, _
    ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long

'* The IsWindow function determines whether the specified window 
'handle identifies an existing window.
Private Declare Function IsWindow Lib "user32" (ByVal hwnd&) As Long

'* The GetWindowText function copies the text of the specified window’s 
'title bar (if it has one) into a buffer. If the specified window is a control, 
'the text of the control is copied.
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
    (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
'* The WindowFromPoint function retrieves the handle of the window that contains 
'the specified point.
Private Declare Function WindowFromPoint Lib "user32" _
    (ByVal xPoint As Long, ByVal yPoint As Long) As Long
'* The GetCursorPos function retrieves the cursor’s position, in screen coordinates.
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long

'* Type to hold the mouse coordinates
Private Type POINTAPI
    X As Long
    Y As Long
End Type

Private point As POINTAPI

'******************************************************
'* System messages for Mouse that we want to trace
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
'******************************************************

'* System hook for mouse that we'll use
Private Const WH_MOUSE_LL            As Long = 14

Private mlngMouseHook               As Long
Private mstrWindowCaption           As String

'******************************************************
'* System events of Mouse that we can stop broadcasting
'* to the System and make only traceable from the caller application
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

'* Type to hold Mouse Hook information
Private Type MOUSELLHOOKSTRUCT
    point As POINTAPI
    data As Long
    flags As Long
    time As Long
    extra As Long
End Type

Private mousedata As MOUSELLHOOKSTRUCT

'******************************************************
'* Events that will be fired to the caller application
'* For different Mouse activities in the System
Public Event OnSystemMouseMove()
Public Event OnSystemMouseWheel()
Public Event OnSystemMouseLeftDown()
Public Event OnSystemMouseLeftUp()
Public Event OnSystemMouseRightDown()
Public Event OnSystemMouseRightUp()
Public Event OnSystemMouseMiddleDown()
Public Event OnSystemMouseMiddleUp()
'******************************************************

'* Get the mouse events that we want to steal from the System
Public Property Get StealMouseEvents() As EventThief
    StealMouseEvents = mtypEventThief
End Property

'* Set the mouse events that we want to steal from the System
Public Property Let StealMouseEvents(typEventThief As EventThief)
    mtypEventThief = typEventThief
End Property

'* Get the X coordinate of the Mouse in the current screen
Public Property Get CoordinateX() As Long
    CoordinateX = point.X
End Property

'* Get the Y coordinate of the Mouse in the current screen
Public Property Get CoordinateY() As Long
    CoordinateY = point.Y
End Property

'* Get the Caption (if any) of the window currently under the Mouse
Public Property Get WindowTextUnderMouse() As String
    WindowTextUnderMouse = GetWindowTitle(point.X, point.Y)
End Property

'* Get the handle (hWnd) of the window currently under the Mouse
Public Property Get WindowHandleUnderMouse() As Long
    WindowHandleUnderMouse = GetWindowHandle(point.X, point.Y)
End Property

'* Start tracing system wide mouse events
Public Sub StartMouseTracing(ByVal hwnd As Long)
    If IsWindow(hwnd) Then
        glnghWnd = hwnd
        
        '* If there is already a hook by the application, don't hook again
        If GetProp(hwnd, "MouseHook") Then
            Exit Sub
        End If
        
        '* Try to set the Object instance of the Tracer class in memory
        '* If successful, then set the hook
        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

'* Stop tracing system wide mouse events
Public Sub StopMouseTracing()
    '* First check if the hook was established
    If mlngMouseHook <> 0 Then
        RemoveProp glnghWnd, "MouseHook"
        UnhookWindowsHookEx mlngMouseHook
    End If
End Sub

Private Sub Class_Terminate()
    '* Make sure the hook is removed after the class is terminated
    StopMouseTracing
End Sub

'* Bypassed MouseProc from the modHook's MouseProc.
'* The trick is necessary here to raise the appropriate events to the caller
'* for particular System events of the Mouse
Friend Function MouseProc(ByVal nCode As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
    If (nCode = HC_ACTION) Then
        ' Mouse data not used in this example, but useful
        CopyMemory mousedata, ByVal lParam, Len(mousedata)
        Select Case wParam
            Case WM_MOUSEMOVE
                '* Trace the coordinate of the Mouse whenever it moves
                GetCursorPos point
                '* Raise the event to the caller Window
                RaiseEvent OnSystemMouseMove
                '* Check if caller wanted this event as non traceable to the System
                If mtypEventThief.MOVE Then
                    '* If so, steal the event from the system and make it only traceable
                    '* to the window of the caller application
                    MouseProc = -1
                Else
                    '* If not, release the event to the System
                    MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
                End If
            Case WM_MOUSEWHEEL
                '* Raise the event to the caller Window
                RaiseEvent OnSystemMouseWheel
                '* Check if caller wanted this event as non traceable to the System
                If mtypEventThief.WHEEL Then
                    '* If so, steal the event from the system and make it only traceable
                    '* to the window of the caller application
                    MouseProc = -1
                Else
                    '* If not, release the event to the System
                    MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
                End If
            Case WM_LBUTTONDOWN
                '* Raise the event to the caller Window
                RaiseEvent OnSystemMouseLeftDown
                '* Check if caller wanted this event as non traceable to the System
                If mtypEventThief.LEFT_DOWN Then
                    '* If so, steal the event from the system and make it only traceable
                    '* to the window of the caller application
                    MouseProc = -1
                Else
                    '* If not, release the event to the System
                    MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
                End If
            Case WM_LBUTTONUP
                '* Raise the event to the caller Window
                RaiseEvent OnSystemMouseLeftUp
                '* Check if caller wanted this event as non traceable to the System
                If mtypEventThief.LEFT_UP Then
                    '* If so, steal the event from the system and make it only traceable
                    '* to the window of the caller application
                    MouseProc = -1
                Else
                    '* If not, release the event to the System
                    MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
                End If
            Case WM_RBUTTONDOWN
                '* Raise the event to the caller Window
                RaiseEvent OnSystemMouseRightDown
                '* Check if caller wanted this event as non traceable to the System
                If mtypEventThief.RIGHT_DOWN Then
                    '* If so, steal the event from the system and make it only traceable
                    '* to the window of the caller application
                    MouseProc = -1
                Else
                    '* If not, release the event to the System
                    MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
                End If
            Case WM_RBUTTONUP
                '* Raise the event to the caller Window
                RaiseEvent OnSystemMouseRightUp
                '* Check if caller wanted this event as non traceable to the System
                If mtypEventThief.RIGHT_UP Then
                    '* If so, steal the event from the system and make it only traceable
                    '* to the window of the caller application
                    MouseProc = -1
                Else
                    '* If not, release the event to the System
                    MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
                End If
            Case WM_MBUTTONDOWN
                '* Raise the event to the caller Window
                RaiseEvent OnSystemMouseMiddleDown
                '* Check if caller wanted this event as non traceable to the System
                If mtypEventThief.MIDDLE_DOWN Then
                    '* If so, steal the event from the system and make it only traceable
                    '* to the window of the caller application
                    MouseProc = -1
                Else
                    '* If not, release the event to the System
                    MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
                End If
            Case WM_MBUTTONUP
                '* Raise the event to the caller Window
                RaiseEvent OnSystemMouseMiddleUp
                '* Check if caller wanted this event as non traceable to the System
                If mtypEventThief.MIDDLE_UP Then
                    '* If so, steal the event from the system and make it only traceable
                    '* to the window of the caller application
                    MouseProc = -1
                Else
                    '* If not, release the event to the System
                    MouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
                End If
            Case Else
                ' not implemented yet
        End Select
    End If
End Function

'* Returns the Window Caption (if any) under the mouse
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

'* Returns the Window Handle (hWnd) under the mouse
Private Function GetWindowHandle(CoordX As Long, CoordY As Long) As Long
    GetWindowHandle = WindowFromPoint(CoordX, CoordY)
End Function

以下是通用模块 modHook 的代码

Option Explicit

'* The CopyMemory function copies a block of memory from one location to another.
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
    (Destination As Any, Source As Any, ByVal Length As Long)
'* The GetProp function retrieves a data handle from the property list 
'of the given window. The given character string identifies the handle 
'to be retrieved. The string and handle must have been added to the 
'property list by a previous call to the SetProp function.
Public Declare Function GetProp Lib "user32" Alias "GetPropA" _
    (ByVal hwnd As Long, ByVal lpString As String) As Long
'* The SetProp function adds a new entry or changes an existing entry 
'in the property list of the specified window. The function adds a new entry 
'to the list if the specified character string does not exist already in the list. 
'The new entry contains the string and the handle. 
'Otherwise, the function replaces the string’s current handle with the specified handle.
Public Declare Function SetProp Lib "user32" Alias "SetPropA" _
    (ByVal hwnd As Long, ByVal lpString As String, ByVal hData As Long) As Long
'* The RemoveProp function removes an entry from the property list 
'of the specified window. The specified character string identifies 
'the entry to be removed.
Public Declare Function RemoveProp Lib "user32" Alias "RemovePropA" _
    (ByVal hwnd&, ByVal lpString$) As Long

'* Global variable to hold the hWnd of the caller application's window
Global glnghWnd   As Long

'* Main procedure to trace the mouse events, but it is bypassed
'* to the Tracer class's MouseProc method so that the events can be raised from there.
'* As you know events can't be raised from a general module.
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

'* This method retrieves the object of the tracer class created in the memory
Private Function TracerFromMemory(ByVal hwnd As Long) As Tracer
    Dim MsgHookEx   As Tracer
    Dim ptrObject   As Long
    
    '* Getting the already created Object of the Tracer class
    '* from memory in ptrObjec
    ptrObject = GetProp(glnghWnd, ByVal "MouseHook")
    
    '* Setting the Tracer class object from ptrObject to MsgHookEx
    CopyMemory MsgHookEx, ptrObject, Len(ptrObject)
    
    '* return the Tracer class object
    Set TracerFromMemory = MsgHookEx
    
    '* Remove the reference of the Tracer class object from memory
    CopyMemory MsgHookEx, 0&, Len(ptrObject)
End Function

Using the Code

你可以从任何 COM 兼容的高级语言中使用该库。我创建了一个 VB6 标准 EXE 应用程序,演示了如何使用此库。只有一个名为 frmMain 的窗体,它有两个标签,名为 lblWindowTitlelblEvents。关于此测试应用程序,只有一件事需要记住,不要从 VB IDE 中的“停止”按钮关闭它。而是使用窗体的关闭图标关闭应用程序。以下是代码:

'********************************************************
'* WARNING!!!
'* PLEASE DO NOT STOP THIS APPLICATION FROM THE VB IDE
'* CLICK THE FORM'S CROSS ICON IF YOU INTEND TO CLOSE
'********************************************************

Option Explicit

'* Declaring the mouse tracer object using WithEvents so that the events
'* can be traced
Private WithEvents MyMouseHunter As MouseHunter.Tracer

Private Sub Form_Load()
    '* EventStealingInfo will help to steal any particular mouse event you want.
    '* This will help you to grab the event just within your application
    '* And will not pass the event to the system
    Dim EventStealingInfo As EventThief
    
    lblWindowTitle.Caption = ""
    lblEvents.Caption = ""
    
    Set MyMouseHunter = New MouseHunter.Tracer
    
    '* Selecting the particular mouse events that you want to steal
    '* from the system
    '* Here, you'll steal the Mouse's Right Button's UP & Down events
    '* From the System, so you'll see your right button of the Mouse
    '* Is not working in anywhere in the System, But your application
    '* is still tracing the events!!
    With EventStealingInfo
        .RIGHT_DOWN = True
        .RIGHT_UP = True
    End With
    
    '* Passing the EventStealingInfo to the tracer class
    MyMouseHunter.StealMouseEvents = EventStealingInfo
    '* Start tracing the system wide mouse events
    MyMouseHunter.StartMouseTracing Me.hWnd
    
End Sub

Private Sub Form_Unload(Cancel As Integer)
    '* make sure the system wide mouse tracing is stopped after the application
    '* is closed
    MyMouseHunter.StopMouseTracing
End Sub

'* Tracking the system wide mouse events
Private Sub MyMouseHunter_OnSystemMouseMove()
    '* Choose anything you want to trace when your mouse moves
    '* You can trace the X and Y coordinate of your mouse position in the window
    '* Or the Window handle (hWnd) of the window under your mouse
    '* Or the Window title (Caption) under your mouse.
    
    'lblWindowTitle.Caption = MyMouseHunter.CoordinateX & "," _
                & MyMouseHunter.CoordinateY
    'lblWindowTitle.Caption = MyMouseHunter.WindowHandleUnderMouse
    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

'* ENJOY!!!

关注点

使用此库,系统范围内的鼠标事件跟踪对你来说将非常容易。希望你喜欢这段代码。

历史

  • 由 Zakir Hossain 于 2008 年 9 月 27 日下午 6:46 上传 (+6 GMT)
© . All rights reserved.