KeyboardHook - Können Spiele die Weitergabe von Tastendrücken unterbinden?

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 2 Antworten in diesem Thema. Der letzte Beitrag () ist von rwCapt.

    KeyboardHook - Können Spiele die Weitergabe von Tastendrücken unterbinden?

    Hallo zusammen,

    das Thema KeyHook ist wohl teils brisant, da es missbraucht werden kann, um damit unschöne Programme zu schreiben ... ich möchte hiermit versichern, dass ich das nicht vor habe.

    Mein Problemchen ist nämlich folgendes: Meine CPU ist in die Jahre gekommen und wenn ich Spiele wie GTA offen habe und der PC meint, den GTA-Prozess zu himmeln ("Keine Rückmeldung" wird wohl im Task-Manager stehen), dann friert das Spiel ein und dank des Vollbild-Modus kann ich den Task-Manager nicht öffnen, um den Prozess zu killen.
    Somit habe ich mir gedacht, dass ich mir mal wieder VS herunter lade, auch um zu gucken, wie viel von VB.Net hängen geblieben ist. Den Code für das Abfangen des Tastaturdrucks habe ich mir im Internet zusammen gesucht, genauso den für das Beenden des Prozesses. Das Programm läuft einwandfrei, wenn ich F1 drücke, dann wird der GTA-Prozess beendet. Nur ist mir folgendes aufgefallen: Öffne ich GTA dann noch mal wieder, so kann mein Programm anscheinend die Keys nicht mehr abfangen. Starte ich mein "selbst geschriebenes" Programm neu, dann geht das jedoch wieder (F1 killt dann wieder den GTA-Prozess).
    Die Abfrage des Tastendrucks erfolgt über SetWindowsHookEx. Dieses ist mit dem, "das da zu gehört", in einer eigenen Klasse untergeordnet, das die zwei Events KeyDown und KeyUp ausgibt.
    Ständig das kleine Programm neu zu starten, wenn ich GTA gestartet habe, muss nicht sein. Meine Frage ist nun, wie man wieder die Tastaturabfrage durchführen kann, wenn ein Spiel wie GTA den Fokus neu bekommen hat. Was ich vermute ist, dass GTA auch Hooks registriert und mein KeyboardProc dann zweitrangig wird, wenn das neu gestartete GTA den Fokus hat.

    Gruß Michael
    Yo,

    ich denke einen KeyboardHook brauchst du nicht. Die KeyboardEvents(bzw. die Messages) sollten auch nach dem beenden von GTA noch in deiner App ankommen, evtl. hast du in deinem Code was übersehen, was dieses fehlerhafte Verhalten verursacht. Ohne den Code zu sehen, kann ich nur vermuten. Aber anstatt eines Hooks sollte evtl. ein Hotkey reichen, (RegisterHotkey) oder mit GetAsyncKeyState pollen.
    Also der Code ist der hier.
    Ich probiere nochmal, ob das einfache KeyDown-Event über die Form funktioniert.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class Form1
    3. Dim Procs As New List(Of Process)
    4. Private WithEvents kbHook As New KeyboardHook
    5. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    6. Me.Visible = False
    7. End Sub
    8. Private Sub kbHook__KeyDown(Key As Keys) Handles kbHook.KeyDown
    9. If Key.ToString = "F1" Then
    10. Debug.WriteLine(Key.ToString)
    11. Try
    12. Procs.AddRange(Process.GetProcessesByName("GTA5"))
    13. For Each Proc As Process In Procs.ToArray()
    14. Proc.Kill()
    15. Next
    16. Catch ex As Exception
    17. End Try
    18. ElseIf Key.ToString = "F2" Then
    19. Application.Restart()
    20. Application.Exit()
    21. ElseIf Key.ToString = "F3" Then
    22. Application.Exit()
    23. End If
    24. End Sub
    25. End Class
    26. Public Class KeyboardHook
    27. <DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)>
    28. Private Overloads Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal HookProc As KBDLLHookProc, ByVal hInstance As IntPtr, ByVal wParam As Integer) As Integer
    29. End Function
    30. <DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)>
    31. Private Overloads Shared Function CallNextHookEx(ByVal idHook As Integer, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
    32. End Function
    33. <DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)>
    34. Private Overloads Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Boolean
    35. End Function
    36. <StructLayout(LayoutKind.Sequential)>
    37. Private Structure KBDLLHOOKSTRUCT
    38. Public vkCode As UInt32
    39. Public scanCode As UInt32
    40. Public flags As KBDLLHOOKSTRUCTFlags
    41. Public time As UInt32
    42. Public dwExtraInfo As UIntPtr
    43. End Structure
    44. <Flags()>
    45. Private Enum KBDLLHOOKSTRUCTFlags As UInt32
    46. LLKHF_EXTENDED = &H1
    47. LLKHF_INJECTED = &H10
    48. LLKHF_ALTDOWN = &H20
    49. LLKHF_UP = &H80
    50. End Enum
    51. Public Shared Event KeyDown(ByVal Key As Keys)
    52. Public Shared Event KeyUp(ByVal Key As Keys)
    53. Private Const WH_KEYBOARD_LL As Integer = 13
    54. Private Const HC_ACTION As Integer = 0
    55. Private Const WM_KEYDOWN = &H100
    56. Private Const WM_KEYUP = &H101
    57. Private Const WM_SYSKEYDOWN = &H104
    58. Private Const WM_SYSKEYUP = &H105
    59. Private Delegate Function KBDLLHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
    60. Private KBDLLHookProcDelegate As KBDLLHookProc = New KBDLLHookProc(AddressOf KeyboardProc)
    61. Private HHookID As IntPtr = IntPtr.Zero
    62. Private Function KeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
    63. If (nCode = HC_ACTION) Then
    64. Dim struct As KBDLLHOOKSTRUCT
    65. Select Case wParam
    66. Case WM_KEYDOWN, WM_SYSKEYDOWN
    67. RaiseEvent KeyDown(CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys))
    68. Case WM_KEYUP, WM_SYSKEYUP
    69. RaiseEvent KeyUp(CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys))
    70. End Select
    71. End If
    72. Return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam)
    73. End Function
    74. Public Sub New()
    75. HHookID = SetWindowsHookEx(WH_KEYBOARD_LL, KBDLLHookProcDelegate, System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0)).ToInt32, 0)
    76. If HHookID = IntPtr.Zero Then
    77. Throw New Exception("Could not set keyboard hook")
    78. End If
    79. End Sub
    80. Protected Overrides Sub Finalize()
    81. If Not HHookID = IntPtr.Zero Then
    82. UnhookWindowsHookEx(HHookID)
    83. End If
    84. MyBase.Finalize()
    85. End Sub
    86. End Class