Skip to content

Keyboard Reading

Read the ZX Spectrum keyboard matrix by polling I/O ports. Simple, efficient, and no ROM routines required.

Taught in Game 1, Unit 1 keyboardinputz80ports

Overview

Read keyboard input by polling the I/O ports directly. The Spectrum’s keyboard is arranged in a matrix of 8 rows, each accessible via a specific port address. Keys are active low (0 = pressed). Use when you need responsive input without relying on the ROM.

Code

; =============================================================================
; KEYBOARD READING - ZX SPECTRUM
; Read keyboard matrix via I/O ports
; Taught: Game 1 (Ink War), Unit 1
; CPU: ~50 cycles | Memory: ~40 bytes
; =============================================================================

KEY_PORT    equ     $fe

; Keyboard row addresses (active low)
ROW_QAOP    equ     $fb             ; Q W E R T (bits: T R E W Q)
ROW_ASDF    equ     $fd             ; A S D F G (bits: G F D S A)
ROW_YUIOP   equ     $df             ; Y U I O P (bits: P O I U Y)
ROW_12345   equ     $f7             ; 1 2 3 4 5 (bits: 5 4 3 2 1)
ROW_09876   equ     $ef             ; 0 9 8 7 6 (bits: 6 7 8 9 0)
ROW_SPACE   equ     $7f             ; Space, Sym, M, N, B

; Read keyboard and return direction code
; Returns: A = 0 (none), 1 (up), 2 (down), 3 (left), 4 (right)
read_keyboard:
    xor     a
    ld      (key_pressed), a    ; Clear previous

    ; Check Q (up)
    ld      a, ROW_QAOP
    in      a, (KEY_PORT)
    bit     0, a                ; Q is bit 0
    jr      nz, .not_q
    ld      a, 1
    ld      (key_pressed), a
    ret
.not_q:
    ; Check A (down)
    ld      a, ROW_ASDF
    in      a, (KEY_PORT)
    bit     0, a                ; A is bit 0
    jr      nz, .not_a
    ld      a, 2
    ld      (key_pressed), a
    ret
.not_a:
    ; Check O (left)
    ld      a, ROW_YUIOP
    in      a, (KEY_PORT)
    bit     1, a                ; O is bit 1
    jr      nz, .not_o
    ld      a, 3
    ld      (key_pressed), a
    ret
.not_o:
    ; Check P (right)
    ld      a, ROW_YUIOP
    in      a, (KEY_PORT)
    bit     0, a                ; P is bit 0
    jr      nz, .not_p
    ld      a, 4
    ld      (key_pressed), a
.not_p:
    ret

key_pressed:
    defb    0

Usage:

main_loop:
    halt                        ; Wait for frame
    call    read_keyboard
    ld      a, (key_pressed)
    or      a
    jr      z, main_loop        ; No key pressed

    cp      1
    jr      z, handle_up
    cp      2
    jr      z, handle_down
    ; ... etc
    jr      main_loop

Trade-offs

AspectCost
CPU~50 cycles per read
Memory~40 bytes
LimitationNo debouncing (keys may auto-repeat)

When to use: Any game needing keyboard input. ROM-free approach works on all Spectrums.

When to avoid: When you need debounced input for menus or single-press detection.

Keyboard Matrix Reference

PortBit 0Bit 1Bit 2Bit 3Bit 4
$F712345
$EF09876
$FBQWERT
$FDASDFG
$DFPOIUY
$BFEnterLKJH
$7FSpaceSymMNB
$FEShiftZXCV

Patterns: Game Loop (HALT)

Vault: ZX Spectrum