Wie kann ich einen VK_Control key up event sauber erkennen ? [gelöst]

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Wie kann ich einen VK_Control key up event sauber erkennen ? [gelöst]

Beitrag von corpsman »

Servus zusammen,
für meinen FPC_DOOM port benötige ich natürlich auch eine Taste zum "schießen". Hierfür ist die Rechte CTRL Taste vorgesehen und schon geht das drama los.

Im OnKeyDown Event bekommt man immer nur VK_Control egal welche der beiden Tasten man drückt.
Dafür habe ich dann folgenden Workaround gebastelt:

Code: Alles auswählen


Procedure TForm1.OpenGLControl1KeyDown(Sender: TObject; Var Key: Word;
  Shift: TShiftState);
Var
  ev: event_t;
Begin
  // See d_event.pas for descriptions
  ev := GetTypedEmptyEvent(ev_keydown);
 If key = VK_CONTROL Then Begin
    If GetKeyState(VK_RCONTROL) <> 0 Then Begin
      key := VK_RCONTROL;
    End
    Else Begin
      key := VK_LCONTROL;
    End;
  End;  
  // Siehe i_input.c I_HandleKeyboardEvent
  ev.data1 := Key; // doomkeys.h is made to be equal to lcl
  ev.data2 := Key; // TODO: muss noch richtig gemacht werden ?
  ev.data3 := Key; // TODO: muss noch richtig gemacht werden ?
  D_PostEvent(ev);
End; 

Das Funktioniert auch ganz gut. Das Problem ist nun der KeyUp Event, denn dort ist ja
GetKeyState(VK_RCONTROL)
auf jeden Fall immer 0 -> damit kann ich im OnKeyUp nicht mehr herausfinden welche CTRL Taste nun gedrückt wurde. Habt ihr da ne Idee ? das ganze muss unter Windows und Linux auf jeden Fall funktionieren ..


Laut LCLintf.pas

Code: Alles auswählen

  // VK_L & VK_R - left and right Alt, Ctrl and Shift virtual keys.
  // When Application.ExtendedKeysSupport is false, these keys are
  // used only as parameters to GetAsyncKeyState() and GetKeyState().
  // No other API or message will distinguish left and right keys in this way
  //
  // When Application.ExtendedKeysSupport is true, these keys will be sent
  // on KeyDown / KeyUp instead of the generic VK_SHIFT, VK_CONTROL, etc.
  VK_LSHIFT     = $A0;
  VK_RSHIFT     = $A1;
  VK_LCONTROL   = $A2;
  VK_RCONTROL   = $A3;
soll Application.ExtendedKeysSupport := true was bringen, hab bei mir aber leider nichts gebracht :(
Zuletzt geändert von corpsman am So 2. Feb 2025, 09:54, insgesamt 1-mal geändert.
--
Just try it

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 385
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: Wie kann ich einen VK_Control key up event sauber erkennen ?

Beitrag von Jorg3000 »

Tach!
Man könnte bei OnKeyDown in einer globalen Variable speichern, ob Rechts oder Links gedrückt wird, dann weißt du bei OnKeyUp Bescheid.

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Wie kann ich einen VK_Control key up event sauber erkennen ?

Beitrag von corpsman »

*g* das geht nur, wenn der User nicht beide tasten drückt, denn dann hast du beim KeyUp wieder das Problem, dass du nicht weist welche der beiden nun losgelassen wurde :/
--
Just try it

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 385
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: Wie kann ich einen VK_Control key up event sauber erkennen ?

Beitrag von Jorg3000 »

Dann vielleicht mit zwei Variablen ... ?! (nicht getestet)

Code: Alles auswählen

var PressingCtrl: Array[0..1] of Boolean = (false,false);  // Index 0=links, 1=rechts

Procedure TForm1.OpenGLControl1KeyDown(Sender: TObject; Var Key: Word; Shift: TShiftState);
Begin
  If key = VK_CONTROL Then Begin
    If GetKeyState(VK_RCONTROL) <> 0 Then
      PressingCtrl[1]:=true
    Else
      PressingCtrl[0]:=true;
  End;
End;

Procedure TForm1.OpenGLControl1KeyUp(Sender: TObject; Var Key: Word; Shift: TShiftState);
Begin
  If key = VK_CONTROL Then
    begin
       if not PressingCtrl[1] then begin PressingCtrl[0]:=false; *** links losgelassen *** Exit; end;
       if not PressingCtrl[0] then begin PressingCtrl[1]:=false;  *** rechts losgelassen *** Exit; end;
       If GetKeyState(VK_RCONTROL) <> 0 
        then begin PressingCtrl[0]:=false; *** links losgelassen *** Exit; end
        else begin PressingCtrl[1]:=false;  *** rechts losgelassen *** Exit; end;
    end;
End;

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Wie kann ich einen VK_Control key up event sauber erkennen ?

Beitrag von corpsman »

hmm, das könnte funktionieren ...
Ich frage mich ja schon irgendwie warum die LCL das nicht kann ...
--
Just try it

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6848
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Wie kann ich einen VK_Control key up event sauber erkennen ?

Beitrag von af0815 »

..... weils wahrscheinlich nicht Delphikompatibel ist. SCNR.

Ohne Spass, wenn es Delphi kann, so ist es ein Bug, ansonsten ein "won't fix" weil es eben kompatibel ist. Ansonsten ist dort halt nicht der absolute Focus drauf, weil man sowas eher für Spiele braucht.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Wie kann ich einen VK_Control key up event sauber erkennen ?

Beitrag von corpsman »

So ich habe den Vorschlag von Jorg3000 nu mal ein klein wenig verallgemeinert und so kommt er dann auch in meine Anwendung ;)

