77 Stimmen

Delphi: Systemweiter HotKey

Tutorial von Stefan Trost | Letztes Update am 21.06.2021 | Erstellt am 04.11.2013

In diesem Tutorial möchte ich zeigen, wie man für seine Delphi Anwendung einen systemweiten HotKey registrieren kann (für eine Lazarus-Lösung bitte unten in den Kommentar schauen). Das bedeutet, dass das Programm eine Nachricht über das Drücken einer bestimmten Tastenkombination bekommt, selbst wenn das Programm nicht den Fokus hat.

Eine typische Anwendung wäre ein Programm, das lediglich ein Icon im SysTray von Windows hat und das mit einer eindeutigen Tastenkombination (zum Beispiel STRG + ALT + X) hervorgeholt werden kann.

Normalerweise kann nur das Programm einen Tastendruck empfangen, wenn dieses aktuell den Fokus hat. Soll das Programm auch auf Ereignisse reagieren, wenn eigentlich gerade ein anderes Programm bedient wird, brauchen wir daher einen Workaround.

Diese kann zum Beispiel so aussehen, dass wir die Taste oder Tastenkombination als HotKey bei Windows registrieren. Wird diese Kombination dann gedrückt, weiß Windows Bescheid und schickt unserem Programm eine Nachricht darüber, dass die Taste gedrückt wurde.

Wie man sich denken kann erwächst eine Schwierigkeit daraus, dass wir eine eindeutige Tastenkombination benötigen. Versuchen wir eine Tastenkombination zu registrieren, die schon von einem anderen Programm verwendet wird, wird dies nicht funktionieren. Auch sollten wir keine Tasten oder Kombinationen belegen, die man in einem anderen Programm noch benötigt.

Schauen wir uns aber zunächst an, wie wir einen solchen HotKey registrieren können.

ID unseres Hot Keys

Zunächst benötigt jeder unserer HotKeys, die wir registrieren möchte eine eindeutige ID, um diesen auch später wieder zuerkennen. Wir deklarieren dazu eine beliebige Integer-Variable im "private"-Bereich unserer Unit:

private
  { Private declarations }
  HotKeyID: Integer;
  HotKeyIDFunctionA, HotKeyIDFunctionB: Integer;
  HotKeyIDPrintKey: Integer;

Für jeden HotKey, den wir registrieren möchten, brauchen wir eine eigene Variable. Wollen wir nur einen Hot Key anlegen, reicht die Variable "HotKeyID", bei mehreren sollten wir den Namen der Funktionalität oder der gedrückten Taste hinterlegen, damit wir nicht später durcheinander kommen.

Hot Key registrieren

Als nächstes kümmern wir uns darum, dass unsere Hot Keys beim Starten des Programms bei Windows registriert werden. Den Code dazu schreiben wir in das OnCreate unserer Form.

Die Registrierung läuft immer gleich ab. Zunächst lassen wir mit der Funktion GlobalAddAtom von Windows eine eindeutige ID generieren, die wir dann in unserer HotKeyID-Variable speichern (denn die brauchen wir später wieder). Statt die Funktion GlobalAddAtom zu benutzen, könnten wir genauso einen beliebigen Integer-Wert wie "1" oder "2" benutzen. Das sollten wir aber lieber bleiben lassen, da es durchaus sein kann, dass diese Werte schon von anderen Programmen verwendet werden.

Nachdem wir unsere eindeutige ID von Windows bekommen haben, benutzen wir die Funktion RegisterHotKey, um unseren HotKey zu registrieren. Wir übergeben dazu das Handle unseres Programms (damit weiß Windows an wen beim Drücken der Tastenkombination zu senden ist), die ID und anschließend die Tastenkombination, die wir registrieren möchten.

procedure TForm1.FormCreate(Sender: TObject);
const
  VK_A = $41;
begin
  // HotKey STRG + F1
  HotKeyID := GlobalAddAtom('HotKey1');
  RegisterHotKey(Handle, HotKeyID, MOD_CONTROL, VK_F1);

  // HotKey ALT + SHIFT + A
  HotKeyIDFunctionA := GlobalAddAtom('HotKey2');
  RegisterHotKey(Handle, HotKeyIDFunctionA, MOD_ALT + MOD_SHIFT, VK_A);

  // HotKey Windows-Taste + A
  HotKeyIDFunctionB := GlobalAddAtom('HotKey3');
  RegisterHotKey(Handle, HotKeyIDFunctionA, MOD_WIN, VK_A);

  // HotKey Druck Taste
  HotKeyIDPrintKey := GlobalAddAtom('HotKey4');
  RegisterHotKey(Handle, HotKeyIDPrintKey, 0, VK_SNAPSHOT);
end;

Die Tastenkombination wird in 2 Parametern übergeben. Mit dem ersten Parameter lassen sich die Tasten ALT, STRG, SHIFT oder die Windows-Taste registrieren. Diese Tasten können mit den Konstanten MOD_ALT, MOD_CONTROL, MOD_SHIFT und MOD_WIN angegeben werden, die die Werte 1, 2, 4 und 8 haben. Sollen mehrere dieser Tasten gleichzeitig gedrückt werden, addiert man entsprechend die Werte. Also zum Beispiel MOD_ALT + MOD_CONTROL (1+2) für das gleichzeitige Drücken von ALT und STRG (ALT + SHIFT + A im Beispiel). Übergibt man eine 0, zählt nur der zweite Parameter als HotKey (Druck-Taste im Beispiel).

Der zweite Parameter ist der virtuelle Key Code der weiteren Taste. Also zum Beispiel VK_SNAPSHOT für die Druck-Taste, VK_F1 für F1 oder $41 für den Buchstaben A.

Die Funktion RegisterHotKey gibt false zurück, wenn die Registrierung fehlgeschlagen ist. Bei Bedarf kann  man das noch an dieser Stelle abfangen.

Hot Key Registrierung löschen

Wird unser Programm geschlossen, sollten wir dafür sorgen, dass unsere registrierten HotKeys auch wieder aus dem System gelöscht werden.

procedure TForm1.FormDestroy(Sender: TObject);
begin
  UnRegisterHotKey(Handle, HotKeyID);
  GlobalDeleteAtom(HotKeyID);

  UnRegisterHotKey(Handle, HotKeyIDFunctionA);
  GlobalDeleteAtom(HotKeyIDFunctionA);

  UnRegisterHotKey(Handle, HotKeyIDFunctionB);
  GlobalDeleteAtom(HotKeyIDFunctionB);

  UnRegisterHotKey(Handle, HotKeyIDPrintKey);
  GlobalDeleteAtom(HotKeyIDPrintKey);
end;

Dazu rufen wir die Funktionen UnRegisterHotKey und GlobalDeleteAtom auf und übergeben entsprechend das Programm-Handle und all unsere IDs die wir zu Anfang registriert haben.

Im Programm auf HotKey reagieren

Zuletzt kommen wir zu dem wichtigsten Teil. Bislang haben wir unseren Hot Keys eindeutige IDs gegeben und sie registriert, jedoch reagiert unser Programm bisher noch nicht darauf.

Um auf einen registrierten HotKey reagieren zu können, müssen wir die Windows Message empfangen, die uns Windows an unserer Anwendung schickt, wenn eine entsprechend registrierte Tastenkombination gedrückt wurde.

Dazu deklarieren wir im private Bereich unserer Unit die Funktion WMHotKey:

private
   { Private declarations }
   procedure WMHotKey(var Msg: TWMHotKey); message WM_HOTKEY;

Der Code dieser Funktion könnte dann so aussehen:

procedure TForm1.WMHotKey(var Msg: TWMHotKey);
begin
  if Msg.HotKey = HotKeyID          then ShowMessage('STRG + F1');
  if Msg.HotKey = HotKeyIDFunctionA then ShowMessage('ALT + SHIFT + A');
  if Msg.HotKey = HotKeyIDFunctionB then ShowMessage('WIN + A');
  if Msg.HotKey = HotKeyIDPrintKey  then ShowMessage('PRINT KEY');
end;

In Msg.HotKey steht die ID des HotKeys, der die Funktion aufgerufen hat. Das heißt, wir müssen nur noch abfragen, welche unserer IDs in Msg.HotKey steht und können dann entsprechend darauf reagieren.

In diesem Beispiel geben wir nur mit ShowMessage() eine Nachricht aus, aber es wäre natürlich auch einen Aufruf jeder anderen Funktion oder eines anderen Programmcodes möglich.

AntwortenPositivNegativDatumStimmen
77 Stimmen

Wer dieses Tutorial mit Lazarus umsetzen möchte, wird auf die Fehlermeldung stoßen, dass TWMHotKey nicht definiert ist:

Error: Identifier not found "TWMHotKey"

Um es dennoch zum laufen zu bekommen, müssen wir TWMHotKey

procedure WMHotKey(var Msg:TWMHotkey);message WM_HOTKEY;

durch TMessage ersetzen:

procedure WMHotKey(var Msg:TMessage);message WM_HOTKEY;

TMessage enthält nicht die Eigenschaft "HotKey", stattdessen nehmen wir "wParam":

procedure TForm1.WMHotKey(var Msg: TMessage);
begin
  if Msg.wParam = HotKeyID          then ...
  if Msg.wParam = HotKeyIDFunctionA then ... 
  if Msg.wParam = HotKeyIDFunctionB then ...
  if Msg.wParam = HotKeyIDPrintKey  then ...
end;

Nicht vergessen: Die Unit Windows muss zur USES Section hinzugefügt werden.

So funktioniert es auch mit Lazarus unter Windows einen systemweiten Hotkey zu registrieren.
16.08.2014 um 09:22

AntwortenPositiv Negativ
55 Stimmen

Und wenn als 2te Taste "<" oder "." verwendet werden möchte, wie stelle ich dann die VK_ ein?
21.06.2021 um 14:14

AntwortenPositiv Negativ
55 Stimmen

Nicht jedes Zeichen ist auch als VK_-Konstante definiert.

Du kannst aber ord() verwenden, um auf die Codes zu kommen:

var
  VK_SMALLERTHAN, VK_DOT: integer;
begin
  VK_SMALLERTHAN := ord('<');  // 60
  VK_DOT         := ord('.');  // 46
end;

Wenn du die Werte so ermittelt hast, kannst du die Konstanten natürlich auch gleich selber definieren um die Konstanten dann zu verwenden:

const
  VK_SMALLERTHAN = 60;
  VK_DOT         = 46;

Analog ist dies natürlich auch für andere Tasten möglich.

Darüber hinaus kannst du dir in Lazarus auch die Unit LCLType ansehen, darin siehst du um Zeile 400 bis 500 herum alle vordefinierten Konstanten, die du verwenden kannst ohne sie selbst zu definieren.
21.06.2021 um 16:03

Positiv Negativ
Antworten
Antworten

Über den Autor

AvatarSoftware von Stefan Trost finden Sie auf sttmedia.de. Benötigen Sie eine individuelle Software nach Ihren eigenen Wünschen? Schreiben Sie uns: sttmedia.de/kontakt
Profil anzeigen

 

Ähnliche Themen

Wichtiger Hinweis

Bitte beachten Sie: Die Beiträge auf askingbox.de sind Beiträge von Nutzern und sollen keine professionelle Beratung ersetzen. Sie werden nicht von Unabhängigen geprüft und spiegeln nicht zwingend die Meinung von askingbox.de wieder. Mehr erfahren.

Jetzt mitmachen

Stellen Sie Ihre eigene Frage oder schreiben Sie Ihren eigenen Artikel auf askingbox.de. So gehts.