Skip to content

Verilog platform: keycode delivers browser keyCode not ASCII; shift state lost for digit-row keys #241

@VinCBR900

Description

@VinCBR900

Verilog platform: keycode delivers browser keyCode not ASCII; shift state lost for digit-row keys

Summary

The documentation states:

keycode is an 8-bit value with the high bit set when a key is pressed.

This implies the low 7 bits are ASCII. In practice they are the raw browser keyCode, which differs from ASCII for all punctuation keys and loses shift state entirely for digit-row keys. This makes several characters essential to keyboard-input designs (including ( ) * % ") unreachable.

Root cause

From src/platform/verilog.ts:

poller = setKeyboardFromMap(video, switches, VERILOG_KEYCODE_MAP, (o, key, code, flags) => {
  if (flags & KeyFlags.KeyDown) {
    keycode = code | 0x80;   // <-- code is browser keyCode, not charCode
  }
}, true);

code is the browser KeyboardEvent.keyCode. This causes two distinct problems:

Problem 1 — Shift state lost for digit-row keys

Browser keyCode is identical for a digit key whether or not Shift is held. shift+9 and 9 both produce keyCode = 57. The shifted character ( is
unreachable.

Problem 2 — Punctuation keyCode ≠ ASCII

Punctuation keys have keyCode values ≥ 128 that happen to have bit 7 already set, so keyCode | 0x80 == keyCode. After the typical AND #$7F used in Apple 1 / PIA designs, the result is incorrect:

Key typed keyCode keyCode|0x80 after AND #$7F Expected ASCII
- 189 (0xBD) 0xBD 0x3D = 0x2D -
= 187 (0xBB) 0xBB 0x3B ; 0x3D =
' 222 (0xDE) 0xDE 0x5E ^ 0x27 '
; 186 (0xBA) 0xBA 0x3A : 0x3B ;
/ 191 (0xBF) 0xBF 0x3F ? 0x2F /
, 188 (0xBC) 0xBC 0x3C < 0x2C ,
. 190 (0xBE) 0xBE 0x3E > 0x2E .
shift+9 57 (0x39) 0xB9 0x39 9 0x28 ( ✗ (shift lost)
shift+0 48 (0x30) 0xB0 0x30 0 0x29 ) ✗ (shift lost)
shift+= 187 (0xBB) 0xBB 0x3B ; 0x2B + ✗ (shift lost)
shift+' 222 (0xDE) 0xDE 0x5E ^ 0x22 " ✗ (shift lost)

What does work correctly:

  • Letters A–Z (keyCode 65–90 = ASCII, uppercase only — acceptable)
  • Digits 0–9 (keyCode 48–57 = ASCII ✓)
  • Enter / CR (keyCode 13 ✓), Backspace / BS (keyCode 8 ✓)
  • shift+,<, shift+.>, shift+/?, shift+;: — these
    work by coincidence because keyCode & 0x7F happens to equal the ASCII value of the shifted character

Reproducer

A minimal Verilog testbench echoes every keypress directly to a text terminal (no CPU, no memory, no address decoding) is attached

kbd_echo_test.v.txt

Load it in the IDE, open CRT view, and type punctuation and shift+digit keys and observe displayed characters.

Suggested fix

Replace event.keyCode with event.key (the printable character string) in the keyboard handler. event.key is shift-aware and returns the actual character for printable keys ("(", "+", "\"" etc.), falling back to named strings ("Enter", "Backspace", "ArrowLeft") for non-printable keys.

// current (incorrect for punctuation and shift+digit):
keycode = code | 0x80;   // code = browser keyCode
 
// suggested:
// use event.key.length==1 for printable chars -> charCodeAt(0) | 0x80
// use event.keyCode for non-printable (Enter, BS, arrows etc.)

This would make keycode & 0x7F reliably equal to the ASCII value of the character the user visually typed, on any keyboard layout, including shifted chars.

Impact

Affects any Verilog design that uses keycode for text input — Apple 1 clones, terminal emulators, BASIC interpreters, etc. The built-in cpu6502.v preset is one example; the mango_one Apple 1 fork is another.

A documentation update is needed regardless: clarify that the low 7 bits are keyCode, not ASCII, to determien if translation needed in Verilog.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions