Avlyssna tangentbordinmatning med Delphi

Tänk ett ögonblick på att skapa ett snabbt arkadspel. All grafik visas, låt oss säga, i en TPainBox. TPaintBox kan inte ta emot inmatningsfokus - inga händelser avfyras när användaren trycker på en knapp; vi kan inte fånga markörtangenterna för att flytta vårt slagskepp. Delphi hjälp!

Avlyssna tangentbordets ingång

De flesta Delphi-applikationer hanterar vanligtvis användarinmatning genom specifika händelseshanterare, de som gör det möjligt för oss att fånga användarnas knapptryckningar och bearbeta musrörelser.

Vi vet att fokus är förmågan att ta emot användarinmatning via musen eller tangentbordet. Bara objekt som har fokus kan ta emot en tangentbordshändelse. Vissa kontroller, som TImage, TPaintBox, TPanel och TLabel kan inte få fokus. Det huvudsakliga syftet med de flesta grafiska kontroller är att visa text eller grafik.

Om vi ​​vill avlyssna tangentbordsinmatningen för kontroller som inte kan få inmatningsfokus måste vi ta itu med Windows API, krokar, återuppringningar och meddelanden.

Windows krokar

Tekniskt sett är en "hook" -funktion en återuppringningsfunktion som kan infogas i Windows-meddelandesystemet så att en applikation kan komma åt meddelandeströmmen innan annan behandling av meddelandet äger rum. Bland många typer av fönsterkrokar kallas en tangentbordskrok när applikationen kallar GetMessage () eller PeekMessage () -funktionen och det finns ett WM_KEYUP- eller WM_KEYDOWN-tangentbord för att bearbeta.

För att skapa en tangentbordskrok som fångar upp alla tangentbordsinmatningar riktade till en given tråd måste vi ringa SetWindowsHookEx API-funktion. Rutinerna som tar emot tangentbordshändelserna är applikationsdefinerade återuppringningsfunktioner som kallas hook-funktioner (KeyboardHookProc). Windows anropar din krokfunktion för varje tangenttryckningsmeddelande (tangent upp och ner) innan meddelandet placeras i programmets meddelandekö. Krokfunktionen kan bearbeta, ändra eller kasta tangenttryckningar. Krokar kan vara lokala eller globala.

Returvärdet för SetWindowsHookEx är ett handtag till kroken som just har installerats. Innan en ansökan avslutas måste en ansökan ringa UnhookWindowsHookEx funktion för att frigöra systemresurser kopplade till kroken.

Exempel på tangentbordskrok

Som en demonstration av tangentbordskrokar skapar vi ett projekt med grafisk kontroll som kan ta emot knapptryckningar. TImage härrör från TGraphicControl, det kan användas som en teckningsyta för vårt hypotetiska stridsspel. Eftersom TImage inte kan ta emot tangentbordspress genom standard tangentbordshändelser skapar vi en krokfunktion som avbryter all tangentbordingång riktad till vår ritningsyta.

TImage Bearbetar tangentbordshändelser

Starta nytt Delphi-projekt och placera en bildkomponent på ett formulär. Ställ in Image1.Align egenskapen till alClient. Det är det för den visuella delen, nu måste vi göra lite kodning. Först behöver vi några globala variabler:

 var
  Form1: TForm1;
  KBHook: HHook; detta avlyssnar tangentbordsinmatning
  cx, cy: heltal; spåra stridsfartygets position
  återuppringningsdeklaration
  funktion KeyboardHookProc (kod: heltal; WordParam: Word; LongParam: LongInt): LongInt; stdcall;
genomförande
...

För att installera en krok, kallar vi SetWindowsHookEx i händelsen OnCreate på ett formulär.

 procedur TForm1.FormCreate (avsändare: TObject);
Börja
 Ställ in tangentbordskroken så att vi kan fånga in tangentbordet
 KBHook: = SetWindowsHookEx (WH_KEYBOARD,
           callback> @KeyboardHookProc,
                          HInstance,
                          GetCurrentThreadId ());
 placera stridsfartyget mitt på skärmen
 cx: = Bild1.ClientWidth div 2;
 cy: = Image1.ClientHeight div 2;
 Image1.Canvas.PenPos: = Punkt (cx, cy);
slutet;

För att frigöra systemresurser kopplade till kroken måste vi anropa funktionen UnhookWindowsHookEx i händelsen OnDestroy:

 procedur TForm1.FormDestroy (avsändare: TObject);
Börja
  ta bort tangentbordets avlyssning
  UnHookWindowsHookEx (KBHook);
slutet;

Den viktigaste delen av detta projekt är KeyboardHookProc återuppringningsprocedur används för att behandla tangenttryckningar.

 funktion KeyboardHookProc (kod: heltal; WordParam: Word; LongParam: LongInt): LongInt;
Börja
 fall WordParam av
  vk_Space: radera stridsfartygets väg
   Börja
    med Form1.Image1.Canvas do
    Börja
     Brush.Color: = clWhite;
     Brush.Style: = bsSolid;
     Fillrect (Form1.Image1.ClientRect);
    slutet;
   slutet;
  vk_Right: cx: = cx + 1;
  vk_Left: cx: = cx-1;
  vk_Up: cy: = cy-1;
  vk_Down: cy: = cy + 1;
 slutet; fall
 Om cx < 2 then cx := Form1.Image1.ClientWidth-2;
 Om cx> Form1.Image1.ClientWidth -2, då cx: = 2;
 Om cy < 2 then cy := Form1.Image1.ClientHeight -2 ;
 Om cy> Form1.Image1.ClientHeight-2 då cy: = 2;
 med Form1.Image1.Canvas do
 Börja
  Pen.Färg: = clRed;
  Brush.Color: = clellow;
  TextOut (0,0, Format ('% d,% d', [cx, cy]));
  Rektangel (cx-2, cy-2, cx + 2, cy + 2);
 slutet;
 Resultera: = 0;
För att förhindra att Windows överför tangenttryckningarna till målfönstret måste resultatvärdet vara ett icke-nollvärde.
slutet;

Det är allt. Vi har nu den ultimata koden för bearbetning av tangentbord.

Observera bara en sak: den här koden är inte begränsad till att användas endast med TImage.

Funktionen KeyboardHookProc fungerar som en generell KeyPreview & KeyProcess-mekanism.