3

I'm searching a way to detect mouse and keyboards events in C# and read them (cursor position + key strokes). I read lot of "keyboard hook" stuff, but my problem is that I want to capture these events and then "neutralize" them, I don't know how to say it.

Something similar to what Virtual Box do: it intercept mouse and keyboard and does not "propagate" them to the host system, so, for example, I can press CTRL+TAB, intercept it and prevent windows switching dialog to popup...

Obviosly I will define a special key (RCTRL for example) that let me stop the hook, elsewhere I will never get control back to host :)

4
  • If you register to the windows hotkey event with certain keystrokes, you will be the only one intercepting them. You can do that via the WinApi. Maybe that does the trick for you? Commented Jun 16, 2012 at 11:39
  • And "neutralizing" mouse events isn't really an issue, because you could just intercept and "undo" them. The only way you could REALLY intercept and neutralize mouse and keyboard events is altering the drivers that are in charge of handling the mouse and keyboard devices, which is probably an over-kill for you. Commented Jun 16, 2012 at 11:41
  • @YoryeNathan Ok, but I need to call RegisterHotKey function for every key that can "interfer" with host system?
    – lorenzo-s
    Commented Jun 16, 2012 at 11:48
  • Basically, yes. Any key-combination that you want to neutralize. Commented Jun 16, 2012 at 12:05

1 Answer 1

1

This is the module I use in VB.NET (I'll translate it when I can, but there's an online tool to do that automatically):

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

Here's how you would use it to cancel every keypress:

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

As for the mouse part, VirtualBox doesn't actually cancel all mouse interaction. It either uses mouse integration, which lets you use the mouse as usual (you don't have to do a thing here), or it restricts the captured mouse to a certain area. You can accomplish that in .NET by setting a boundary for the mouse:

System.Windows.Forms.Cursor.Clip = new Rectangle(this.PointToScreen(Point.Empty), this.ClientSize);

Depending on your needs, you may also want to hide the cursor.

Not the answer you're looking for? Browse other questions tagged or ask your own question.