Operating System
Hardware abstraction โ application events
The kernel receives raw device data, translates it through drivers and the HID subsystem, routes it through the window manager to the focused application.
How It Works
When a USB HID report arrives, it triggers a hardware interrupt. The CPU pauses its current work, jumps to the interrupt handler in the kernel, and the OS's HID driver parses the report. For a keyboard, scan codes are mapped to keycodes (hardware-independent key identifiers), then to key symbols (layout-dependent characters). The kernel queues an input event containing the keycode, timestamp, and modifier state.
The window system (Quartz Compositor on macOS, DWM on Windows, Wayland/X11 on Linux) determines which window has input focus and delivers the event to that application's event queue. If an input method is active (for CJK composition, dead keys, or the emoji picker), it intercepts the event first, potentially buffering multiple keystrokes into a single character. The accessibility subsystem also hooks in here โ screen readers observe the event stream to announce what's happening.
The Signal Flow
Key Concepts
The CPU's mechanism for handling urgent device events. When a USB device has data, the controller asserts an interrupt line โ the CPU pauses, runs the handler, then resumes. No polling needed.
Three layers of key identity: scan code (hardware-specific), keycode (OS-level, layout-independent), character (what you see โ 'a', 'รฑ', 'ไฝ '). Each mapping is a lookup table.
Only one window receives keyboard input at a time. The window manager tracks which window is focused, and mouse events go to the window under the cursor (or the grabbed window).
Software that composes characters from multiple keystrokes. Essential for CJK languages (Chinese, Japanese, Korean) where thousands of characters must be input from a ~100-key keyboard.
Deep Dive
Interrupt-driven I/O
Modern input is interrupt-driven, not polled. When the USB controller receives a complete HID report, it writes the data to a pre-allocated DMA buffer and raises a hardware interrupt. The CPU vectors to the interrupt handler within microseconds, parses the report, and queues an input event โ all before returning to whatever the CPU was doing. This is why typing feels responsive even when the CPU is loaded: interrupts preempt normal execution.
The Unicode pipeline
Converting a keypress to a character requires traversing the Unicode stack. The OS maps the keycode to a character based on the active keyboard layout (QWERTY, AZERTY, Dvorak). Dead keys (like ยด + e = รฉ) require buffering. CJK input methods convert phonetic input into candidate characters using dictionaries. The final output is a Unicode code point โ a number like U+0041 (A) or U+4F60 (ไฝ ) โ which is encoded as UTF-8 (the web's universal encoding) or UTF-16 (Windows internals) for further processing.