埃里克的绝对正确,没有一个简单的方法来做到这一点。我附上了我的尽力而为的代码,其中我得到了95%的使用方式(使用ToUnicodeEx
)。
它没有赶上特殊(IME /死键)正确的字符(的AltGr - 对英国英语键盘€
)。它的确如此,但是,preserve the state of the kernel-mode keyboard buffer(所以它不会影响键入的高级组合键)。
请注意,此代码不是生产就绪,并需要适当的错误处理等等,它也只在几个键盘布局上进行测试。因人而异。
Public Declare Function UnhookWindowsHookEx Lib "user32" (
ByVal hHook As Integer) As Integer
Public Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (
ByVal idHook As Integer,
ByVal lpfn As KeyboardHookDelegate,
ByVal hmod As Integer,
ByVal dwThreadId As Integer) As Integer
Private Declare Function GetAsyncKeyState Lib "user32" (
ByVal vKey As Integer) As Integer
Private Declare Function CallNextHookEx Lib "user32" (
ByVal hHook As Integer,
ByVal nCode As Integer,
ByVal wParam As Integer,
ByVal lParam As KBDLLHOOKSTRUCT) As Integer
Public Structure KBDLLHOOKSTRUCT
Public vkCode As Integer
Public scanCode As Integer
Public flags As Integer
Public time As Integer
Public dwExtraInfo As Integer
End Structure
' Low-Level Keyboard Constants
Private Const HC_ACTION As Integer = 0
Private Const LLKHF_EXTENDED As Integer = &H1
Private Const LLKHF_INJECTED As Integer = &H10
Private Const LLKHF_ALTDOWN As Integer = &H20
Private Const LLKHF_UP As Integer = &H80
Private Const WH_KEYBOARD_LL As Integer = 13&
Public KeyboardHandle As Integer
Public Declare Function ToUnicodeEx Lib "user32" (wVirtKey As UInteger, wScanCode As UInteger, lpKeyState As Byte(), <Out()> ByVal lpChar As System.Text.StringBuilder, cchBuff As Integer, wFlags As UInteger, dwhkl As IntPtr) As Integer
Public Declare Function GetKeyboardState Lib "user32" (lpKeyState As Byte()) As Boolean
Public Declare Function GetKeyState Lib "user32" (keyCode As Integer) As Short
Private Function ConvertToUnicode(lParam As KBDLLHOOKSTRUCT) As String
Select Case lParam.vkCode
Case 8
Return "{Backspace}"
Case 9
Return "{Tab}"
Case Else
Dim SB As New System.Text.StringBuilder()
Dim KeyState(255) As Byte
'The output from this isn't actually used but it forces the Api
'to evaluate the modifiers for the key code
Dim ModifierState As Integer
GetKeyState(ModifierState)
Dim KeyStateStatus As Boolean = GetKeyboardState(KeyState)
If Not KeyStateStatus Then
Return ""
End If
ToUnicodeEx(CUInt(lParam.vkCode),
CUInt(lParam.scanCode),
KeyState, SB, SB.Capacity, 0,
InputLanguage.CurrentInputLanguage.Handle)
Return SB.ToString()
End Select
End Function
Public Function KeyboardCallback(ByVal Code As Integer,
ByVal wParam As Integer,
ByRef lParam As KBDLLHOOKSTRUCT) As Integer
Try
Dim Key As String = Nothing
If (lParam.flags And LLKHF_EXTENDED) = 0 Then
If (lParam.flags And LLKHF_UP) = 0 Then
Key = ConvertToUnicode(lParam)
End If
Else
Dim KeyCode = DirectCast(lParam.vkCode, System.Windows.Forms.Keys)
If KeyCode <> System.Windows.Forms.Keys.RShiftKey And
KeyCode <> System.Windows.Forms.Keys.LShiftKey Then
If (lParam.flags And LLKHF_UP) = 0 Then
'Special Key pressed
Key = "{" & KeyCode.ToString & "+}"
Else
'Special Key released
Key = "{" & KeyCode.ToString & "-}"
End If
End If
End If
If Key IsNot Nothing Then
Debug.WriteLine(Key)
End If
Catch ex As Exception
'Do something!
End Try
Return CallNextHookEx(KeyboardHandle, Code, wParam, lParam)
End Function
查看'ToAsciiEx'函数。 –
会[RegisterHotKey](http://msdn.microsoft.com/en-us/library/windows/desktop/ms646309.aspx)提供您正在寻找的功能,还是这不会很好地应对游戏/ DirectInput? – IInspectable
感谢@Tim的建议,那就是我开始的地方。不幸的是,在该页面中,如果为热键指定的键击已经被另一个热键注册,则RegisterHotKey将失败。有些游戏似乎使用该技术(或至少使用阻止它的类似方法)。 IIRC Valve的Source Engine可以做到这一点。我同意这会让生活更轻松。 – Basic