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

Posted on 1998-10-05
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.
Question by:mince

Author Comment

ID: 1341814
Please answer my question immediately because I need it very much to complete my

Expert Comment

ID: 1341815
Isn't "OnKeyDown"/"OnKeyUp" fast enough?

/// John

Expert Comment

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.

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

LVL 10

Expert Comment

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...

Viktor Ivanov
LVL 10

Expert Comment

ID: 1341818
though = thought, actually it's though too ;->

Accepted Solution

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.  

  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);

  KeysDown[Key and 255] := true;

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;
  for i := 0 to 255 do KeysDown[i] := false;


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;


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

  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 declarations }
    { Public declarations }

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


{$R *.DFM}

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

  KeysDown[Key and 255] := true;

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

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

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



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_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_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_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_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;



Featured Post

VMware Disaster Recovery and Data Protection

In this expert guide, you’ll learn about the components of a Modern Data Center. You will use cases for the value-added capabilities of Veeam®, including combining backup and replication for VMware disaster recovery and using replication for data center migration.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
TVirtualStringTree  search using TEdit 7 121
Downloading email attachments 2 74
JAudiorecorder record freezing the app 29 67
how to resize animated Gif image in delphi ? 1 31
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…
In a recent question ( here at Experts Exchange, a member asked how to add page numbers to a PDF file using Adobe Acrobat XI Pro. This short video Micro Tutorial sh…
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…

821 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