Seite 1 von 1

Problem GetAsyncKeystate

Verfasst: 25.07.2022 10:17
von Franky_FR
Hallo,

ich suche eine Möglichkeit abzufragen, ob IRGENDEINE Taste gedrückt wird. Die Keyboard-Bibliothek funktioniert ja nur mit Screen und DirectX.
Hier im Forum bin ich dann auf GetAsyncKeystate gestoßen, aber damit kann man ja nur eine Taste abfragen.
Nun bin ich auf folgende Idee gekommen:

Code: Alles auswählen


x=0     

Repeat
  
 x=x+1
  Debug x
  If x=255 
    x=0
    EndIf
  Until GetAsyncKeyState_(x) <>0
Das Problem: das Programm beendet sich immer an unterschiedlichen Tastenwerten, so als ob die Tasten gedrückt würden.
Wenn ich nicht von 0-255 abfrage, sondern die Tasten z.b. 0-9, funktioniert es meistens, aber auch nicht immer.
Warum beendet sich das Proogramm, die Tasten werden doch nicht gedrückt ?
Irgendein anderer Process kann es doch auch nicht sein, oder ? Da dürfte auch nichts im Hintergrund eine Taste bedienen ? :roll:

Re: Problem GetAsyncKeystate

Verfasst: 25.07.2022 12:16
von HeX0R
Weil Du GetAsyncKeyState() falsch benutzt, siehe =>
https://docs.microsoft.com/en-us/window ... nckeystate

Wenn Du wissen möchtest, ob eine Taste gedrückt ist, musst Du das so ändern:

Code: Alles auswählen

Until GetAsyncKeyState_(x) & $8000 <>0

Re: Problem GetAsyncKeystate

Verfasst: 25.07.2022 16:11
von Axolotl
Kann man so machen ...
Die (Baumarkt-) Frage ist natürlich wofür brauchst du das?
Evtl. gibt es bessere Lösungen: z.B. WM_KEYDOWN, Hotkey, KeyboardHooks, ...

Re: Problem GetAsyncKeystate

Verfasst: 26.07.2022 13:56
von Franky_FR
Ich wollte einfach nur eine Routine, die auf keine spezielle Taste warte, sondern irgendeinen Tastendruck, z.B. nachdem man einen Text anzeigt,
den der User lesen soll. Hast Du für WM_KEYDOWN, Hotkey, KeyboardHooks kleine Beispiele ?
Insbesondere mit den Keyboardhooks kenne ich mich nicht aus... (Callbacks ?) Für Callbacks wäre ein Tutorial mal toll !

Re: Problem GetAsyncKeystate

Verfasst: 26.07.2022 14:01
von Franky_FR
Wen es interessiert, ich habe jetzt eine kleine Routine zur Keyboardabfrage und GetAsyncKeystate als Inputroutine geschrieben:

Code: Alles auswählen

X=0; von 0-255 Tastatur abfragen

Procedure KeyInput()

Repeat
  Shared PressedKey
  Shared X
  X=X+1
  ;Debug x
  If X=255
    X=0
    EndIf
  Until GetAsyncKeyState_(X) & $8000 <>0 ;Taste gedrückt
  PressedKey=X
  
EndProcedure




