2007. április 16., hétfő

Interesting API calls part I : detecting simultaneous keystrokes


Problem/Question/Abstract:

How can I detect if more than one key is pressed at the same time?

Answer:

You can use Windows API to detect multiple keystrokes. The name of the function that give us this facility is GetKeyState. The higher order bit show us the state of the key we pass as parameter to the function. On this sample I detect the states of the arrow keys, spacebar, shift keys and ESC. This sample can detect up to four keystrokes at the same time, but have some limitations, due to hardware limitations (i think). This will detect UP + RIGHT + SPACE but won�t detect UP + LEFT + SPACE. I may be wrong, but this happens because of keyboards pins design. That�s why I included the SHIFT state, because SHIFT keys will be detected with any combination of arrow keys. To run this sample place on a blank form a Label and a Button. Click the button to start, press ESC to stop.

{****************************************************************
*     Multiple keystrokes detection using Windows API          *
*     Source written by Rafael Cotta (rcotta.geo@yahoo.com)    *
*     July 26th, 2001                                          *
****************************************************************}

// To run this sample, create a blank form, and place a label
// and a timer on it.

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

function GetKeysPressed(): Cardinal;

var
  Form1: TForm1;

implementation

{$R *.DFM}

{
   Each bit on the function result represents
   the state of a key, so

      0000 0001 = UP
      0000 0010 = DOWN
      0000 0100 = LEFT
      0000 1000 = RIGHT
      0001 0000 = SPACE BAR
      0010 0000 = ESC
      0100 0000 = SHIFT
}

function GetKeysPressed(): Cardinal;
var
  dwRet: Cardinal;
begin

  dwRet := 0;

  if ((GetKeyState(VK_UP) and $10000000) > 0) then
    dwRet := dwRet + 1;
  if ((GetKeyState(VK_DOWN) and $10000000) > 0) then
    dwRet := dwRet + 2;
  if ((GetKeyState(VK_LEFT) and $10000000) > 0) then
    dwRet := dwRet + 4;
  if ((GetKeyState(VK_RIGHT) and $10000000) > 0) then
    dwRet := dwRet + 8;
  if ((GetKeyState(32) and $10000000) > 0) then
    dwRet := dwRet + 16; // SpaceBar
  if ((GetKeyState(27) and $10000000) > 0) then
    dwRet := dwRet + 32; // ESC
  if ((GetKeyState(VK_SHIFT) and $10000000) > 0) then
    dwRet := dwRet + 64; // ESC

  GetKeysPressed := dwRet;

end;

procedure TForm1.Button1Click(Sender: TObject);
var
  dwKeys: Cardinal;
begin
  dwKeys := 0;

  // While ESC is not pressed

  while ((dwKeys and 32) = 0) do
  begin
    Application.ProcessMessages;
    dwKeys := GetKeysPressed;

    Label1.Caption := 'Keys pressed : ';

    if ((dwKeys and 1) > 0) then
      Label1.Caption := Label1.Caption + ' UP';

    if ((dwKeys and 2) > 0) then
      Label1.Caption := Label1.Caption + ' DOWN';

    if ((dwKeys and 4) > 0) then
      Label1.Caption := Label1.Caption + ' LEFT';

    if ((dwKeys and 8) > 0) then
      Label1.Caption := Label1.Caption + ' RIGHT';

    if ((dwKeys and 16) > 0) then
      Label1.Caption := Label1.Caption + ' SPACE';

    if ((dwKeys and 32) > 0) then
      Label1.Caption := Label1.Caption + ' ESC';

    if ((dwKeys and 64) > 0) then
      Label1.Caption := Label1.Caption + ' SHIFT';

  end;

end;

end.

Nincsenek megjegyzések:

Megjegyzés küldése