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
InitKeyboard - MUST call before using any functions
DoneKeyboard - MUST call before exit (unhooks INT 9h)
ClearKeyPressed - MUST call at END of every game loop
IsKeyDown - Use for continuous input (movement)
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