Tastendrücke per Keyboard-Hook an andere Tasten weiterleiten

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Rubiko
Beiträge: 943
Registriert: 25.02.2005 19:43
Computerausstattung: Intel i7 2600k
8GB Ram
GeForce GTX 560 Ti
Wohnort: Schwabach

Tastendrücke per Keyboard-Hook an andere Tasten weiterleiten

Beitrag von Rubiko »

Hallo,

ich habe folgendes Problem.
Ich spiele derzeit ein Onlinespiel bei dem man leider nur mit Pfeiltasten laufen kann (interne die Steuerung umstellen geht hier nicht).
Da ich aber nunmal ein eingefleischter Zocker bin und w,a,s,d die Standardbelegung ist (und damit das Schreiben und benutzen von Hotkeys per F-Tasten einfacher ist) habe ich vor einen Keyboard-Hook
auf diese Tasten zu setzen und wenn diese gedrückt sind, sie an die jeweilige Pfeiltaste weiterzuleiten. Ich benutze also W und gesendet wird an Windows "Pfeiltaste-Hoch".

Folgenden Code aus dem Archiv auf PureArea habe ich gefunden:

Code: Alles auswählen

; German forum: http://robsite.de/php/pureboard/viewtopic.php?t=1693&highlight=hook
; Author: ChaOsKid
; Date: 17. July 2003


; Example for filtering "Strg-Z" from input in an EditorGadget

#Window = 0 

#Gadget_Editor = 0 
#Gadget_Button_Hook = 1 
#Gadget_Button_Exit = 2 

#WindowWidth = 600 
#WindowHeight = 300 
#minWindowWidth = 100 
#minWindowHeight = 50 

Global hook.l 

Procedure OpenMainWindow() 
  Result = OpenWindow(#Window, 0, 0, #WindowWidth, #WindowHeight, "Strg+Z Hook", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar) 
  If Result 
    If CreateGadgetList(WindowID(#Window)) 
      EditorGadget(#Gadget_Editor, 10, 10, #WindowWidth - 20, #WindowHeight - 60) 
      ButtonGadget(#Gadget_Button_Hook, 10, WindowHeight(#Window) - 40, 120, 30, "Hook Einschalten") 
      ButtonGadget(#Gadget_Button_Exit, WindowWidth(#Window) - 70, WindowHeight(#Window) - 40, 60, 30, "Exit") 
    EndIf 
  EndIf 
ProcedureReturn Result 
EndProcedure 
; 

Procedure WindowCallback(WindowID, Message, wParam, lParam) 
  Select Message 
    Case #WM_SIZE 
      If WindowWidth(#Window) < #minWindowWidth Or WindowHeight(#Window) < #minWindowHeight 
        If WindowWidth(#Window) < #minWindowWidth 
          ResizeWindow(#minWindowWidth, 0, 0, WindowWidth(#Window), WindowHeight(#Window)) 
        EndIf 
        If WindowHeight(#Window) < #minWindowHeight 
          ResizeWindow(#Window, 0, 0, WindowWidth(#Window), #minWindowHeight) 
        EndIf 
      Else 
        ResizeGadget(#Gadget_Editor, -1, -1, WindowWidth(#Window) - 20, WindowHeight(#Window) - 60) 
        ResizeGadget(#Gadget_Button_Hook, -1, WindowHeight(#Window) - 40, -1, -1) 
        ResizeGadget(#Gadget_Button_Exit, WindowWidth(#Window) - 70, WindowHeight(#Window) - 40, -1, -1) 
      EndIf 
  EndSelect 
  ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure 
; 
  
Procedure.l KeyboardHook(nCode.l, wParam.l, lParam.l) 
  If nCode < 0 
    ProcedureReturn CallNextHookEx_(hook, nCode, wParam, lParam) 
  EndIf
      If wParam = 87 
      ; Debug RSet(Bin(lParam), 32,"0") 
      ; Debug "HOOKED" 
      ProcedureReturn 1
ProcedureReturn CallNextHookEx_(hook, nCode, wParam, lParam) 
EndProcedure 
; 
If OpenMainWindow() 
  SetWindowCallback(@WindowCallback()) 
  Repeat 
    Select WaitWindowEvent() 
      Case #PB_Event_Gadget 
        Select EventGadget() 
          Case #Gadget_Button_Hook 
            If Aktiv ; aktiv dann ausschalten 
              UnhookWindowsHookEx_(hook) 
;              Debug "HOOK AUS" 
              Aktiv = 0 
              SetGadgetText(#Gadget_Button_Hook, "Hook Einschalten") 
            Else ; hook einschalten 
              hInstance = GetModuleHandle_(0) 
              lpdwProcessId = GetWindowThreadProcessId_(WindowID(#Window), 0) 
              hook = SetWindowsHookEx_(#WH_KEYBOARD, @KeyboardHook(), hInstance, lpdwProcessId) 
;              Debug "HOOK AN" 
              Aktiv = 1 
              SetGadgetText(#Gadget_Button_Hook, "Hook Ausschalten") 
            EndIf 
          Case #Gadget_Button_Exit 
            quit = 1 
;          Case #Gadget_Editor 
        EndSelect 
      Case #PB_Event_CloseWindow  
        quit = 1 
    EndSelect 
  Until quit 
EndIf 

If Aktiv 
  UnhookWindowsHookEx_(hook) 
  ; Debug "HOOK ausschalten nicht vergessen !" 
EndIf 
End 

; ExecutableFormat=Windows
; FirstLine=1
; EnableXP
; EOF
funktioniert prima, W lässt sich hooken aber ich bin nunmal ein Anfänger in diesem Bereich und deshalb die Frage:
Welche Befehle brauche ich nun um stattdessen "Pfeiltaste-Hoch" zu senden?
Da ich keine Ahnung habe wie der Befehl lautet den man hier benutzen müsste kann ich auch meine Lösungsidee, die ohnehin nicht klappen wird, nicht testen.
Diese wäre nach dem gesetzen Hook die Taste zu überprüfen und stattdessen eben die jeweilige Pfeiltaste zu senden... in etwa

Code: Alles auswählen

; Pseudocode
...
      If wParam = 87 
      ProcedureReturn 1
      If GetAsyncKeyState_(#VK_W)
          SendKey(#VK_ARROW_UP)
      Endif
...
ich geh aber nun mal schwer davon aus, dass sich nach gesetzem Hook das überhaupt noch so überprüfen lässt.
Hat jemand eine Idee oder kann mir Tipps geben?

Vielen Dank im voraus,
Rubiko
Ich wollte die Welt verändern, doch Gott gab mir nicht den Quelltext.
Burstnibbler
Beiträge: 58
Registriert: 04.10.2008 12:10

Re: Tastendrücke per Keyboard-Hook an andere Tasten weiterleiten

Beitrag von Burstnibbler »

Hallo,

ich habe aus deinem Code mal die Prozedur: Procedure.l KeyboardHook(nCode.l, wParam.l, lParam.l) ein bisschen verändert.

Code: Alles auswählen

Procedure.l KeyboardHook(nCode.l, wParam.l, lParam.l)
Protected Check.l=#True
 
  If nCode < 0 
    ProcedureReturn CallNextHookEx_(hook, nCode, wParam, lParam) 
  EndIf
  
  Select wParam
   Case #VK_W : keybd_event_(#VK_UP,   $48,#KEYEVENTF_EXTENDEDKEY,#Null)
   Case #VK_S : keybd_event_(#VK_DOWN, $50,#KEYEVENTF_EXTENDEDKEY,#Null) 
   Case #VK_A : keybd_event_(#VK_LEFT, $4B,#KEYEVENTF_EXTENDEDKEY,#Null) 
   Case #VK_D : keybd_event_(#VK_RIGHT,$4D,#KEYEVENTF_EXTENDEDKEY,#Null)
   Default : Check=#False
  EndSelect 
      
If Check : ProcedureReturn 1 : EndIf     
ProcedureReturn CallNextHookEx_(hook, nCode, wParam, lParam) 
EndProcedure 
Noch ´ne Anmwerkung:
Laut MSDN, ist die Funktion Keybd_event() etwas "Outdated" und wurde durch SendInput_() ersetzt (welche aber etwas umständlicher zu proggen ist - darum habe ich´s gelassen :mrgreen: ).

Mfg,
Burstnibbler
Benutzeravatar
Rubiko
Beiträge: 943
Registriert: 25.02.2005 19:43
Computerausstattung: Intel i7 2600k
8GB Ram
GeForce GTX 560 Ti
Wohnort: Schwabach

Re: Tastendrücke per Keyboard-Hook an andere Tasten weiterleiten

Beitrag von Rubiko »

Vielen Dank, das klappt super! Bis auf eine Sache...
mir ist jetzt leider aufgefallen, dass sich das ganze nur auf das Editorfeld des Programms bezieht und der Hook bei anderen Programmen garnicht erst reagiert. :(

Lässt sich das ändern?

Aber danke schon einmal für die Antwort
Ich wollte die Welt verändern, doch Gott gab mir nicht den Quelltext.
Burstnibbler
Beiträge: 58
Registriert: 04.10.2008 12:10

Re: Tastendrücke per Keyboard-Hook an andere Tasten weiterleiten

Beitrag von Burstnibbler »

Rubiko hat geschrieben:... Lässt sich das ändern?
Ja, entweder als globaler oder lokaler Hook - über den Umweg einer DLL.
Die globale Variante ist zwar nicht die feine Englische, aber dafür leichter umzusetzen.

Globale Variante:

Code: Alles auswählen

;Diesen Code als Shared_Dll kompilieren
ProcedureDLL KeyboardHook(nCode.l,wParam.l,lParam.l)
Protected Check.l=#True 
; 
If nCode=#HC_ACTION 
 Select wParam
  Case #VK_W : keybd_event_(#VK_UP,   $48,#KEYEVENTF_EXTENDEDKEY,#Null)
  Case #VK_S : keybd_event_(#VK_DOWN, $50,#KEYEVENTF_EXTENDEDKEY,#Null) 
  Case #VK_A : keybd_event_(#VK_LEFT, $4B,#KEYEVENTF_EXTENDEDKEY,#Null) 
  Case #VK_D : keybd_event_(#VK_RIGHT,$4D,#KEYEVENTF_EXTENDEDKEY,#Null)
  Default : Check=#False
 EndSelect 
Else
 Check=#False
EndIf
;
If Check : ProcedureReturn 1 : EndIf
ProcedureReturn CallNextHookEx_(@KeyboardHook(),nCode,wParam,lParam)
EndProcedure
;

Code: Alles auswählen

EnableExplicit
;
#G_Txt=0
#G_Btn=1
#Lazy= 0
#Bizzy=1
#Lib=  0
#DLL_Name="MyKeyHook.dll" ;eventuell anpassen
#WinF=#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered
;
Prototype.l Proto_KeyHook(nCode.l,wParam.l,lParam.l)
Define.l Quit, Hooker
Define.l hMod, hHook 
;
hMod=OpenLibrary(#Lib,#DLL_Name)
If Not hMod    : End : EndIf
Global KeyHook.Proto_KeyHook=GetFunction(#Lib,"KeyboardHook")
If Not KeyHook : End : EndIf
;
OpenWindow(0,0,0,200,80,"Hook",#WinF)
TextGadget(#G_Txt,10,10,180,20,"Kein Haken in der Tastatur.",#PB_Text_Center)
ButtonGadget(#G_Btn,50,40,100,20,"Haken rein !")
;
Repeat 
 Select WaitWindowEvent()
  Case #PB_Event_Gadget
   If EventGadget()=#G_Btn
    Select Hooker
     Case #Lazy
      hHook=SetWindowsHookEx_(#WH_KEYBOARD,KeyHook,hMod,#Null)
      SetGadgetText(#G_Txt,"Tastatur hängt am Haken.")
      SetGadgetText(#G_Btn,"Haken raus !")
      Hooker!1
     Case #Bizzy
      UnhookWindowsHookEx_(hHook)
      SetGadgetText(#G_Txt,"Kein Haken in der Tastatur.")
      SetGadgetText(#G_Btn,"Haken rein !")
      Hooker!1
    EndSelect
   EndIf
  Case #PB_Event_CloseWindow : Quit!1
 EndSelect
Until Quit
;
If Hooker : UnhookWindowsHookEx_(hHook) : EndIf
End
;
Für die lokale Variante müsstest Du die Konstante #Null, durch die ThreadId des Browsers austauschen.

Und wieder ´ne Anmerkung:
Ich hab den Code nur mit Textfeldern getestet, keine Ahnung ob er auch bei Browserspielen funktioniert, da ich die Dinger nicht anrühre.
Naja, einfach mal testen. :mrgreen:

MfG,
Burstnibbler
Benutzeravatar
Rubiko
Beiträge: 943
Registriert: 25.02.2005 19:43
Computerausstattung: Intel i7 2600k
8GB Ram
GeForce GTX 560 Ti
Wohnort: Schwabach

Re: Tastendrücke per Keyboard-Hook an andere Tasten weiterleiten

Beitrag von Rubiko »

Vielen Dank für die große Hilfe, klappt super! :D
Übrigens kein Browsergame sondern ein 2D MMorpg(Tibia)
Ich wollte die Welt verändern, doch Gott gab mir nicht den Quelltext.
Antworten