我有一个西班牙语键盘,所以它使用ISO-LATIN,我的代码页是1252。
我找到了一个键盘低级钩子类,我分开了一个代码来管理我需要的所有键盘键,问题是例如在我的键盘中“Keys.Oemtilde”将是“ñ”字符,所以我需要对大部分密钥进行硬编码。
如何在没有经过艰难修改的情况下为我打印正确的角色?:
MsgBox(ChrW(Keys.Oemtilde)) ' Result: À
' Correct result woould be: ñ
这是钩子类:
#Region " KeyboardHook Class "
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
Return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam)
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("Could not set keyboard hook")
End If
End Sub
Protected Overrides Sub Finalize()
If Not HHookID = IntPtr.Zero Then
UnhookWindowsHookEx(HHookID)
End If
MyBase.Finalize()
End Sub
End Class
#End Region
......这是我自己的代码:
#Region " KeyLogger "
Public WithEvents KeysHook As New KeyboardHook
Dim Auto_Backspace_Key As Boolean = True
Dim Auto_Enter_Key As Boolean = True
Dim Auto_Tab_Key As Boolean = True
Dim No_F_Keys As Boolean = False
Private Sub KeysHook_KeyDown(ByVal Key As Keys) Handles KeysHook.KeyDown
Select Case Control.ModifierKeys
Case 393216 ' Alt-GR + Key
Select Case Key
Case Keys.D1 : Key_Listener("|")
Case Keys.D2 : Key_Listener("@")
Case Keys.D3 : Key_Listener("#")
Case Keys.D4 : Key_Listener("~")
Case Keys.D5 : Key_Listener("€")
Case Keys.D6 : Key_Listener("¬")
Case Keys.E : Key_Listener("€")
Case Keys.Oem1 : Key_Listener("[")
Case Keys.Oem5 : Key_Listener("\")
Case Keys.Oem7 : Key_Listener("{")
Case Keys.Oemplus : Key_Listener("]")
Case Keys.OemQuestion : Key_Listener("}")
Case Else : Key_Listener("")
End Select
Case 65536 ' LShift/RShift + Key
Select Case Key
Case Keys.D0 : Key_Listener("=")
Case Keys.D1 : Key_Listener("!")
Case Keys.D2 : Key_Listener("""")
Case Keys.D3 : Key_Listener("·")
Case Keys.D4 : Key_Listener("$")
Case Keys.D5 : Key_Listener("%")
Case Keys.D6 : Key_Listener("&")
Case Keys.D7 : Key_Listener("/")
Case Keys.D8 : Key_Listener("(")
Case Keys.D9 : Key_Listener(")")
Case Keys.Oem1 : Key_Listener("^")
Case Keys.Oem5 : Key_Listener("ª")
Case Keys.Oem6 : Key_Listener("¿")
Case Keys.Oem7 : Key_Listener("¨")
Case Keys.OemBackslash : Key_Listener(">")
Case Keys.Oemcomma : Key_Listener(";")
Case Keys.OemMinus : Key_Listener("_")
Case Keys.OemOpenBrackets : Key_Listener("?")
Case Keys.OemPeriod : Key_Listener(":")
Case Keys.Oemplus : Key_Listener("*")
Case Keys.OemQuestion : Key_Listener("Ç")
Case Keys.Oemtilde : Key_Listener("Ñ")
Case Else : Key_Listener("")
End Select
Case Else
If Key.ToString.Length = 1 Then ' Single alpha key
If Control.IsKeyLocked(Keys.CapsLock) Or Control.ModifierKeys = Keys.Shift Then
Key_Listener(Key.ToString.ToUpper)
Else
Key_Listener(Key.ToString.ToLower)
End If
Else
Select Case Key ' Single special key
Case Keys.Add : Key_Listener("+")
Case Keys.Back : Key_Listener("{BackSpace}")
Case Keys.D0 : Key_Listener("0")
Case Keys.D1 : Key_Listener("1")
Case Keys.D2 : Key_Listener("2")
Case Keys.D3 : Key_Listener("3")
Case Keys.D4 : Key_Listener("4")
Case Keys.D5 : Key_Listener("5")
Case Keys.D6 : Key_Listener("6")
Case Keys.D7 : Key_Listener("7")
Case Keys.D8 : Key_Listener("8")
Case Keys.D9 : Key_Listener("9")
Case Keys.Decimal : Key_Listener(".")
Case Keys.Delete : Key_Listener("{Supr}")
Case Keys.Divide : Key_Listener("/")
Case Keys.End : Key_Listener("{End}")
Case Keys.Enter : Key_Listener("{Enter}")
Case Keys.F1 : Key_Listener("{F1}")
Case Keys.F10 : Key_Listener("{F10}")
Case Keys.F11 : Key_Listener("{F11}")
Case Keys.F12 : Key_Listener("{F12}")
Case Keys.F2 : Key_Listener("{F2}")
Case Keys.F3 : Key_Listener("{F3}")
Case Keys.F4 : Key_Listener("{F4}")
Case Keys.F5 : Key_Listener("{F5}")
Case Keys.F6 : Key_Listener("{F6}")
Case Keys.F7 : Key_Listener("{F7}")
Case Keys.F8 : Key_Listener("{F8}")
Case Keys.F9 : Key_Listener("{F9}")
Case Keys.Home : Key_Listener("{Home}")
Case Keys.Insert : Key_Listener("{Insert}")
Case Keys.Multiply : Key_Listener("*")
Case Keys.NumPad0 : Key_Listener("0")
Case Keys.NumPad1 : Key_Listener("1")
Case Keys.NumPad2 : Key_Listener("2")
Case Keys.NumPad3 : Key_Listener("3")
Case Keys.NumPad4 : Key_Listener("4")
Case Keys.NumPad5 : Key_Listener("5")
Case Keys.NumPad6 : Key_Listener("6")
Case Keys.NumPad7 : Key_Listener("7")
Case Keys.NumPad8 : Key_Listener("8")
Case Keys.NumPad9 : Key_Listener("9")
Case Keys.Oem1 : Key_Listener("`")
Case Keys.Oem5 : Key_Listener("º")
Case Keys.Oem6 : Key_Listener("¡")
Case Keys.Oem7 : Key_Listener("´")
Case Keys.OemBackslash : Key_Listener("<")
Case Keys.Oemcomma : Key_Listener(",")
Case Keys.OemMinus : Key_Listener(".")
Case Keys.OemOpenBrackets : Key_Listener("'")
Case Keys.OemPeriod : Key_Listener("-")
Case Keys.Oemplus : Key_Listener("+")
Case Keys.OemQuestion : Key_Listener("ç")
Case Keys.Oemtilde : Key_Listener("ñ")
Case Keys.PageDown : Key_Listener("{AvPag}")
Case Keys.PageUp : Key_Listener("{RePag}")
Case Keys.Space : Key_Listener(" ")
Case Keys.Subtract : Key_Listener("-")
Case Keys.Tab : Key_Listener("{Tabulation}")
Case Else : Key_Listener("")
End Select
End If
End Select
End Sub
Public Sub Key_Listener(ByVal key As String)
If Auto_Backspace_Key AndAlso key = "{BackSpace}" Then ' Delete character
RichTextBox1.Text = RichTextBox1.Text.Substring(0, RichTextBox1.Text.Length - 1)
ElseIf Auto_Enter_Key AndAlso key = "{Enter}" Then ' Insert new line
RichTextBox1.Text += ControlChars.NewLine
ElseIf Auto_Tab_Key AndAlso key = "{Tabulation}" Then ' Insert Tabulation
RichTextBox1.Text += ControlChars.Tab
ElseIf No_F_Keys AndAlso key.StartsWith("{F") Then ' Ommit F Keys
Else ' Print the character
RichTextBox1.Text += key
End If
End Sub
#End Region
答案 0 :(得分:2)
您可以永远编写一个正确的低级键盘钩子,将虚拟键转换为键入键。键盘状态和活动键盘布局是拥有前景窗口的进程的属性。从来没有实现钩子的过程。
特别是键盘状态会出错,你不知道该过程的键盘逻辑状态是否有shift,alt,control和Windows键有效。当程序收到键盘事件时记录该状态。特别是对于使用变音符号的语言的键盘布局是死键的状态,您键入的键以使下一个键入的字母具有重音。此键盘状态是每个进程状态,无法从其他进程检索。它只能在进程本身GetKeyboardState()函数中被发现。对于活动键盘布局,GetKeyboardLayout()函数大致相同。语言栏允许进程使用不同的布局。
使用WH_KEYBOARD挂钩时,它只能正常工作100%。它需要一个可以注入其他进程的DLL。 SetWindowsHookEx()的第三个参数。这确保了GetKeyboardState和GetKeyboardLayout返回准确的信息。你不能在VB.NET中编写这样的DLL,你注入的进程不会加载CLR来执行托管代码。需要像C,C ++或Delphi这样的语言,这些语言具有非常适度的运行时支持要求。这通常是项目逐渐消失的地方。不仅仅是因为运行时注入问题,调试这样的代码以及处理64位操作系统和UAC上的进程的位数是主要问题。
你可以通过使用GetAsyncKeyState()来获取修改键的状态。除了注入的DLL之外,没有死键的解决方案。这不是一个有用的答案,它只是解释了为什么你永远无法在vb.net中完全可靠地工作。