Intercettazione dell'input da tastiera con Delphi

Considera per un momento la creazione di alcuni giochi arcade veloci. Tutta la grafica viene visualizzata, diciamo, in un TPainBox. TPaintBox non è in grado di ricevere lo stato attivo dell'input: nessun evento viene generato quando l'utente preme un tasto; non possiamo intercettare i tasti cursore per muovere la nostra corazzata. Aiuto Delphi!

Intercetta input da tastiera

La maggior parte delle applicazioni Delphi in genere gestiscono l'input dell'utente tramite gestori di eventi specifici, quelli che ci consentono di catturare i tasti utente e di elaborare il movimento del mouse.

Sappiamo che il focus è la capacità di ricevere l'input dell'utente tramite il mouse o la tastiera. Solo il l'oggetto che ha lo stato attivo può ricevere un evento da tastiera. Alcuni controlli, come TImage, TPaintBox, TPanel e TLabel non possono ricevere lo stato attivo. Lo scopo principale della maggior parte dei controlli grafici è visualizzare testo o grafica.

Se vogliamo intercettare l'input da tastiera per i controlli che non possono ricevere lo stato attivo dell'input, dovremo occuparci di API, hook, callback e messaggi di Windows.

Ganci di Windows

Tecnicamente, una funzione "hook" è una funzione di callback che può essere inserita nel sistema di messaggi di Windows in modo che un'applicazione possa accedere al flusso di messaggi prima che abbia luogo un'altra elaborazione del messaggio. Tra molti tipi di hook di Windows, viene chiamato un hook di tastiera ogni volta che l'applicazione chiama la funzione GetMessage () o PeekMessage () e c'è un messaggio da tastiera WM_KEYUP o WM_KEYDOWN da elaborare.

Per creare un hook di tastiera che intercetta tutti gli input da tastiera diretti a un determinato thread, dobbiamo chiamare SetWindowsHookEx Funzione API. Le routine che ricevono gli eventi della tastiera sono funzioni di callback definite dall'applicazione chiamate funzioni hook (KeyboardHookProc). Windows chiama la funzione hook per ciascun messaggio di battitura (tasto su e tasto giù) prima che il messaggio venga inserito nella coda dei messaggi dell'applicazione. La funzione hook può elaborare, modificare o scartare i tasti. Gli hook possono essere locali o globali.

Il valore di ritorno di SetWindowsHookEx è un handle per il gancio appena installato. Prima di terminare, un'applicazione deve chiamare il UnhookWindowsHookEx funzione per liberare risorse di sistema associate all'hook.

Esempio di hook della tastiera

Come dimostrazione degli hook della tastiera, creeremo un progetto con controllo grafico in grado di ricevere la pressione dei tasti. TImage è derivato da TGraphicControl, può essere utilizzato come superficie di disegno per il nostro ipotetico gioco di battaglia. Poiché TImage non è in grado di ricevere pressioni da tastiera attraverso eventi da tastiera standard, creeremo una funzione hook che intercetta tutti gli input da tastiera diretti verso la nostra superficie di disegno.

Elaborazione eventi tastiera tastiera

Avviare un nuovo progetto Delphi e posizionare un componente Image in un modulo. Impostare la proprietà Image1.Align su alClient. Questo è tutto per la parte visiva, ora dobbiamo fare un po 'di codice. Innanzitutto, avremo bisogno di alcune variabili globali:

 var
  Form1: TForm1;
  KBHook: HHook; questo intercetta l'input da tastiera
  cx, cy: intero; traccia la posizione della nave da battaglia
  dichiarazione di richiamata
  funzione KeyboardHookProc (Codice: intero; WordParam: Word; LongParam: LongInt): LongInt; stdcall;
implementazione
...

Per installare un hook, chiamiamo SetWindowsHookEx nell'evento OnCreate di un modulo.

 procedura TForm1.FormCreate (mittente: TObject);
inizio
 Imposta il gancio della tastiera in modo che possiamo intercettare l'input da tastiera
 KBHook: = SetWindowsHookEx (WH_KEYBOARD,
           callback> @KeyboardHookProc,
                          hInstance,
                          GetCurrentThreadId ());
 posiziona la nave da battaglia al centro dello schermo
 cx: = Image1.ClientWidth div 2;
 cy: = Image1.ClientHeight div 2;
 Image1.Canvas.PenPos: = Point (cx, cy);
fine;

Per liberare risorse di sistema associate all'hook, dobbiamo chiamare la funzione UnhookWindowsHookEx nell'evento OnDestroy:

 procedura TForm1.FormDestroy (mittente: TObject);
inizio
  sganciare l'intercettazione da tastiera
  UnHookWindowsHookEx (KBHook);
fine;

La parte più importante di questo progetto è la Procedura di richiamata KeyboardHookProc utilizzato per elaborare i tasti.

 funzione KeyboardHookProc (Codice: intero; WordParam: Word; LongParam: LongInt): LongInt;
inizio
 caso WordParam di
  vk_Space: cancella il percorso della nave da battaglia
   inizio
    con Form1.Image1.Canvas do
    inizio
     Brush.Color: = clWhite;
     Brush.Style: = bsSolid;
     Fillrect (Form1.Image1.ClientRect);
    fine;
   fine;
  vk_Right: cx: = cx + 1;
  vk_Left: cx: = cx-1;
  vk_Up: cy: = cy-1;
  vk_Down: cy: = cy + 1;
 fine; Astuccio
 Se cx < 2 then cx := Form1.Image1.ClientWidth-2;
 Se cx> Form1.Image1.ClientWidth -2 quindi cx: = 2;
 Se il cy < 2 then cy := Form1.Image1.ClientHeight -2 ;
 Se cy> Form1.Image1.ClientHeight-2 quindi cy: = 2;
 con Form1.Image1.Canvas do
 inizio
  Pen.Color: = clRed;
  Brush.Color: = clYellow;
  TextOut (0,0, formato ('% d,% d', [cx, cy]));
  Rettangolo (cx-2, cy-2, cx + 2, cy + 2);
 fine;
 Risultato: = 0;
Per impedire a Windows di passare le sequenze di tasti alla finestra di destinazione, il valore Risultato deve essere un valore diverso da zero.
fine;

Questo è tutto. Ora abbiamo l'ultimo codice di elaborazione della tastiera.

Nota solo una cosa: questo codice non è in alcun modo limitato per essere utilizzato solo con TImage.

La funzione KeyboardHookProc funge da meccanismo KeyPreview e KeyProcess generale.