Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Shift + NumPadX erkennen (https://www.delphipraxis.net/197339-shift-numpadx-erkennen.html)

Amateurprofi 31. Jul 2018 17:07

Shift + NumPadX erkennen
 
Ich möchte (in FormShortcut) auf alle Tasten, die irgendein Zeichen repräsentieren, reagieren und irgendwelche Aktionen auslösen.
Ich möchte auch unterscheiden können, ob gleichzeitig die Shift-Taste gedrückt ist, oder nicht.

Bei den Tasten des Ziffernblocks macht das Probleme weil zum Beispiel bei Shift+NumPad1 nicht etwa NumPad1 als gedrückt gemeldet wird, sondern VK_End.

Mein Ausweg für Helden ist, mit GetKeyboardState den Status aller Tasten zu holen und auszuwerten.

Zu meiner Überraschung liefert GetKeyboardState teils Informationen die (meine Meinung) nicht viel mit der Realität (oder mit dem, was ich für Realität halte) zu tun hat.

Um herauszufinden, was GetKeyboardState liefert habe ich TKeyBoardState in Form einer Matrix ausgegeben, zunächst wenn Shift+NumPad1 gedrückt ist und dann, wenn End gedrückt ist und fand für folgende VK_XX die folgenden Werte.

Die Ergebnisse:
In beiden Fällen ist TKeyBoardState[VK_End] = $81, als gedrückt.
Unterschiedlich waren:
VK_LButton ( 1 bei Shift+1, 0 bei End)
VK_RButton ( 0 bei Shift+1, 1 bei End)
VK_Menu ( 1 bei Shift+1, 0 bei End)
VK_RMENU ( 0 bei Shift+1, 1 bei End)

Meine Lösung (für Shift+NumPad1) ist, dann wenn VK_End gedrückt ist, ist in TKeyBoardState zu prüfen ob bei VK_LBUTTON eine 1 steht oder nicht.
Ist da eine 1 dann interpretiere ich das so, dass Shift+NumPad1 gedrückt sind.
Analog mache ich das für NumPad2 bis 6 (andere Numpad-Tasten brauche ich nicht).
Das funktioniert, aber ich weiß nicht warum und ich weiß auch nicht, ob das nur bei mir so ist.

Nach langer Darstellung was ich mache die Frage:

Weiß jemand eine elegantere Lösung?

Code:
             Shift-1  End
01   1  VK_LBUTTON   1      0
02   2  VK_RBUTTON   0      1
08   8  VK_BACK      1      1
09   9  VK_TAB       1      1
0D 13  VK_RETURN    1      1
10  16  VK_SHIFT     1      1
12  18  VK_MENU      1      0
23  35  VK_END      81     81
24  36  VK_HOME      1      1
5B 91  VK_LWIN      1      1
5C 92  VK_RWIN      1      1
90 144  VK_NUMLOCK   1      1
A0 160  VK_LSHIFT    1      1
A2 162  VK_LCONTROL  1      1
A3 163  VK_RCONTROL  1      1
A4 164  VK_LMENU     1      1
A5 165  VK_RMENU     0      1
F0 240                1      1
F3 243                1      1
F6 246                1      1
FB 251  VK_ZOOM      1      1
TKeyBoardState, wenn Shift + Numpad1 gedrückt sind.

Code:
    0  1  2  3  4  5  6  7  8  9  A B C D E F
    -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
00  00 01 00 00 00 00 00 00 01 01 00 00 00 01 00 00
10  01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
20  00 00 00 81 01 00 00 00 00 00 00 00 00 00 00 00
30  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
40  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50  00 00 00 00 00 00 00 00 00 00 00 01 01 00 00 00
60  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
80  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
A0  01 00 01 01 01 00 00 00 00 00 00 00 00 00 00 00
B0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
C0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
D0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
E0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
F0  01 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00
Delphi-Quellcode:
procedure TMain.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
var Key:Word; Shift:TShiftState;
//------------------------------------------------------------------------------
FUNCTION GetKeyCode:Boolean;
begin
   Key:=Msg.CharCode;
   if Key in [VK_Shift,VK_Control,VK_Menu] then Exit(False); // Nur Shift, Ctrl, Alt
   Shift:=[ssShift,ssCtrl,ssAlt]*KeyDataToShiftState(Msg.KeyData);
   Result:=True;
end;
//------------------------------------------------------------------------------
FUNCTION HandlePianoKey:Boolean;
var Index:Integer; Tone:Byte; KeyState:TKeyBoardState;
begin
   Result:=(ActiveControl<>reEditor) and (Shift*[ssCtrl,ssAlt]=[]) and (Key<=$FF);
   if Result then begin
      if Key in [VK_End,VK_Down,VK_Next,VK_Left,VK_Clear,VK_Right] then begin
         GetKeyboardState(KeyState);
         if KeyState[VK_LButton]=1 then begin
            case Key of
               VK_End  : Key:=VK_NumPad1;
               VK_Down : Key:=VK_NumPad2;
               VK_Next : Key:=VK_NumPad3;
               VK_Left : Key:=VK_NumPad4;
               VK_Clear : Key:=VK_NumPad5;
               VK_Right : Key:=VK_NumPad6;
               else       Exit(False);
            end;
            Shift:=[ssShift];
         end;
      end;
      Index:=KeyToToneIndex[Key];
      if Index<Length(KeyToTone) then
         with KeyToTone[Index] do begin
            if Shift=[] then Tone:=Tone1 else Tone:=Tone2;
            PianoPlayTone(Tone);
            Exit;
         end;
   end;
   Result:=False;
end;
//------------------------------------------------------------------------------
//PROCEDURE StoreKeyStates;
//var I:Integer; KeyState:TKeyBoardState; S:String;
//begin
//   GetKeyboardState(KeyState);
//   S:='   0  1  2  3  4  5  6  7  8  9  A B C D E F'#13#10+
//      '   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --'#13#10;
//   for I:=0 to High(KeyState) do begin
//      if I and 15=0 then S:=S+IntToHex(I and $F0,2)+' ';
//      S:=S+IntToHex(KeyState[I],2)+' ';
//      if I and 15=15 then S:=S+#13#10;
//   end;
//   ClipBoard.AsText:=S;
//end;
//------------------------------------------------------------------------------
begin {FormShortCut}
   Handled:=GetKeyCode;
   if not Handled then Exit; // war nur Shift, Ctrl, Alt
//   StoreKeyStates;
   ...
   ...
   if HandlePianoKey then Exit;
   Handled:=False;
end; {FormShortCut}

Delphi.Narium 31. Jul 2018 17:39

AW: Shift + NumPadX erkennen
 
Frage, was hast Du vor?

Um auf Tastendrücke zu reagieren setze ich KeyPreview des Forms auf True und fülle OnKeyUp mit Leben.

Da kann man Key (Word) (also z. B. die $81) und Shift (TShiftState) abfragen. Man bekommt beides als Parameter in die Ereignisroutine geliefert.
Delphi-Quellcode:
procedure TForm.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
Man kann dann in Shift abfragen, ob Strg, Alt oder Shift oder auch 'ne beliebige Kombination daraus betätigt wurde, in Key steht der nummerische Wert der Taste. Kann man dann mit VK_wieauchimmer vergleichen ...

Wäre das 'ne Alternative oder hast Du weiterreichende Anforderungen, die in dem Ereignis nicht umzusetzen sind?

hoika 31. Jul 2018 18:23

AW: Shift + NumPadX erkennen
 
Hallo,
kennt Du das hier schon?
Das geht doch in Deine Richtung.

https://social.msdn.microsoft.com/Fo...rum=vblanguage

Amateurprofi 31. Jul 2018 18:42

AW: Shift + NumPadX erkennen
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1409245)
Frage, was hast Du vor?

