Toetsenbordinvoer onderscheppen met Delphi

Overweeg even om een ​​snel arcade-spel te maken. Alle afbeeldingen worden, laten we zeggen, weergegeven in een TPainBox. TPaintBox kan de invoerfocus niet ontvangen - er worden geen gebeurtenissen geactiveerd wanneer de gebruiker op een toets drukt; we kunnen cursortoetsen niet onderscheppen om ons slagschip te verplaatsen. Delphi help!

Toetsenbordinvoer onderscheppen

De meeste Delphi-applicaties verwerken doorgaans gebruikersinvoer via specifieke eventhandlers, waarmee we gebruikersaanslagen kunnen vastleggen en muisbewegingen kunnen verwerken.

We weten dat focus de mogelijkheid is om gebruikersinvoer te ontvangen via de muis of het toetsenbord. Alleen de object dat de focus heeft, kan een toetsenbordgebeurtenis ontvangen. Sommige bedieningselementen, zoals TImage, TPaintBox, TPanel en TLabel kunnen geen focus krijgen. Het primaire doel van de meeste grafische bedieningselementen is om tekst of afbeeldingen weer te geven.

Als we toetsenbordinvoer willen onderscheppen voor besturingselementen die de invoerfocus niet kunnen ontvangen, hebben we te maken met Windows API, hooks, callbacks en berichten.

Windows Haken

Technisch gezien is een "hook" -functie een callback-functie die kan worden ingevoegd in het Windows-berichtensysteem, zodat een toepassing toegang heeft tot de berichtenstroom voordat andere verwerking van het bericht plaatsvindt. Onder veel soorten Windows-haken wordt een toetsenbordhaak aangeroepen wanneer de toepassing de functie GetMessage () of PeekMessage () aanroept en er een WM_KEYUP- of WM_KEYDOWN-toetsenbordbericht moet worden verwerkt.

Om een ​​toetsenbordhaak te maken die alle toetsenbordinvoer onderschept die naar een bepaalde thread is gericht, moeten we bellen SetWindowsHookEx API-functie. De routines die de toetsenbordgebeurtenissen ontvangen, zijn door de toepassing gedefinieerde callback-functies, hook-functies genoemd (KeyboardHookProc). Windows roept uw ​​hook-functie aan voor elk toetsaanslagbericht (toets omhoog en toets omlaag) voordat het bericht in de berichtenwachtrij van de toepassing wordt geplaatst. De hook-functie kan toetsaanslagen verwerken, wijzigen of weggooien. Haken kunnen lokaal of wereldwijd zijn.

De geretourneerde waarde van SetWindowsHookEx is een greep naar de net geïnstalleerde haak. Voordat de toepassing wordt beëindigd, moet de toepassing de UnhookWindowsHookEx functie om systeembronnen vrij te maken die aan de haak zijn gekoppeld.

Voorbeeld van toetsenbordhaak

Als een demonstratie van toetsenbordhaken maken we een project met grafische besturing dat toetsaanslagen kan ontvangen. TImage is afgeleid van TGraphicControl en kan worden gebruikt als een tekenoppervlak voor ons hypothetische vechtspel. Aangezien TImage geen toetsaanslagen kan ontvangen via standaard toetsenbordgebeurtenissen, maken we een haakfunctie die alle toetsenbordinvoer onderschept die naar ons tekenoppervlak is gericht.

TImage Toetsenbordgebeurtenissen verwerken

Start een nieuw Delphi-project en plaats een afbeeldingscomponent op een formulier. Stel Image1.Align property in op alClient. Dat is het voor het visuele gedeelte, nu moeten we wat codering doen. Eerst hebben we enkele globale variabelen nodig:

 var
  Form1: TForm1;
  KBHook: HHook; dit onderschept toetsenbordinvoer
  cx, cy: geheel getal; volg positie gevechtsschip
  terugbelverklaring
  functie KeyboardHookProc (Code: Integer; WordParam: Word; LongParam: LongInt): LongInt; stdcall;
implementatie
...

Om een ​​hook te installeren, roepen we SetWindowsHookEx aan in de OnCreate-gebeurtenis van een formulier.

 procedure TForm1.FormCreate (afzender: TObject);
beginnen
 Stel de toetsenbordhaak in zodat we toetsenbordinvoer kunnen onderscheppen
 KBHook: = SetWindowsHookEx (WH KEYBOARD,
           callback> @KeyboardHookProc,
                          hInstance,
                          GetCurrentThreadId ());
 plaats het gevechtsschip in het midden van het scherm
 cx: = Image1.ClientWidth div 2;
 cy: = Image1.ClientHeight div 2;
 Image1.Canvas.PenPos: = Point (cx, cy);
einde;

Om systeembronnen vrij te maken die aan de hook zijn gekoppeld, moeten we de functie UnhookWindowsHookEx aanroepen in de OnDestroy-gebeurtenis:

 procedure TForm1.FormDestroy (afzender: TObject);
beginnen
  haak de onderschepping van het toetsenbord los
  UnHookWindowsHookEx (KBHook);
einde;

Het belangrijkste onderdeel van dit project is het KeyboardHookProc callback-procedure gebruikt om toetsaanslagen te verwerken.

 functie KeyboardHookProc (Code: Integer; WordParam: Word; LongParam: LongInt): LongInt;
beginnen
 case WordParam van
  vk_Space: pad van gevechtsschip wissen
   beginnen
    met Form1.Image1.Canvas doen
    beginnen
     Brush.Color: = clWhite;
     Brush.Style: = bsSolid;
     Fillrect (Form1.Image1.ClientRect);
    einde;
   einde;
  vk_Right: cx: = cx + 1;
  vk_Left: cx: = cx-1;
  vk_Up: cy: = cy-1;
  vk_Down: cy: = cy + 1;
 einde; geval
 Als cx < 2 then cx := Form1.Image1.ClientWidth-2;
 Als cx> Form1.Image1.ClientWidth -2 dan cx: = 2;
 Als cy < 2 then cy := Form1.Image1.ClientHeight -2 ;
 Als cy> Form1.Image1.ClientHeight-2 dan cy: = 2;
 met Form1.Image1.Canvas doen
 beginnen
  Pen.Color: = clRed;
  Brush.Color: = clGeel;
  TextOut (0,0, Format ('% d,% d', [cx, cy]));
  Rechthoek (cx-2, cy-2, cx + 2, cy + 2);
 einde;
 Resultaat: = 0;
Om te voorkomen dat Windows de toetsaanslagen doorgeeft aan het doelvenster, moet de resultaatwaarde een waarde van nul zijn.
einde;

Dat is het. We hebben nu de ultieme toetsenbordverwerkingscode.

Let op slechts één ding: deze code is geenszins beperkt om alleen met TImage te worden gebruikt.

De functie KeyboardHookProc dient als een algemeen KeyPreview & KeyProcess-mechanisme.