Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 914
  • Last Modified:

Keyboard access for Delphi game loop

Hello! I wonder whether anyone can help me -

I would like to write a simple loop with the ability to 'poll' the keyboard for key presses, so that if say the Down Arrow is pressed, something in the code will respond (I guess using a Case statement).

I have found some code that appears to work in exe form but that my version of Delphi will not compile - John Ayres Delphi Rocks (asteriods clone) - the code uses 'outdated' keyboard HOOKS.

HookProc:=MakeProcInstance(@KeyboardHook, HInstance);
KBHook:=SetWindowsHookEx(WH_KEYBOARD,THookProc(HookProc),HInstance,GetCurrentTask);
 
How can I access the Windows handles to check if any keys are being pressed?

Also if I'm right in my thinking am I limited to just detecting one keypress at a time?

As you might have guessed the loop is intended for simple games/simulators w/o Direct X (for now).
0
lefunkster
Asked:
lefunkster
3 Solutions
 
DavidBirch2dotComCommented:
why not just use the key down/up on the draw or on the form ?
0
 
shaneholmesCommented:
Procedure wmgetdlgCode(var Message:Twmgetdlgcode); message
WM_GetDlgCode;

Procedure TMycomponent.wmgetdlgCode(var Message:Twmgetdlgcode);
begin
 message.result:=DLGC_WantArrows;
end;

This will force the form to recognize the arrow key strokes and you can
do what ever you like with them
please keep in mind that you have to zero the key variable on the
onkeydown event if you don't want delphi's key handling procedure to
take any action on them.
like this...

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift:
TShiftState);
begin
  if key = vk_space then key := 0;
end;
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
lefunksterAuthor Commented:
OK - thanks for the response!

This is were I am with this:

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  // Let's move the sprite every time the arrow keys are pressed

  if Key = vk_left then PosX := PosX - 1; // Left
  if Key = vk_up  then PosY := PosY - 1; // Up
  if Key = 39 then PosX := PosX + 1; // Right
  if Key = 40 then PosY := PosY + 1; // Down
end;

This works but just for one keystroke - ie pressing 2 keys isn't processed; stepping through the code shows that the whole procedure is run through yet only one keystoke (ie move) is registered... is there a way around this?

I've only gone this way as this appears to be the simplest way to get the job done. I am a beginner and will of course look at Handles soon (I can't say I like the look of them - but I'm sure once I get a 'handle' on them...)

0
 
jonas78Commented:
Here is a shortcut:

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Shape1: TShape;
    Timer1: TTimer;
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure Timer1Timer(Sender: TObject);
    procedure FormKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
  private
    { Private declarations }
  public
    { Public declarations }
    CKey:Word;

   CLeft,CRight,CUp,CDown:Boolean;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin

CKey := Key;

if Key = VK_LEFT then
  CLeft := True;
if Key = VK_RIGHT then
   CRight := True;
if Key = VK_UP then
   CUp := True;
if Key = VK_DOWN then
   CDown := True;

end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
if CLeft then
  Shape1.Left := Shape1.Left -2;
if CRight then
  Shape1.Left := Shape1.Left +2;
if CUp then
  Shape1.Top := Shape1.Top -2;
if CDown then
  Shape1.Top := Shape1.Top +2;
end;

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
if Key = VK_LEFT then
  CLeft := False;
if Key = VK_RIGHT then
   CRight := False;
if Key = VK_UP then
   CUp := False;
if Key = VK_DOWN then
   CDown := False;
end;

end.
0
 
jonas78Commented:
It's probably not the best way to do this but it works.

Just remember to set the timer intervall to something low like 100 or 50 depending on what refresh rate you want.
0
 
-Thespian-Commented:
The easy way - make an array of keys. The keyboard has <256 keys. So:
keys: array [0..255] of boolean; //the size is 256 if you will not use special keys.

Init somewere:
for i:=0 to 255 do
  keys[i]:=false;

In KeyDown proc:
  keys[Key]:=true;

In KeyUp proc:
  keys[Key]:=false;

In the procedure where you draw (for example before drawing scene):
if (keys[VK_UP])and(keys[VK_LEFT]) then
begin
  keys[VK_UP]:=false;
  keys[VK_LEFT]:=false;
  // Do anything;
end;

______
Best regards,
  Thespian.
0
 
Slick812Commented:
hello lefunkster, , , I might use the API function  GetAsyncKeyState( ) to get a reading of wheather a Key is down or not

if GetAsyncKeyState(Ord('H')) < 0 then

if GetAsyncKeyState(VK_LEFT) < 0 then

 - - - - - - -  -

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  // Let's move the sprite every time the arrow keys are pressed

  if Key = vk_left then
    if GetAsyncKeyState(Ord('M')) < 0 then
    PosX := PosX - 2
    else
    PosX := PosX-1;

  if Key = vk_up  then
     if GetAsyncKeyState(VK_SHIFT) < 0 then
      PosX := PosY - 2
      else
      PosX := PosY-1;

  if Key = 39 then PosX := PosX + 1; // Right
  if Key = 40 then PosY := PosY + 1; // Down
end;
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Tackle projects and never again get stuck behind a technical roadblock.
Join Now