【问题标题】:Capture mouse and keyboard events and in C# and "prevent system propagation"在 C# 中捕获鼠标和键盘事件并“防止系统传播”
【发布时间】:2012-06-16 11:26:53
【问题描述】:

我正在寻找一种方法来在 C# 中检测鼠标和键盘事件并读取它们(光标位置 + 击键)。我读了很多“键盘钩子”的东西,但我的问题是我想捕捉这些事件并然后“中和”它们,我不知道该怎么说。

类似于 Virtual Box 所做的事情:它拦截鼠标和键盘,并且不会将它们“传播”到主机系统,因此,例如,我可以按 CTRL+TAB,拦截它并防止窗口切换对话框弹出...

显然我会定义一个特殊的键(例如RCTRL)让我停止钩子,在其他地方我永远无法将控制权交还给主机:)

【问题讨论】:

  • 如果您使用某些击键注册到 Windows 热键事件,您将是唯一拦截它们的人。您可以通过WinApi 做到这一点。也许这对你有用?
  • 并且“中和”鼠标事件并不是真正的问题,因为您可以拦截并“撤消”它们。真正拦截和消除鼠标和键盘事件的唯一方法是更改​​负责处理鼠标和键盘设备的驱动程序,这对你来说可能是一种过度杀伤。
  • @YoryeNathan 好的,但是我需要为每个可以“干扰”主机系统的键调用 RegisterHotKey 函数?
  • 基本上,是的。您想要中和的任何组合键。
  • 我会试试的,谢谢。

标签: c# keyboard mouse hook


【解决方案1】:

这是我在 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);

根据您的需要,您可能还想隐藏光标。

【讨论】:

    猜你喜欢
    • 2014-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-19
    • 2010-11-09
    • 2021-07-01
    相关资源
    最近更新 更多