Um auf Tastendrücke zu reagieren setze ich KeyPreview des Forms auf True und fülle OnKeyUp mit Leben.

Da kann man Key (Word) (also z. B. die $81) und Shift (TShiftState) abfragen. Man bekommt beides als Parameter in die Ereignisroutine geliefert.
Delphi-Quellcode:
procedure TForm.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
Man kann dann in Shift abfragen, ob Strg, Alt oder Shift oder auch 'ne beliebige Kombination daraus betätigt wurde, in Key steht der nummerische Wert der Taste. Kann man dann mit VK_wieauchimmer vergleichen ...

Wäre das 'ne Alternative oder hast Du weiterreichende Anforderungen, die in dem Ereignis nicht umzusetzen sind?

Was ich wollte?:
Ich schriebs explizit: Auf z.B. NumPad1 reagieren und unterscheiden können, ob die Shift-Taste gleichzeitig gedrückt ist.


Und genau das funktioniert nicht mit FormKeyUp.
Wenn du NumPad1 drückst, wird im FormKeyUp korrekt als Key $61 geliefert und not (ssShift in Shift).
Aber wenn du Shift+NumPad1 drückst wird im FormKeyUp als Key $23 = 35 = VK_End und ebenfalls not (ssShift in Shift) geliefert.

Amateurprofi 31. Jul 2018 18:50

