Entwickler-Ecke

Windows API - Tastenkombination ohne Buchstaben mit RegisterHotKey?


MasterrudE - Di 10.08.10 22:33
Titel: Tastenkombination ohne Buchstaben mit RegisterHotKey?
Hallo zusammen,

ich versuche gerade, ein Beispiel aus dem "Delphi 7 Kochbuch" umzuändern, um eine Tastenkombination abzufangen, das Programm lässt sich auch problemlos kompilieren und wird im Taskamanger aufgeführt, allerdings mag es nicht auf meine Tastenkombination reagieren...
Hier ist mal der Code, ich versuche, die Tastenkombination Strg + Shift abzufangen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  protected
    procedure HotKey(var msg: TMessage); message WM_HOTKEY;
  private
    { Private declarations }
    id: Integer;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.hotkey(var msg: TMessage);
begin
  //Das Folgende wurde im Original-Beispiel mit msg.LParamLo und msg.LParamHi gemacht, 
  //die Tastencodes waren MOD_CONTROL + MOD_ALT für LParamLo und 83 für LParamHi. Ich hab auch schon versucht, nur die 83 auf 0 zu ändern, ohne Erfolg
  if (msg.WParam = VK_SHIFT) and (msg.LParam = VK_Control) then 
  begin
    self.Visible := not self.Visible;
    if self.Visible then
      self.WindowState := wsNormal
    else
      self.WindowState := wsMinimized;
  end;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  id := GlobalAddAtom('Hotkey1');
  RegisterHotKey(handle, id, VK_SHIFT, VK_CONTROL); //Hier stand im Original auch MOD_CONTROL + MOD_ALT im 3. Parameter und 83 im vierten Parameter
  //Ich hab auch schon versucht, die Original-Tastenkombis stehen zu lassen und nur anstatt 83 eine 0 zu übergeben, 
  //allerdings hat auch da die Tastenkombination nicht funktioniert
end;

end.


Hat jemand einen Tipp, was ich falsch mache? Leider sind meine Kenntnisse bis jetzt noch ziemlich begrenzt, ich hab erst ein paar Sachen für den Eigenbedarf programmiert.
Herzlichen Dank schonmal im voraus für die Hilfe!

Grüße André


elundril - Di 10.08.10 22:45

Hallo und :welcome: im DF!

Du willst als Hotkey nur Strg + Shift haben? Ob das geht ist fraglich. Aber probier mal statt dem VK_Shift MOD_SHIFT zu schreiben. Und aber dann auch in deiner HotkeyProcedure dann auch wirklich LParamLo und LParamHi zu verwenden.

lg elundril


MasterrudE - Di 10.08.10 23:11

Hallo elundril,

Vielen Dank für die schnelle Antwort!
habe jetzt bei dem oberen Kommentar geschrieben


Delphi-Quelltext
1:
if (msg.LParamHi = MOD_SHIFT) and (msg.LParam = VK_Control) then                    


und bei dem unteren Kommentar:


Delphi-Quelltext
1:
RegisterHotKey(handle, id, MOD_SHIFT, VK_CONTROL);                    


Hattest du das so gemeint? Wenn ja, es funktioniert leider nicht...
Hast Du noch eine andere Idee? Kann ich auch mit GetAsyncKeyState (heißt die function so?) global den Status von Tasten abfragen? Ich bekomme ja dann keine WM_HOTKEY Nachricht.


Grüße
André


elundril - Di 10.08.10 23:26

ne, eigentlich meinte ich sowas:


Delphi-Quelltext
1:
if (msg.LParamLo = MOD_SHIFT) and (msg.LParamHi = VK_Control) then                    


Grund ist der das anscheinend die niederen Bits (LParamLo) die ganzen Zusatztasten wie Shift, Alt und Strg kodieren und die hohen Bits (LParamHi) die eigentliche Taste die gedrückt wurde. (In deinem Beispiel war es die Taste mit dem VK-Code 83, was der Power-Knopf wäre soweit ich das richtig aus der VK-Codes-Tabelle rauslese)

Mit GetAsyncKeyState könnte es funktionieren, das musst du dann aber in ne Schleife, Timer oder sonswas packen um registieren zu können wann die Tastenkombination gedrückt wurde. Außerdem glaub ich nicht das man dann auch nur shift und strg verwenden kann, sondern man auch ne richtige taste braucht.

lg elundril

//Edit: Weiters könntest du auch nachsehen was RegisterHotKey zurück gibt. ;) Sollte nämlich True zurückgeben wenn du alles richtig gemacht hast. ;)


MasterrudE - Di 10.08.10 23:38

Hallo mal wieder... ;-)

Schon wieder Danke für die schnelle Hilfe!
Leider hats auch dieses Mal nicht funktioniert. Ich hab es mehrmals in den folgenden Kombinationen versucht:

-nur die erste Zeile geändert
-beide Zeilen auf MOD_*** geändert
-Die MOD_*** Parameter wieder zusammengeschrieben als "MOD_SHIFT + MOD_CONTROL" im 3. Parameter in der zweiten Zeile
-Sowohl MOD_SHIFT und MOD_CONTROL als auch gleichzeitig VK_CONTROL abgefragt

