Низкоуровневый хук клавиатуры не распознает нажатия клавиш VB.NET
Я успешно практиковал низкоуровневые зацепки клавиатуры в Visual Basic 2010 (.NET Framework v4.0), затем перенес этот же проект перехвата в Visual Studio 2017 (.NET Framework 4.5.2), и теперь он не обнаруживает нажатий клавиш, Я уже пытался изменить целевой фреймворк на v4.0, но безрезультатно.
Вот мой код:
'Form1
Private WithEvents KbHook As KeyboardHook
Private Sub KbHook_KeyDown(Keycode As Keys) Handles KbHook.KeyDown
MessageBox.Show("Key pressed!")
End Sub
И класс KeyboardHook:
Imports System.Runtime.InteropServices
Public Class KeyboardHook
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)>
Private Overloads Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal HookProc As KBDLLHookProc, ByVal hInstance As IntPtr, ByVal wParam As Integer) As Integer
End Function
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)>
Private Overloads Shared Function CallNextHookEx(ByVal idHook As Integer, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Function
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)>
Private Overloads Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Boolean
End Function
<StructLayout(LayoutKind.Sequential)>
Private Structure KBDLLHOOKSTRUCT
Public vkCode As UInt32
Public scanCode As UInt32
Public flags As KBDLLHOOKSTRUCTFlags
Public time As UInt32
Public dwExtraInfo As UIntPtr
End Structure
<Flags()>
Private Enum KBDLLHOOKSTRUCTFlags As UInt32
LLKHF_EXTENDED = &H1
LLKHF_INJECTED = &H10
LLKHF_ALTDOWN = &H20
LLKHF_UP = &H80
End Enum
Public Shared Event KeyDown(ByVal Key As Keys)
Public Shared Event KeyUp(ByVal Key As Keys)
Private Const WH_KEYBOARD_LL As Integer = 13
Private Const HC_ACTION As Integer = 0
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Private Const WM_SYSKEYDOWN = &H104
Private Const WM_SYSKEYUP = &H105
Private Delegate Function KBDLLHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
Private KBDLLHookProcDelegate As KBDLLHookProc = New KBDLLHookProc(AddressOf KeyboardProc)
Private HHookID As IntPtr = IntPtr.Zero
Private Function KeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
If (nCode = HC_ACTION) Then
Dim struct As KBDLLHOOKSTRUCT
Select Case wParam
Case WM_KEYDOWN, WM_SYSKEYDOWN
RaiseEvent KeyDown(CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys))
Case WM_KEYUP, WM_SYSKEYUP
RaiseEvent KeyUp(CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys))
End Select
End If
Dim ret As Integer = CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam)
Return ret
End Function
Public Sub New()
HHookID = SetWindowsHookEx(WH_KEYBOARD_LL, KBDLLHookProcDelegate, System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0)).ToInt32, 0)
If HHookID = IntPtr.Zero Then
Throw New Exception("Error!")
End If
End Sub
Protected Overrides Sub Finalize()
If Not HHookID = IntPtr.Zero Then
UnhookWindowsHookEx(HHookID)
End If
MyBase.Finalize()
End Sub
End class
В Form1 установлена точка останова на
Private Sub KbHook_KeyDown(Keycode As Keys) Handles KbHook.KeyDown
но приложение никогда не ломается при наборе текста на моей клавиатуре. Я довольно запутался, так как он работал в VB2010... У кого-нибудь есть подсказки, как решить проблему?
Заранее спасибо;)
1 ответ
Спасибо за приведенный выше код blondkarol и Джиму Хьюитту. Я заставил его работать в .net 3.5. а у меня в 4.8 не работает. Поэтому я включил некоторый код из другого поста и получил следующий код для работы в .net 4.8.
Imports System.Runtime.InteropServices
Public Class LL_KeyboardHook
Public Delegate Function CallBack(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
<DllImport("user32.dll")>
Public Shared Function SetWindowsHookEx(idHook As Integer, lpfn As CallBack, hMod As IntPtr, dwThreadId As Integer) As IntPtr
End Function
<DllImport("user32.dll")>
Private Shared Function UnhookWindowsHookEx(idHook As IntPtr) As Integer
End Function
<DllImport("user32.dll")>
Private Shared Function CallNextHookEx(idHook As IntPtr, nCode As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
End Function
<StructLayout(LayoutKind.Sequential)>
Private Structure KBDLLHOOKSTRUCT
Public vkCode As UInteger
Public scanCode As UInteger
Public flags As UInteger
Public time As UInteger
Public dwExtraInfo As UInteger
End Structure
Private Const WH_KEYBOARD_LL As Integer = 13
Private Const HC_ACTION As Integer = 0
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Private Const WM_SYSKEYDOWN = &H104
Private Const WM_SYSKEYUP = &H105
Private Delegate Function KBDLLHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
Private HHookID As IntPtr = IntPtr.Zero
Public Shared Event KeyDown(ByVal Key As Keys)
Public Shared Event KeyUp(ByVal Key As Keys)
Private Function KeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
Dim Key As Keys
If (nCode = HC_ACTION) Then
Dim struct As KBDLLHOOKSTRUCT
Select Case wParam
Case WM_KEYDOWN, WM_SYSKEYDOWN
Key = CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys)
RaiseEvent KeyDown(Key)
'example below to intercept and not pass along the "A" down key
'If Key.ToString = "A" Then
' Return 1
' Exit Function
'End If
Case WM_KEYUP, WM_SYSKEYUP
Key = CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys)
RaiseEvent KeyUp(Key)
End Select
End If
Dim ret As Integer = CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam)
Return ret
End Function
Public Sub New()
Static WindowsHookProc = New CallBack(AddressOf KeyboardProc)
HHookID = SetWindowsHookEx(WH_KEYBOARD_LL, WindowsHookProc, IntPtr.Zero, 0)
If HHookID = IntPtr.Zero Then
Throw New Exception("Error!")
End If
End Sub
Protected Overrides Sub Finalize()
If Not HHookID = IntPtr.Zero Then
UnhookWindowsHookEx(HHookID)
End If
MyBase.Finalize()
End Sub
End Class
Чтобы использовать код в форме:
Private WithEvents kbHook As New LL_KeyboardHook
Private Sub kbHook_KeyDown(Key As Keys) Handles kbHook.KeyDown
Debug.WriteLine(Key)
End Sub
Private Sub kbHook_KeyUp(Key As Keys) Handles kbHook.KeyUp
Debug.WriteLine(Key)
End Sub