AW: Shift + NumPadX erkennen
 
Zitat:

Zitat von hoika (Beitrag 1409250)
Hallo,
kennt Du das hier schon?
Das geht doch in Deine Richtung.

https://social.msdn.microsoft.com/Fo...rum=vblanguage

Auch das funktioniert nicht.
Drücke ich NUR NumPad1 funktioniert das; klar.
Aber drücke ich Shift + Numpad1 wird als Key VK_End geliefert UND Shift NICHT gedrückt.

KodeZwerg 31. Jul 2018 19:16

AW: Shift + NumPadX erkennen
 
Wie sah Dein Code mit
Delphi-Quellcode:
procedure TForm.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
aus?

Ps: Kann es sein das Du das eventuell mit Num-Lock Abfrage realisieren musst?

Delphi.Narium 31. Jul 2018 19:17

AW: Shift + NumPadX erkennen
 
Meine Frage "Frage, was hast Du vor?" zielte daraufhin, welche Aufgabe mit dem Erkennen von den Tastaturdruckkombinationen erreicht werden soll. Das beim Druck von Shift+NumPad1 eben genau diese Kombination festgestellt werden soll, ist schon klar.

Habe mal ein bisserl rumprobiert:

Beim Drücken von Strg und/oder Alt plus einer NumPad-Taste bekommt man die entsprechende Info. Ob man dabei Shift betätigt oder nicht, ändert nichts am Ergebnis. Shift ist nie dabei.

Wenn man nun aber Numlock ausschaltet, dann erfährt man auch, ob Shift in der Tastenkombination plus einer NumPad-Taste dabei ist.

Meine Googlelitis brachte auch nix zum Vorschein, außer: Du bist nicht alleine mit diesem Problem.

Redeemer 31. Jul 2018 19:55

AW: Shift + NumPadX erkennen
 
Ich weiß ja nicht, was du machst, aber das hier funktioniert problemlos bei mir und das ist auch, wie man TShortcutEvent verwendet:
Delphi-Quellcode:
procedure TollesEvent(var Msg: TWMKey; var Handled: Boolean);
var
  ss: TShiftState;
begin
  ss := KeyDataToShiftState(Msg.KeyData);
  if ss = [ssShift] then
  if Msg.Charcode = VK_NUMPAD0 then // =96
  TueTolleSachen();
end;
Wenn man nicht weiß, was eigentlich los ist:
Delphi-Quellcode:
uses Menus;

procedure TollesEvent(var Msg: TWMKey; var Handled: Boolean);
var
  ss: TShiftState;
begin
  ss := KeyDataToShiftState(Msg.KeyData);
  Caption := IfThen(ssCtrl in ss, 'Strg+')
           + IfThen(ssShift in ss, 'Umsch+')
           + IfThen(ssAlt in ss, 'Alt+')
           + ShortCutToText(Msg.CharCode) + '/'
           + IntToStr(Msg.CharCode);
end;

Amateurprofi 31. Jul 2018 20:02

AW: Shift + NumPadX erkennen
 
Zitat:

Zitat von KodeZwerg (Beitrag 1409253)
Wie sah Dein Code mit
Delphi-Quellcode:
procedure TForm.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
aus?

Ps: Kann es sein das Du das eventuell mit Num-Lock Abfrage realisieren musst?

Delphi-Quellcode:
procedure TMain.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
   Info(piInfo,IntToHex(Key,2)+' '+IntToStr(Ord(ssShift in Shift)));
end;
"Info" ist eine meiner Standard-Prozeduren, die einen Text in dem durch den ersten Parameter definierten Panel der Statusbar ausgibt.

NumLock ist na klar "down".

Amateurprofi 31. Jul 2018 20:16

AW: Shift + NumPadX erkennen
 
Zitat:

Zitat von Redeemer (Beitrag 1409259)
Ich weiß ja nicht, was du machst, aber das hier funktioniert problemlos bei mir und das ist auch, wie man TShortcutEvent verwendet:
Delphi-Quellcode:
procedure TollesEvent(var Msg: TWMKey; var Handled: Boolean);
var
  ss: TShiftState;
begin
  ss := KeyDataToShiftState(Msg.KeyData);
  if ss = [ssShift] then
  if Msg.Charcode = VK_NUMPAD0 then // =96
  TueTolleSachen();
end;
Wenn man nicht weiß, was eigentlich los ist:
Delphi-Quellcode:
uses Menus;

procedure TollesEvent(var Msg: TWMKey; var Handled: Boolean);
var
  ss: TShiftState;
begin
  ss := KeyDataToShiftState(Msg.KeyData);
  Caption := IfThen(ssCtrl in ss, 'Strg+')
           + IfThen(ssShift in ss, 'Umsch+')
           + IfThen(ssAlt in ss, 'Alt+')
           + ShortCutToText(Msg.CharCode) + '/'
           + IntToStr(Msg.CharCode);
end;

Ich vermute "TollesEvent" ist "FormShortCut"
Hab deinen Code im FormShortCut unverändert eingefügt - und funktioniert nicht (bei Shift + NumPadX)
Unter "funktioniert" verstehe ich, um bei deinem erstgenannten Code zu bleiben, dass die Prozedur TueTolleSachen() ausgeführt wird, wenn ich Shift + Numpad1 (bei deinem Beispiel NumPad0) drücke.

Falls es dir entgangen ist:
So ziemlich genau das, was du vorschlägst mach ich in dem in #1 gezeigten FormShortcut.

KodeZwerg 31. Jul 2018 21:14

AW: Shift + NumPadX erkennen
 
Ich habe das selbe Problem mit Redeemers Vorschlag, weder per TApplicationEvents noch per TApplication, jeweils das TShortcutEvent Event, kommt dabei nur etwas positives heraus wenn numlock ausgeschaltet ist.
Ich hatte gehofft auf diese Weise beides abfangen zu können
Delphi-Quellcode:
procedure TForm1.ApplicationEvents1ShortCut(var Msg: TWMKey;
var Handled: Boolean);
var
  ss: TShiftState;
begin
  ss := KeyDataToShiftState(Msg.KeyData);
  if ss = [ssShift] then
  begin
   if ((Msg.Charcode = VK_NUMPAD0) or (Msg.Charcode = VK_INSERT)) then // theoretisch sollte das ohne/mit numlock codes abdecken
   begin
    ShowMessage(IntToStr(Msg.CharCode));
    Handled := True;
   end;
  end;
end;
Pustekuchen.

KodeZwerg 31. Jul 2018 22:10

AW: Shift + NumPadX erkennen
 
Hier ein work-around, aber happert noch hier und da, aber um Dir meinen Grundgedanken zu verdeutlichen:
Delphi-Quellcode:
procedure TForm1.ApplicationEvents1ShortCut(var Msg: TWMKey;
var Handled: Boolean);
  procedure SetNumLock(Active: Boolean);
  var
    State: SHORT;
    Scan: UINT;
  begin
    Scan := MapVirtualKey(VK_NUMLOCK, 0);
    State := GetKeyState(VK_NUMLOCK);
    // Prüfen ob Status nicht schon korrekt ist
    if Active xor (State and $0001 = $0001) then
     begin
       // User hat den Finger drauf :o) ( also erstmal wieder loslassen )
       if State < 0 then
        keybd_event(VK_NUMLOCK, Scan, KEYEVENTF_KEYUP, 0);
       // Taste drücken
       keybd_event(VK_NUMLOCK, Scan, 0, 0);
       // User hat nicht den Finger drauf :o) ( also loslassen )
       if State >= 0 then
        keybd_event(VK_NUMLOCK, Scan, KEYEVENTF_KEYUP, 0);
     end;
  end;
var
  ss: TShiftState;
  OrgState, KBstate: TKeyboardState;
begin
  ss := KeyDataToShiftState(Msg.KeyData);
  GetKeyboardState(KBstate);
  OrgState := KBstate;
  if ss = [ssShift] then
  begin
   if KBstate[VK_NUMLOCK] <> 0 then
    begin
      KBstate[VK_NUMLOCK] := 0;
      SetNumLock(False);
      SetKeyboardState(KBstate);
      Msg.CharCode := $0;
      Handled := True;
    end;
   if ((Msg.Charcode = VK_NUMPAD0) or (Msg.Charcode = VK_INSERT)) then
   begin
    ShowMessage('Numpad 0 + Shift: '+IntToStr(Msg.CharCode));
    Handled := True;
   end;
{   if OrgState[VK_NUMLOCK] <> 0 then
    begin
      SetKeyboardState(OrgState);
      SetNumLock(True);
      Msg.CharCode := $0;
    end;}
   if not Handled = True then if (Msg.Charcode <> VK_SHIFT) then ShowMessage(IntToStr(Msg.CharCode));
  end;