Das Programm kompiliert in allen Versionen problemlos, allerdings reagiert es nicht auf die Tastenkombination.
Das mit der Ausgabe ist ne gute Idee, werd ich mal probieren.
Die Taste "83" ist das "S", in der Original-Version reagiert das Programm also auf Strg + Shift + S.

Wenn alle diese Funktionen nur auf "echte" Tastenkombinationen ansprechen, wie könnte man dann sowas noch anders realisieren?

Grüße
André


elundril - Di 10.08.10 23:49

Probier mal folgendes:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  protected
    procedure HotKey(var msg: TWMHotKey); message WM_HOTKEY;
  private
    { Private declarations }
    id: Integer;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.hotkey(var msg: TWMHotKey);
begin
  if msg.HotKey = id then //warum denn nicht gleich die eindeutige id nutzen wenn man schon eine hat??
  begin
    self.Visible := not self.Visible;
    if self.Visible then
      self.WindowState := wsNormal
    else
      self.WindowState := wsMinimized;
  end;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  id := GlobalAddAtom('Hotkey1');
  if not RegisterHotKey(handle, id, MOD_SHIFT, VK_CONTROL) then
    Showmessage(SysErrorMessage(GetLastError));
end;

end.


Bin mir aber nicht sicher ob das geht. Kann durchaus sein das man zwingend einen Buchstaben braucht.

Alternative wäre eben ein GetAsyncKeyState oder ein Keyboard-Hook. Oder halt wenn du uns verratest was du vor hast, vielleicht noch was anderes. ;)

lg elundril


MasterrudE - Mi 11.08.10 00:03

So...

Hab jetzt mal ein Memo zum Formular hinzugefügt und verschiedene Kombinationen ausprobiert:

1.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
procedure TForm1.hotkey(var msg: TMessage);
begin
  if (msg.WParam = VK_SHIFT) and (msg.LParam = VK_Control) then
  begin
    self.Visible := not self.Visible;
    if self.Visible then
      self.WindowState := wsNormal
    else
      self.WindowState := wsMinimized;
  end;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  id := GlobalAddAtom('Hotkey1');
  if (RegisterHotKey(handle, id, VK_SHIFT, VK_CONTROL)) then
    Memo1.Lines.Add('RegisterHotKey = TRUE')
  else
    Memo1.Lines.Add('RegisterHotKey = FALSE, Action failed!');
end;


Ergebnis: RegisterHotKey = FALSE

2.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
procedure TForm1.hotkey(var msg: TMessage);
begin
  if (msg.LParamLo = MOD_SHIFT + MOD_CONTROL) then
  begin
    self.Visible := not self.Visible;
    if self.Visible then
      self.WindowState := wsNormal
    else
      self.WindowState := wsMinimized;
  end;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  id := GlobalAddAtom('Hotkey1');
  if (RegisterHotKey(handle, id, MOD_SHIFT + MOD_CONTROL, 0)) then
    Memo1.Lines.Add('RegisterHotKey = TRUE')
  else
    Memo1.Lines.Add('RegisterHotKey = FALSE, Action failed!');
end;


Ergebnis: RegisterHotKey = TRUE

3.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
procedure TForm1.hotkey(var msg: TMessage);
begin
  if (msg.LParamLo = MOD_SHIFT + MOD_CONTROL) and (msg.LParamHi = VK_SHIFT)then
  begin
    self.Visible := not self.Visible;
    if self.Visible then
      self.WindowState := wsNormal
    else
      self.WindowState := wsMinimized;
  end;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  id := GlobalAddAtom('Hotkey1');
  if (RegisterHotKey(handle, id, MOD_SHIFT + MOD_CONTROL, VK_SHIFT)) then
    Memo1.Lines.Add('RegisterHotKey = TRUE')
  else
    Memo1.Lines.Add('RegisterHotKey = FALSE, Action failed!');
end;


Ergebnis: Funktioniert!!!

Allerdings nur, wenn man erst Strg und dann Shift drückt, setzt man VK_CONTROL ein, ist es dementsprechend andersrum. Werd noch ein bißchen dran rumbasteln, damit es in beiden Richtungen funktioniert.
Erstmal herzlichen Dank!


Grüße
André




EDIT: Hab gerade erst Deine letzte Antwort gelesen, weil ich parallel zum posten hier noch mit Delphi gespielt hatte. Wie gesagt, der Großteil des Codes stammte aus dem Kochbuch, über Optimierungen hatte ich noch gar nicht nachgedacht. danke für den Tip!

EDIT2: Ganz vergessen... Was ich vorhabe? Ich versuche mich daran, ein Plugin für VirtuaWin zu schreiben, dass ähnlich wie VWPreview funktionieren soll. Mal sehen, ob es was wird. Ich arbeite jetzt seit ein paar Wochen an verschiedenen Vorübungen und will sie dann hinterher zu einem Plugin zusammenfügen.