Repeat 
  KeyInput()
  If GetAsyncKeyState_(#VK_RETURN) & $8000 <>0   ;Return gedrückt - break
    Break
  EndIf

  Debug PressedKey 

  Repeat
  Until GetAsyncKeyState_(PressedKey) & $8000 =0    ; gedrückte Taste wieder losgelasssen
  Input$=Input$+Chr(PressedKey)     ;Tasteneingaben in String
  X=0
  
  
Until GetAsyncKeyState_(#VK_RETURN) & $8000 <>0   ;Return nicht gedrückt


Debug Input$


Re: Problem GetAsyncKeystate

Verfasst: 26.07.2022 14:12
von Franky_FR
HeX0R hat geschrieben: 25.07.2022 12:16 Weil Du GetAsyncKeyState() falsch benutzt, siehe =>
https://docs.microsoft.com/en-us/window ... nckeystate

Wenn Du wissen möchtest, ob eine Taste gedrückt ist, musst Du das so ändern:

Code: Alles auswählen

Until GetAsyncKeyState_(x) & $8000 <>0
Ich hatte mir die MS-Doc durchgelesen, das mit dem HighByte war mir nur nicht richtig klargewesen.
Verstehen tue ich das allerdings immer noch nicht richtig: wenn das HBit gesetzt ist, müsste ein Vergleich mit <> 0 doch auch
funktionieren, auch ohne bitweisen Vergleich mit & ??

EDIT : bin wohl gerade selbst drauf gekommen, weil das Low-Bit wie in der Doc beschrieben irgendwo gesetzt wird von einem anderen Prozess ?

Re: Problem GetAsyncKeystate

Verfasst: 27.07.2022 11:51
von Axolotl
Franky_FR hat geschrieben: 26.07.2022 13:56 ... Hast Du für WM_KEYDOWN, Hotkey, KeyboardHooks kleine Beispiele ? ...
Weil du so nett gefragt hast.
Zum Thema KeyboardHooks hatte ich mal im englischen Forum was gepostet.
LowLevelKeyboardHook.pb

Ein etwas größeres Beispiel, dafür ist alles drin! (außer console)
Je nachdem ob du Windows Nachrichten mit WM_HOTKEY, WM_KEYDOWN in der Mainloop, Callback oder in Subclass Proceduren abfragen möchtest.
Hinweis: Nicht alle WM_* Nachrichten werden in der Mainloop bereitgestellt. So etwas ändert sich schonmal von einer PB-Version zur nächsten. (Beispiel: WM_Close) Es gibt unzählige alte Beispiele (für alte PB-Versionen) wo das mal funktioniert hatte....
Ach so, der Unterschied zwischen Callback und Subclass: Callback geht pro window nur eine, subclass gehen viele.

Okay, hier der Code.
Fragen? Fragen!

Code: Alles auswählen

;:: FILE        : <New> 
;:: Target OS   : Windows
;:: License     : Free, unrestricted, no warranty whatsoever
;::               Use at your own risk
;::
;:: Copyright (c) 2022 by AHa 

CompilerIf #PB_Compiler_IsMainFile ;/--- Template for Testing 
  EnableExplicit 

  Enumeration EWindow 1 
    #WINDOW_Main 
  EndEnumeration 
  
  Enumeration EGadget 1 
    #GADGET_btnClick 
    #GADGET_edtOutput 
  EndEnumeration 

  #HotKey  = 1  
  #MOD_NOREPEAT  = $4000  ; not defined by default 

  ; --- constants 

  #PB_Window_MainFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget 

  ; --- global variables 

  Global Hotkey_Registered = #False 


  ; --- windows API (windows only) 

  Procedure.s GetKeyNameText(lParam) 
    Protected string.s{80} 
    If GetKeyNameText_(lParam, @string, 80) 
      ProcedureReturn string 
    EndIf 
    ProcedureReturn "" 
  EndProcedure 


  ; --- Hotkey Helpers 
  
  Procedure AddHotKey(Window, Hotkey, Modifier, VirtKey) 
    If IsWindow(Window) And Hotkey_Registered = #False
      If Modifier <> 0 And VirtKey <> 0 
        RegisterHotKey_(WindowID(Window), Hotkey, Modifier, VirtKey) 
        Hotkey_Registered = #True 
      EndIf 
    EndIf 
  EndProcedure

  Procedure RemoveHotKey(Window, Hotkey)  
    If IsWindow(Window) And Hotkey_Registered 
      UnregisterHotKey_(WindowID(Window), Hotkey) 
      Hotkey_Registered = #False 
    EndIf 
  EndProcedure


  Procedure.i KeyPressed(VirtualKey)    ; returns #False or #True -- #VK_SHIFT, #VK_CONTROL, etc. 
    If GetAsyncKeyState_(VirtualKey) & $8000  
      ProcedureReturn #True 
    EndIf 
    ProcedureReturn #False 
  EndProcedure ;() 


  ; --- procedures 

  Procedure Output(Message.s) 
    AddGadgetItem(#GADGET_edtOutput, -1, Message.s) 
  EndProcedure 

  Procedure OnEvent_SizeWindow() 
    Protected wndw, wndh 

    wndw = WindowWidth(#WINDOW_Main) : wndh = WindowHeight(#WINDOW_Main) 
    ResizeGadget(#GADGET_edtOutput, #PB_Ignore, #PB_Ignore, wndw - 8, wndh - 36) 
  EndProcedure ;() 

  Procedure MainWindow_CallbackProc(hWnd, uMsg, wParam, lParam) 
    ; the PB way of doing callbacks 
    Select uMsg 
      Case #WM_HOTKEY 
        Output("callback: My Hotkey ") 
    
      Case #WM_KEYDOWN  ;:Debug "callback: KEYDOWN" 
        Output("callback: Key is down key = " + wParam + ", Name = " + GetKeyNameText(lParam)) 

    EndSelect 
    ProcedureReturn #PB_ProcessPureBasicEvents 
  EndProcedure 


  Procedure MainWindow_SubclassProc(hWnd, uMsg, wParam, lParam)  ; standard windows interface for message events  
    Static s_hPrevWndProc = 0
    Protected hPrevWndProc, state 

    hPrevWndProc = s_hPrevWndProc 

    Select uMsg ; 
      Case -1                                                          :Debug "subclass:  INTERNAL: init " 
        If wParam = ('I' << 24) | ('N' << 16) | ('I' << 8) | 'T' 
          hPrevWndProc = GetWindowLongPtr_(hWnd, #GWLP_WNDPROC)               ; keep the window procedure address 
          SetWindowLongPtr_(hWnd, #GWLP_WNDPROC, @MainWindow_SubclassProc())  ; set window procedure to my callback procedure 

          s_hPrevWndProc = hPrevWndProc 
          ;s_<Something to keep> = lParam  ;' init by lParam 
          ProcedureReturn 0  ; system can give up on this message 
        EndIf 

      Case #WM_HOTKEY 
        Output("subclass: My Hotkey ") 

      Case #WM_KEYDOWN  ;:Debug "subclass: KEYDOWN" 
        Output("subclass: Key is down key = " + wParam + ", Name = " + GetKeyNameText(lParam)) 

      Case #WM_NCDESTROY                                               :Debug "subclass: WM_NCDESTROY " 
        SetWindowLongPtr_(hWnd, #GWLP_WNDPROC, hPrevWndProc)  ; necessary ? 
        s_hPrevWndProc = 0 

    EndSelect ; uMsg 
    ProcedureReturn CallWindowProc_(hPrevWndProc, hWnd, uMsg, wParam, lParam)  ; use stored window procedure address 
  EndProcedure  

  ; --- main window and loop --- 

  Procedure CreateMainWindow(WndW = 440, WndH = 400)  
    If OpenWindow(#WINDOW_Main, 0, 0, WndW, WndH, "__Caption__", #PB_Window_MainFlags) 
      StickyWindow(#WINDOW_Main, 1) 
      ButtonGadget(#GADGET_btnClick, 4, 4, 76, 20, "__Click_me__") 
      EditorGadget(#GADGET_edtOutput, 4, 32, WndW - 8, WndH - 36) 

      BindEvent(#PB_Event_SizeWindow, @OnEvent_SizeWindow(), #WINDOW_Main) 

      SetWindowCallback(@MainWindow_CallbackProc(), #WINDOW_Main) 

      MainWindow_SubclassProc(WindowID(#WINDOW_Main), -1, ('I' << 24) | ('N' << 16) | ('I' << 8) | 'T', 0)  ; wParam = 'INIT' 

      ProcedureReturn 1 
    EndIf 
    ProcedureReturn 0  
  EndProcedure 

  Procedure main() 
    Protected state, key  

    If CreateMainWindow() 
    
      AddHotKey(#WINDOW_Main, #Hotkey, #MOD_ALT | #MOD_NOREPEAT, #VK_X) 

      Output("Press any Key on your keyboard. ") 
      Repeat  ; main loop 
        Select WaitWindowEvent(250)  
          Case #WM_HOTKEY 
            Output("mainloop: My Hotkey ") 

          Case #WM_KEYDOWN  
            key = EventwParam() ; virtual-key codes ! 
            Output("mainloop: Key is down key = " + key + ", Name = " + GetKeyNameText(EventlParam())) 

          Case #PB_Event_None 
            If KeyPressed(#VK_SHIFT) Or KeyPressed(#VK_CONTROL) 
              Output("mainloop: Don't hold the SHIFT or CNTRL Keys down")  ; <-- this message depends on Timeout in waitwindowevent() !!! 
            EndIf 
          Case #PB_Event_CloseWindow 
            If EventWindow() = #WINDOW_Main : Break : EndIf  ; close button on main window --> close application 
          Case #PB_Event_SizeWindow 
            Output("mainloop: Size Window New W = " + WindowWidth(#WINDOW_Main) + ", H = " + WindowHeight(#WINDOW_Main)) 
          Case #PB_Event_MinimizeWindow, #PB_Event_MaximizeWindow 
              Output("mainloop: Minimize or Maximize Window") 
          Case #PB_Event_Gadget 
            Select EventGadget()
              Case #GADGET_btnClick  
              Output("mainloop: Click on Button") 
            EndSelect 
        EndSelect
      ForEver ; main loop 
      RemoveHotKey(#WINDOW_Main, #Hotkey) 
    EndIf ; OpenWindow 
  EndProcedure 

  End main() 
CompilerEndIf ; #PB_Compiler_IsMainFile ;\--- End of Template for Testing 

Re: Problem GetAsyncKeystate

Verfasst: 29.07.2022 20:50
von Franky_FR
uff, ich arbeite das mal durch. Fragen kommen bestimmt noch :wink: