-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMouseHook.vb
142 lines (114 loc) · 6.04 KB
/
MouseHook.vb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
Imports System.Runtime.InteropServices
Public Class MouseHook : Implements IDisposable
Private Const HC_ACTION As Integer = 0
Private Const WH_MOUSE_LL As Integer = 14
Private Const WM_MOUSEMOVE As Integer = &H200
Public Delegate Function MouseHookCallBack(nCode As Integer, wParam As IntPtr, lParam As IntPtr) As Integer
<DllImport("Kernel32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)>
Public Shared Function GetModuleHandle(ByVal ModuleName As String) As IntPtr : End Function
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)>
Public Shared Function SetWindowsHookEx(idHook As Integer, HookProc As MouseHookCallBack,
hInstance As IntPtr, ThreadId As Integer) As IntPtr : End Function
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)>
Public Shared Function CallNextHookEx(hHook As IntPtr, nCode As Integer,
wParam As IntPtr, lParam As IntPtr) As Integer : End Function
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)>
Public Shared Function UnhookWindowsHookEx(hHook As IntPtr) As Boolean : End Function
Public hwnd As IntPtr = IntPtr.Zero
Friend rcC As RECT
Private Shared HookHandle As IntPtr = IntPtr.Zero
Private Function MouseProc(
ByVal nCode As Integer,
ByVal wParam As IntPtr,
ByVal lParam As IntPtr) As Integer
If nCode < HC_ACTION Then Return CallNextHookEx(HookHandle, nCode, wParam, lParam)
If (nCode = HC_ACTION) Then
Select Case wParam.ToInt32()
Case WM_MOUSEMOVE
'Debug.Print($"{hwnd}")
If hwnd = IntPtr.Zero Then Exit Select
If hwnd <> GetForegroundWindow() Then
If Not cursorShow Then
pointer(True)
End If
Exit Select 'GetForegroundWindow() can be IntPtr.Zero when switching active app
Else
If cursorShow Then
pointer(False)
End If
End If
'We only care about the first member so we marshal directly to a point
Dim cpos As Point = Marshal.PtrToStructure(Of Point)(lParam) 'cursor position
'top left corner
Dim ptCTL = New Point(0, 0)
ClientToScreen(hwnd, ptCTL)
'bottom right corner
Dim ptCBR = New Point(rcC.right - 1, rcC.bottom) 'needs -1 or right border gets stuck
ClientToScreen(hwnd, ptCBR)
If cpos.X < ptCTL.X AndAlso cpos.Y < ptCTL.Y Then 'top left corner
Cursor.Position = ptCTL 'New Point(ptCTL.X, ptCTL.Y)
Return 1
ElseIf cpos.X > ptCBR.X AndAlso cpos.Y < ptCTL.Y Then 'top right corner
Cursor.Position = New Point(ptCBR.X, ptCTL.Y)
Return 1
ElseIf cpos.X > ptCBR.X AndAlso cpos.Y > ptCBR.Y Then 'bottom right corner
Cursor.Position = ptCBR 'New Point(ptCBR.X, ptCBR.Y)
Return 1
ElseIf cpos.X < ptCTL.X AndAlso cpos.Y > ptCBR.Y Then 'bottom left corner
Cursor.Position = New Point(ptCTL.X, ptCBR.Y)
Return 1
ElseIf cpos.X < ptCTL.X Then 'left border
Cursor.Position = New Point(ptCTL.X, cpos.Y)
Return 1
ElseIf cpos.X > ptCBR.X Then 'right border
Cursor.Position = New Point(ptCBR.X, cpos.Y)
Return 1
ElseIf cpos.Y > ptCBR.Y Then 'bottom border
Cursor.Position = New Point(cpos.X, ptCBR.Y)
Return 1
ElseIf cpos.Y < ptCTL.Y Then 'top border with exception to be able to drag window
Dim pci As New CURSORINFO With {.cbSize = Marshal.SizeOf(GetType(CURSORINFO))}
GetCursorInfo(pci)
If pci.flags = 0 Then 'Cursor is not visible
Cursor.Position = New Point(cpos.X, ptCTL.Y)
Return 1
End If
End If
End Select
End If
Return CallNextHookEx(HookHandle, nCode, wParam, lParam)
End Function
Private mhCallBack As MouseHookCallBack = New MouseHookCallBack(AddressOf MouseProc)
Private disposedValue As Boolean
Public Sub HookMouse()
HookHandle = SetWindowsHookEx(WH_MOUSE_LL, mhCallBack,
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0)
If HookHandle = IntPtr.Zero Then Throw New System.Exception("Mouse hook failed")
End Sub
Public Sub UnhookMouse()
If HookHandle <> IntPtr.Zero Then UnhookWindowsHookEx(HookHandle)
End Sub
Protected Overridable Sub Dispose(disposing As Boolean)
If Not disposedValue Then
If disposing Then
' TODO: dispose managed state (managed objects)
End If
' TODO: free unmanaged resources (unmanaged objects) and override finalizer
UnhookMouse()
' TODO: set large fields to null
disposedValue = True
End If
End Sub
' TODO: override finalizer only if 'Dispose(disposing As Boolean)' has code to free unmanaged resources
Protected Overrides Sub Finalize()
' Do not change this code. Put cleanup code in 'Dispose(disposing As Boolean)' method
Dispose(disposing:=False)
MyBase.Finalize()
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in 'Dispose(disposing As Boolean)' method
Dispose(disposing:=True)
GC.SuppressFinalize(Me)
End Sub
End Class