For my own implementation of a lightweight remote service application (like RDP, TeamViewer), I need to listen to the system's (or global) mouse events, like mouse move or left/right/middle/etc click.
I found out, that there is a managed interface/API for querying the system's mouse position:
Dim pos As System.Drawing.Point = Windows.Forms.Cursor.Position
Label1.Text = String.Format("Current Position: {0} - {1}", pos.X, pos.Y)
However, the class Windows.Forms.Cursor
seems to have no events, I can register/listen to. Private WithEvents MyCurser As Windows.Forms.Cursor
does not have any listing with Handles
.
To make it more clear: I do want to track mouse events outside my application (so click event listeners to my own forms are not applicable), as my application is a remote service application like RDP or TeamViewer which only forwards mouse events (and the display) to an remote computer.
Is there a managed (.NET) way of getting the mouse position changes as an event (and not requiring to have a timer to query the position), and also whether the user have clicked (is clicking) a button on the mouse (and what button it is)?
Bonus question: Does your solution work when the mouse move/click "event" has been triggered by another software and not by the human who is actually operating the mouse.
You can use my library called InputHelper. It was built to help .NET developers both capture and simulate mouse and keyboard input in a simple, and correct, manner.
After seeing and answering way too many Stack Overflow questions where the user either used a deprecated API or where their P/Invoke signatures where way off, I decided to create this as a more .NET-friendly way of managing input as well as an attempt to fight the only partially correct code that users gathered from many different places on the internet.
InputHelper is built around the native Windows API (WinAPI) and utilizes functions such as SendInput()
, SendMessage()
/PostMessage()
and SetWindowsHookEx()
in order to get its job done.
Its Wiki is sadly still far from complete as I've only documented the mouse and keyboard hooks, however the library includes XML documentation files containing comments explaining every function in it, which are automatically displayed by IntelliSense as you type your code. So for a mini-documentation and overview of the library you can always open Visual Studio's Object Browser (press F12 on any type or namespace, or go to View > Object Browser
) and locate it there.
InputHelper currently consists of four caregories:
InputHelper.Hooks
: Classes for capturing system-wide mouse and keyboard input. This can be used to make hot keys, for instance.
InputHelper.Keyboard
: Methods for simulating physical ("real") keyboard input/key strokes.
InputHelper.Mouse
: Methods for simulating physical mouse input.
InputHelper.WindowMessages
: Methods for simulating mouse and keyboard input at a more virtual level. This utilizes window messages (Send-/PostMessage
) and can be used to target specific windows.
The one you're looking for is InputHelper.Hooks
, specifically, InputHelper.Hooks.MouseHook
.
To start with, download the compiled version of the library on the Releases page and add it as a reference to your project. For convenience import the InputHelperLib
namespace in the file(s) that you'll be using it:
Imports InputHelperLib
Now, the easiest way to create a mouse hook is to just instantiate an instance of the MouseHook
class at class-level:
Dim MouseHook As New InputHelper.Hooks.MouseHook
This will listen for mouse events until the variable goes out of scope or until you call Dispose()
on it.
If you don't want to start the hook right away, just declare the variable and initialize it whenever you want.
Dim MouseHook As InputHelper.Hooks.MouseHook
'Start the hook at the click of a button.
Private Sub StartButton_Click(sender As Object, e As EventArgs) Handles StartButton.Click
If MouseHook Is Nothing Then
MouseHook = New InputHelper.Hooks.MouseHook
End If
End Sub
The hook includes four events:
MouseDown
- Occurs when a mouse button is pressed or held down.
MouseMove
- Occurs when the mouse moves.
MouseUp
- Occurs when a mouse button is released.
MouseWheel
- Occurs when the mouse wheel is scrolled.
You can subscribe to the events using the AddHandler
statement.
Dim MouseHook As InputHelper.Hooks.MouseHook
'Start the hook at the click of a button.
Private Sub StartButton_Click(sender As Object, e As EventArgs) Handles StartButton.Click
If MouseHook Is Nothing Then
MouseHook = New InputHelper.Hooks.MouseHook
AddHandler MouseHook.MouseDown, AddressOf MouseHook_MouseDown
AddHandler MouseHook.MouseMove, AddressOf MouseHook_MouseMove
AddHandler MouseHook.MouseWheel, AddressOf MouseHook_MouseWheel
End If
End Sub
Example MouseDown
event handler:
Private Sub MouseHook_MouseDown(sender As Object, e As InputHelperLib.InputHelper.Hooks.MouseHookEventArgs)
If e.Button = System.Windows.Forms.MouseButtons.Left AndAlso e.DoubleClick = True Then
MessageBox.Show("Left mouse button was double-clicked.")
End If
End Sub
Example MouseMove
event handler:
Private Sub MouseHook_MouseMove(sender As Object, e As InputHelperLib.InputHelper.Hooks.MouseHookEventArgs)
LogTextBox.AppendText("Mouse moved to (X: " & e.Location.X & ", Y: " & e.Location.Y & ")")
End Sub
Example MouseWheel
event handler:
Private Sub MouseHook_MouseWheel(sender As Object, e As InputHelperLib.InputHelper.Hooks.MouseHookEventArgs)
If e.Delta > 0 AndAlso e.ScrollDirection = InputHelper.Hooks.ScrollDirection.Vertical Then
MessageBox.Show("Mouse scrolled up")
End If
End Sub
And now you have a functioning, global mouse hook!
For more details about the hook and its event args, please have a look at the project's wiki.
Bonus question: Does your solution work when the mouse move/click "event" has been triggered by another software and not by the human who is actually operating the mouse.
Yes and no. It depends on how the other software triggered the event. If it uses SendInput
or alike to simulate actual, physical input then yes. If it uses window messages to target specific windows then no.