Keyboard Handler

Unit: Keyboard

Hardware keyboard handler via INT 9h interrupt.

Constants

Common Keys

const
  { Letters }
  Key_A = $1E;  Key_B = $30;  Key_C = $2E;  Key_D = $20;
  Key_E = $12;  Key_F = $21;  Key_G = $22;  Key_H = $23;
  Key_I = $17;  Key_J = $24;  Key_K = $25;  Key_L = $26;
  Key_M = $32;  Key_N = $31;  Key_O = $18;  Key_P = $19;
  Key_Q = $10;  Key_R = $13;  Key_S = $1F;  Key_T = $14;
  Key_U = $16;  Key_V = $2F;  Key_W = $11;  Key_X = $2D;
  Key_Y = $15;  Key_Z = $2C;

  { Numbers }
  Key_1 = $02;  Key_2 = $03;  Key_3 = $04;  Key_4 = $05;
  Key_5 = $06;  Key_6 = $07;  Key_7 = $08;  Key_8 = $09;
  Key_9 = $0A;  Key_0 = $0B;

  { Function keys }
  Key_F1 = $3B;  Key_F2 = $3C;  Key_F3 = $3D;  Key_F4 = $3E;
  Key_F5 = $3F;  Key_F6 = $40;  Key_F7 = $41;  Key_F8 = $42;
  Key_F9 = $43;  Key_F10 = $44; Key_F11 = $57; Key_F12 = $58;

  { Special }
  Key_Escape = $01;  Key_Enter = $1C;  Key_Space = $39;
  Key_Backspace = $0E;  Key_Tab = $0F;

  { Arrows }
  Key_Up = $48;  Key_Down = $50;  Key_Left = $4B;  Key_Right = $4D;

  { Modifiers }
  Key_LShift = $2A;  Key_RShift = $36;
  Key_LCtrl = $1D;   Key_LAlt = $38;

Character Maps

const
  CharMapNormal: array[0..127] of Char;  { Scancode → char }
  CharMapShift: array[0..127] of Char;   { Scancode → char (shifted) }

Functions

procedure InitKeyboard;                            { Hook INT 9h }
procedure DoneKeyboard;                            { CRITICAL: Unhook before exit }
function IsKeyDown(ScanCode: Byte): Boolean;       { Key currently held }
function IsKeyPressed(ScanCode: Byte): Boolean;    { Key pressed and released }
procedure ClearKeyPressed;                         { CRITICAL: Call at end of loop }
procedure ClearAllKeyStates;
function WaitForAnyKeyPress: Byte;

Example

uses Keyboard;

var
  Running: Boolean;

begin
  InitKeyboard;

  Running := True;
  while Running do
  begin
    { Continuous input - movement }
    if IsKeyDown(Key_W) then PlayerY := PlayerY - 2;
    if IsKeyDown(Key_S) then PlayerY := PlayerY + 2;
    if IsKeyDown(Key_A) then PlayerX := PlayerX - 2;
    if IsKeyDown(Key_D) then PlayerX := PlayerX + 2;

    { Single-press input - actions }
    if IsKeyPressed(Key_Space) then FireWeapon;
    if IsKeyPressed(Key_Escape) then Running := False;

    { Game logic and rendering }
    UpdateGame;
    RenderGame;

    { MUST call at end of loop }
    ClearKeyPressed;
  end;

  DoneKeyboard;  { CRITICAL: Unhook INT 9h }
end.

Text Input

var
  InputText: string;
  Shifted: Boolean;
  Ch: Char;
  ScanCode: Byte;

begin
  InitKeyboard;
  InputText := '';

  while InputActive do
  begin
    { Check shift state }
    Shifted := IsKeyDown(Key_LShift) or IsKeyDown(Key_RShift);

    { Scan letter keys }
    for ScanCode := Key_A to Key_Z do
    begin
      if IsKeyPressed(ScanCode) then
      begin
        if Shifted then
          Ch := CharMapShift[ScanCode]
        else
          Ch := CharMapNormal[ScanCode];
        InputText := InputText + Ch;
      end;
    end;

    { Backspace }
    if IsKeyPressed(Key_Backspace) and (Length(InputText) > 0) then
      Delete(InputText, Length(InputText), 1);

    { Enter to finish }
    if IsKeyPressed(Key_Enter) then
      InputActive := False;

    ClearKeyPressed;
  end;

  DoneKeyboard;
end;

Critical Rules

  1. InitKeyboard - MUST call before using any functions

  2. DoneKeyboard - MUST call before exit (unhooks INT 9h)

  3. ClearKeyPressed - MUST call at END of every game loop

  4. IsKeyDown - Use for continuous input (movement)

  5. IsKeyPressed - Use for single actions (fire, menu selection)

IsKeyDown vs IsKeyPressed

IsKeyDown - Returns True while key is physically held:

{ Player moves continuously while W is held }
if IsKeyDown(Key_W) then
  PlayerY := PlayerY - 1;

IsKeyPressed - Returns True once per key press (edge detection):

{ Fire weapon once per Space press }
if IsKeyPressed(Key_Space) then
  FireWeapon;

Notes

  • Direct hardware access (no BIOS delays)

  • Supports multiple simultaneous keys (perfect for games)

  • Triggers on key release (ensures no quick taps missed)

  • CharMapNormal/CharMapShift for ASCII conversion

  • Install ExitProc handler to call DoneKeyboard on Ctrl+C