Danke

Code: Alles auswählen

Type
  TKeyBuffer = Array[0..1] Of Boolean;   

  TForm1 = Class(TForm)
  private
    fCTRLBuffer: TKeyBuffer;
    fShiftBuffer: TKeyBuffer;
    fALTBuffer: TKeyBuffer;
    Procedure ClearKeyBuffer(Var Buf: TKeyBuffer);
    Procedure CheckKeyDown(Var Key: Word; Var buf: TKeyBuffer; BothKey, Index0Key, Index1Key: Word);
    Procedure CheckKeyUp(Var Key: Word; Var buf: TKeyBuffer; BothKey, Index0Key, Index1Key: Word);
  end;

Procedure TForm1.ClearKeyBuffer(Var Buf: TKeyBuffer);
Var
  i: Integer;
Begin
  For i := low(buf) To high(buf) Do Begin
    buf[i] := false;
  End;
End;

Procedure TForm1.CheckKeyDown(Var Key: Word; Var buf: TKeyBuffer; BothKey,
  Index0Key, Index1Key: Word);
Begin
  If key = BothKey Then Begin
    If GetKeyState(Index1Key) <> 0 Then Begin
      buf[1] := true;
      key := Index1Key;
    End
    Else Begin
      buf[0] := true;
      key := Index0Key;
    End;
  End;
End;

Procedure TForm1.CheckKeyUp(Var Key: Word; Var buf: TKeyBuffer; BothKey,
  Index0Key, Index1Key: Word);
Begin
  If key = BothKey Then Begin
    // Nur eine Taste ist gedrückt, dann muss es die jeweils andere sein !
    If Not buf[1] Then Begin
      buf[0] := false;
      key := Index0Key;
      exit;
    End;
    If Not buf[0] Then Begin
      buf[1] := false;
      key := Index1Key;
      exit;
    End;
    // Beide Tasten waren gedrückt, welche ist nun Los gelassen worden ?
    If GetKeyState(Index1Key) <> 0 Then Begin
      buf[0] := false;
      key := Index0Key;
    End
    Else Begin
      buf[1] := false;
      key := Index1Key;
    End;
  End;
End;  

Procedure TForm1.FormCreate(Sender: TObject);
Begin
  ClearKeyBuffer(fCTRLBuffer);
  ClearKeyBuffer(fShiftBuffer);
  ClearKeyBuffer(fALTBuffer); 
end;

Procedure TForm1.OpenGLControl1KeyDown(Sender: TObject; Var Key: Word;
  Shift: TShiftState);
Begin
  CheckKeyDown(key, fCTRLBuffer, vk_Control, VK_LCONTROL, VK_RCONTROL);
  CheckKeyDown(key, fShiftBuffer, VK_SHIFT, VK_LSHIFT, VK_RSHIFT);
  CheckKeyDown(key, fALTBuffer, VK_MENU, VK_LMENU, VK_RMENU);
  // Key hat nun die Richtigen VK-Codes 
End;

Procedure TForm1.OpenGLControl1KeyUp(Sender: TObject; Var Key: Word;
  Shift: TShiftState);
Begin
  CheckKeyUp(key, fCTRLBuffer, vk_Control, VK_LCONTROL, VK_RCONTROL);
  CheckKeyUp(key, fShiftBuffer, VK_SHIFT, VK_LSHIFT, VK_RSHIFT);
  CheckKeyUp(key, fALTBuffer, VK_MENU, VK_LMENU, VK_RMENU);
  // Key hat nun die Richtigen VK-Codes 
End;

--
Just try it

Antworten