NKLegacy implements a PS/2 keyboard driver that handles IRQ 1 (INTDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/pastaboy12345/NKLegacy/llms.txt
Use this file to discover all available pages before exploring further.
0x21), reads scancodes from port 0x60, translates them using a Scancode Set 1 lookup table, and stores the resulting ASCII characters in a 256-byte circular buffer for consumption by the shell. The driver is interrupt-driven: every keypress fires the keyboard_callback ISR, which translates and buffers the character without any polling overhead in the main loop.
API Reference
void keyboard_init(void)
Registers the keyboard IRQ handler by calling idt_register_handler(33, keyboard_callback), hooking INT 0x21 (IRQ 1) to the internal scancode handler. No hardware reset or port initialization is performed — the PS/2 controller is left in its power-on state.
pic_init() (so IRQ vectors are remapped to 0x20–0x2F) and before sti is executed.
char keyboard_getchar(void)
Non-blocking read from the internal circular key buffer. Returns the oldest buffered ASCII character if one is available, otherwise returns 0 immediately.
The buffer holds up to 255 characters (KB_BUF_SIZE = 256, with one slot reserved to distinguish empty from full). If the buffer overflows (i.e., the shell is not draining it fast enough), new characters are silently dropped in the ISR.
keyboard_getchar is non-blocking — it returns 0 immediately when no key is pending. Callers must poll it in a loop. The shell in cmd.c uses __asm__ volatile("pause") between poll iterations to reduce CPU contention and give the CPU a hint that it is in a spin-wait loop.Scancode Set 1
The PC keyboard reports key events as scancodes on I/O port0x60. NKLegacy uses Scancode Set 1 (the legacy XT set), which all modern PS/2 keyboards emulate.
Make/break encoding:
- Make code (key down): value is less than
0x80. The scancode is used as an index into thescancode_asciiorscancode_ascii_shiftlookup table. - Break code (key up): value has bit 7 set — i.e.,
scancode = make_code | 0x80. The driver checksscancode & 0x80and discards break codes (except for shift key tracking).
Shift Key Support
The driver maintains ashift_held flag:
- Left Shift press (
0x2A) and Right Shift press (0x36) setshift_held = 1. - Left Shift release (
0xAA) and Right Shift release (0xB6) clearshift_held = 0. - When
shift_heldis non-zero thescancode_ascii_shifttable is used instead ofscancode_ascii, producing uppercase letters and shifted symbols (!@#$%^&*etc.).
Lookup Table Summary
| Key | Unshifted | Shifted |
|---|---|---|
1–9, 0 | 1–9, 0 | !, @, #, $, %, ^, &, *, (, ) |
- | - | _ |
= | = | + |
[, ] | [, ] | {, } |
; | ; | : |
' | ' | " |
` | ` | ~ |
\ | \ | | |
,, ., / | ,, ., / | <, >, ? |
| Letters | Lowercase | Uppercase |
| Space | | |
| Enter | \n | \n |
| Backspace | \b | \b |
| Tab | \t | \t |
| Escape | 0x1B | 0x1B |
| F1–F12, Numlock, Scroll Lock, Caps Lock | 0 (ignored) | 0 (ignored) |
Shell Integration
The shell loop incmd.c polls keyboard_getchar() on every iteration and falls back to serial_getchar(COM1) if no PS/2 key is available. This allows the same shell to accept input from both input sources simultaneously:
vga_putchar('\b') + vga_putchar(' ') + vga_putchar('\b') to erase the character visually on screen (move back, overwrite with space, move back again).