end;
Das Problem: sobald man Shift drückt wechselt NumLock An/Aus/An/Aus usw usf, also da muss noch dolle was gemacht werden, ansonsten klappt es damit ganz gut.

Amateurprofi 1. Aug 2018 11:23

AW: Shift + NumPadX erkennen
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1409254)
Meine Frage "Frage, was hast Du vor?" zielte daraufhin, welche Aufgabe mit dem Erkennen von den Tastaturdruckkombinationen erreicht werden soll. Das beim Druck von Shift+NumPad1 eben genau diese Kombination festgestellt werden soll, ist schon klar.

Habe mal ein bisserl rumprobiert:

Beim Drücken von Strg und/oder Alt plus einer NumPad-Taste bekommt man die entsprechende Info. Ob man dabei Shift betätigt oder nicht, ändert nichts am Ergebnis. Shift ist nie dabei.

Wenn man nun aber Numlock ausschaltet, dann erfährt man auch, ob Shift in der Tastenkombination plus einer NumPad-Taste dabei ist.

Meine Googlelitis brachte auch nix zum Vorschein, außer: Du bist nicht alleine mit diesem Problem.

Naja, "nicht alleine mit dem Problem".
eigentlich habe ich nicht wirklich ein Problem, denn ich habe ja eine funktionierende Lösung, die ich in #1 gezeigt habe.
Mein Ansinnen war, eine elegantere Methode aufgezeigt zu bekommen.

KodeZwerg 22. Aug 2018 21:36

AW: Shift + NumPadX erkennen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Schau mal bitte in das Projekt rein, ich habe total normale Delphi Methoden veranschaulicht und auch ein SHIFT+NumPadX lässt sich damit auslesen, egal ob NumLock on/off.

Amateurprofi 22. Aug 2018 23:50

AW: Shift + NumPadX erkennen
 
Zitat:

Zitat von KodeZwerg (Beitrag 1411357)
Schau mal bitte in das Projekt rein, ich habe total normale Delphi Methoden veranschaulicht und auch ein SHIFT+NumPadX lässt sich damit auslesen, egal ob NumLock on/off.

Ich weiß ja nun nicht was dir angezeigt wird.
Das folgende wird mir angezeigt:
Angegeben habe ich jeweils in der ersten Zeile, die Taste die ich drücke (oder loslasse) und in der zweiten Zeile die 4 Werte die angezeigt werden.
NumPad2 Down
2 98 Leer 50
NumPad2 Up
2 98 98 50

Shift Down
2 16 98 50
NumPad1 Down
2 35 16 50
NumPad1 Up
2 16 35 50
Shift Up
2 16 16 50

Bei NumPad1 Down kommt im FormKeyDown genau das, was Probleme macht, nämlich die Information Key=35 und Shift-Taste gedrückt. Also Shift + VK_End,
Tatsächlich gedrückt war aber Shift + Numpad1.
Sehr schön ist auch zu sehen, das Shift + Numpad1 kein FormKeyPress auslöst.
Um auf die Tasten bzw. Tastenkombinationen zu reagieren bleibt also nur FormKeyDown (oder FormKeyUp) - ich bevorzuge FormShortcut.
Und da kommt bei Shift + NumpadX etwas anderes als tatsächlich gedrückt wurde.

Was ich jetzt nicht so richtig verstehe ist Dein Kommentar "und auch ein SHIFT+NumPadX lässt sich damit auslesen", denn genau das ist nicht der Fall - jedenfalls nicht bei mir.

KodeZwerg 23. Aug 2018 00:15

AW: Shift + NumPadX erkennen
 
Welch eine Schande, ich dachte echt das ich per KeyUp und KeyDown schon ganz gut liege.
Ich habe es nicht tief genug mit anderen Tasten getestet bzw total außer Acht gelassen.

Tut mir leid für Störung.

Ps:
Da stehen oftmals noch alte Werte in den Feldern, das war halt ein Schuss in den Ofen auch wenn ich das noch ausbügel mit den Feldern bleibt es falsch.


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:23 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz