2013-06-03 1 views
1

내가이 ISO-LATIN를 사용되도록 스페인 키보드가 후크 내가 필요로하는 모든 키보드 키를 관리하는 코드는 문제가 내 키보드에서 "Keys.Oemtilde"가 "ñ"문자가 될 것이므로 많은 키를 하드 코드해야합니다. 열심히 수정?없이 나를 위해 올바른 문자를 인쇄 할 수있는 방법문제는 내 코드 페이지는 1252</p> <p>내가 키보드 낮은 수준의 후크 클래스를 발견하고 내가 따로 만들어,

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 

답변

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에서 완전히 신뢰할 수있는 이유를 설명하지 못합니다.

+0

한스에 대한 광범위한 설명을 해주셔서 감사합니다. 그러나 저수준의 후크 부분을 잊어 버렸습니다. 가장 큰 문제는 "ChrW (Keys.Oemtilde)"를 사용하면 결과가 " À "문자가 실제로"ñ "이거나 어쩌면 틀렸습니까? 후크를 사용하든 사용하지 않든 "키"열거 형의 특정 문자를 제대로 인식하지 못합니다.이 문제는 OS 언어 나 키보드 언어 또는 이와 유사한 것으로부터 파생 될 수 있으며 코드의 일부를 변경하면 문자를 인식 할 수 있을지도 모른다고 생각했습니다. 이것에 대한 해결책이 있습니까? – ElektroStudios

+0

Keys.Oemtilde와 타이핑 키의 매핑은 키보드 레이아웃 작업입니다. 다른 키보드는 해당 키에 대해 다른 문자를 생성합니다. 기본 winapi 함수는 ToUnicodeEx()입니다. 위에 설명 된대로 키보드 상태 및 레이아웃이 필요한 방법에 유의하십시오. –

관련 문제