在 C# 中捕获鼠标和键盘事件,并“防止系统传播”
本文关键字:系统 传播 事件 鼠标 键盘 | 更新日期: 2023-09-27 18:37:20
我正在寻找一种在 C# 中检测鼠标和键盘事件并读取它们的方法(光标位置 + 击键)。我读了很多"键盘钩子"的东西,但我的问题是我想捕捉这些事件然后"中和"它们,我不知道怎么说。
类似于Virtual Box所做的:它拦截鼠标和键盘并且不会将它们"传播"到主机系统,因此,例如,我可以按 CTRL+TAB
,拦截它并防止窗口切换对话框弹出...
显然,我将定义一个特殊的键(例如RCTRL
)让我停止钩子,在其他地方我永远不会将控制权交还给主机:)
这是我
在 VB.NET 中使用的模块(我会尽可能翻译它,但有一个在线工具可以自动执行此操作):
Imports System.Runtime.InteropServices
Public Module KeyboardHook
<DllImport("user32.dll")>
Public Function SetWindowsHookEx(ByVal idHook As Integer, ByVal HookProc As KBDLLHookProc, ByVal hInstance As IntPtr, ByVal wParam As Integer) As IntPtr
End Function
<DllImport("user32.dll")>
Public Function CallNextHookEx(ByVal idHook As IntPtr, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Function
<DllImport("user32.dll")>
Public Function UnhookWindowsHookEx(ByVal idHook As IntPtr) As Boolean
End Function
<StructLayout(LayoutKind.Sequential)>
Public Structure KBDLLHOOKSTRUCT
Public vkCode As UInteger
Public scanCode As UInteger
Public flags As KBDLLHOOKSTRUCTFlags
Public time As UInteger
Public dwExtraInfo As UIntPtr
End Structure
<Flags()>
Public Enum KBDLLHOOKSTRUCTFlags As UInteger
LLKHF_EXTENDED = &H1
LLKHF_INJECTED = &H10
LLKHF_ALTDOWN = &H20
LLKHF_UP = &H80
End Enum
Public Const WH_KEYBOARD_LL As Integer = 13
Public Const HC_ACTION As Integer = 0
Public Const WM_KEYDOWN As Integer = &H100
Public Const WM_KEYUP As Integer = &H101
Public Const WM_SYSKEYDOWN As Integer = &H104
Public Const WM_SYSKEYUP As Integer = &H105
Public Delegate Function KBDLLHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Module
以下是使用它来取消每次按键的方法:
Private hook As IntPtr
Private isVisible As Boolean = False
Private keyHookDelegate As New KBDLLHookProc(AddressOf Me.KeyHook)
Private Sub Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Set the key hook:
hook = SetWindowsHookEx(KeyboardHook.WH_KEYBOARD_LL, Me.keyHookDelegate, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()(0)), 0)
If hook = IntPtr.Zero Then
MessageBox.Show("Failed to set global key hook.", "Key Hook Set Failiure", MessageBoxButtons.OK, MessageBoxIcon.Error)
Throw New ApplicationException("Failed to set key hook.")
End If
End Sub
Private Function KeyHook(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
If nCode = KeyboardHook.HC_ACTION Then
Dim p As Integer = wParam.ToInt32()
If p = WM_KEYDOWN OrElse p = WM_SYSKEYDOWN Then
Dim keyCode As Keys = CType(CType(Marshal.PtrToStructure(lParam, GetType(KBDLLHOOKSTRUCT)), KBDLLHOOKSTRUCT).vkCode, Keys) ' This gets the key that was pressed.
'Cancel it!
Return 1
End If
End If
Return KeyboardHook.CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam)
End Function
Protected Overrides Sub Finalize()
Try
'Remove the key hook:
If hook <> IntPtr.Zero Then KeyboardHook.UnhookWindowsHookEx(hook)
Finally
MyBase.Finalize()
End Try
End Sub
至于鼠标部分,VirtualBox实际上并没有取消所有鼠标交互。它要么使用鼠标集成,让您像往常一样使用鼠标(您不必在这里做任何事情),要么将捕获的鼠标限制在某个区域。可以通过设置鼠标边界在 .NET 中实现此目的:
System.Windows.Forms.Cursor.Clip = new Rectangle(this.PointToScreen(Point.Empty), this.ClientSize);
根据您的需要,您可能还希望隐藏光标。