Solved

Keyboard handler (for game) with Delphi or C++ Builder

Posted on 1998-10-05
6
488 Views
Last Modified: 2010-04-06
How to make a keyboard handler (usually games use it, like
doom, duke nukeem so it can run very fast) with Delphi or C++ Builder. I want to get very immediate respons when I press keyboard so I can move fastly.
0
Comment
Question by:mince
6 Comments
 

Author Comment

by:mince
ID: 1341814
Please answer my question immediately because I need it very much to complete my
study.
0
 
LVL 4

Expert Comment

by:erajoj
ID: 1341815
Hi,
Isn't "OnKeyDown"/"OnKeyUp" fast enough?

/// John
0
 
LVL 1

Expert Comment

by:Roadrunner100598
ID: 1341816
If your program should recieve (and maybe process) the keyboard message first, try a hook function (see: SetWindowsHookEx). This will gain some extra microseconds.

And of course there is DirectX 5 - DirectInput as described in Mircosoft Press's 'Inside Direct X'. But I have never tried it myself...

Generally I would recommend using 'OnKeyDown'/'OnKeyUp' as the savest and easiest solution.

. and set the repetition rate in the control panel/keyboard to maximum.

Roadrunner
0
Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

 
LVL 10

Expert Comment

by:viktornet
ID: 1341817
Yup, as the guys told you what you should do I guess I don't need to repeat that suggestion again.... OnKeyPress/OnKeyDown/OnKeyUp/SetWindowsHookEx/UnhookWindows.....and so on.....

P.S. Especially for games I guess the Hook is better, but it's more comlex to implement.... By complex I mean that you need more, code, more though, and a DLL which should be provided with your program...

Regards,
Viktor Ivanov
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1341818
though = thought, actually it's though too ;->
0
 
LVL 5

Accepted Solution

by:
scrapdog earned 200 total points
ID: 1341819
It is not a good idea to use events alone for a keyboard handler in a game.  In games, it is necessary to check whether or not several keys or pressed at a time.

The best way to do this is to use an array of booleans.  

var
  KeysDown :array[0..255] of boolean;

During your program, at any time you could check if a key is down or not by checking the array.  For example if you want to see if the A key is down, you would use:

if KeysDown[65] then ...

(where 65 is the key code for A).

And if you wanted to check if the A key AND the B key are both down, you could use:

if KeysDown[65] and KeysDown[66] then...



In order to keep this array updated, you can use the OnKeyUp and OnKeyDown events for your form.



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

  KeysDown[Key and 255] := true;
end;



When the key is pressed, its respective value in the array is set to true.  And then when the key is released, it is set back to false.

It is important that you intialize the KeysDown array to all false values before you start though. (like this)


procedure TForm1.FormCreate(Sender: TObject);
var i :integer;
begin
  for i := 0 to 255 do KeysDown[i] := false;
end;


---------------------------------------

This is the way DOS games handle the keyboard.  Any keypress or release generates make or break codes which are processed and the results are stored in an array.  Using this method allows to detect exactly which keys (even all of them) are down at any given moment.


Here is a demo program.  It shows which of the keys from a to z are pressed, in a label.


unit Unit1;

interface

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

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

var
  Form1: TForm1;
  KeysDown :array[0..255] of boolean;

implementation

{$R *.DFM}

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

  KeysDown[Key and 255] := true;
end;



procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  KeysDown[Key and 255] := false;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i :integer;
begin
  for i := 0 to 255 do KeysDown[i] := false;
end;

procedure TForm1.Timer1Timer(Sender: TObject);  //interval of 1 msec or so
var KeyStr :string;
    i      :integer;
begin
  KeyStr := '';
  for i := 65 to 90 do
    if KeysDown[i] then KeyStr := KeyStr + Chr(i);
  Label1.Caption := KeyStr;

end;

end.



Make sure you set the timer to a small interval (to make sure the label is updated quickly).  The keyboard handler is operating at all times though.


Here is a list of scan codes, taken from the Windows source code that came with Delphi
------------------------------------------

VK_LBUTTON = 1;
  VK_RBUTTON = 2;
  VK_CANCEL = 3;
  VK_MBUTTON = 4;  { NOT contiguous with L & RBUTTON }
  VK_BACK = 8;
  VK_TAB = 9;
  VK_CLEAR = 12;
  VK_RETURN = 13;
  VK_SHIFT = $10;
  VK_CONTROL = 17;
  VK_MENU = 18;
  VK_PAUSE = 19;
  VK_CAPITAL = 20;
  VK_ESCAPE = 27;
  VK_SPACE = $20;
  VK_PRIOR = 33;
  VK_NEXT = 34;
  VK_END = 35;
  VK_HOME = 36;
  VK_LEFT = 37;
  VK_UP = 38;
  VK_RIGHT = 39;
  VK_DOWN = 40;
  VK_SELECT = 41;
  VK_PRINT = 42;
  VK_EXECUTE = 43;
  VK_SNAPSHOT = 44;
  VK_INSERT = 45;
  VK_DELETE = 46;
  VK_HELP = 47;
{ VK_0 thru VK_9 are the same as ASCII '0' thru '9' ($30 - $39) }
{ VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' ($41 - $5A) }
  VK_LWIN = 91;
  VK_RWIN = 92;
  VK_APPS = 93;
  VK_NUMPAD0 = 96;
  VK_NUMPAD1 = 97;
  VK_NUMPAD2 = 98;
  VK_NUMPAD3 = 99;
  VK_NUMPAD4 = 100;
  VK_NUMPAD5 = 101;
  VK_NUMPAD6 = 102;
  VK_NUMPAD7 = 103;
  VK_NUMPAD8 = 104;
  VK_NUMPAD9 = 105;
  VK_MULTIPLY = 106;
  VK_ADD = 107;
  VK_SEPARATOR = 108;
  VK_SUBTRACT = 109;
  VK_DECIMAL = 110;
  VK_DIVIDE = 111;
  VK_F1 = 112;
  VK_F2 = 113;
  VK_F3 = 114;
  VK_F4 = 115;
  VK_F5 = 116;
  VK_F6 = 117;
  VK_F7 = 118;
  VK_F8 = 119;
  VK_F9 = 120;
  VK_F10 = 121;
  VK_F11 = 122;
  VK_F12 = 123;
  VK_F13 = 124;
  VK_F14 = 125;
  VK_F15 = 126;
  VK_F16 = 127;
  VK_F17 = 128;
  VK_F18 = 129;
  VK_F19 = 130;
  VK_F20 = 131;
  VK_F21 = 132;
  VK_F22 = 133;
  VK_F23 = 134;
  VK_F24 = 135;
  VK_NUMLOCK = 144;
  VK_SCROLL = 145;
{ VK_L & VK_R - left and right Alt, Ctrl and Shift virtual keys.
  Used only as parameters to GetAsyncKeyState() and GetKeyState().
  No other API or message will distinguish left and right keys in this way. }
  VK_LSHIFT = 160;
  VK_RSHIFT = 161;
  VK_LCONTROL = 162;
  VK_RCONTROL = 163;
  VK_LMENU = 164;
  VK_RMENU = 165;
  VK_PROCESSKEY = 229;
  VK_ATTN = 246;
  VK_CRSEL = 247;
  VK_EXSEL = 248;
  VK_EREOF = 249;
  VK_PLAY = 250;
  VK_ZOOM = 251;
  VK_NONAME = 252;
  VK_PA1 = 253;
  VK_OEM_CLEAR = 254;


Scrapdog

0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …

820 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question