Turn a keycode + modifiers into a character. The input module delivers HID
usage keycodes but nothing mapped them to characters; rather than hand-maintain
layout tables, vendor the X11 xkeyboard-config database and compile it to native
Zig at build time (no X11 runtime), the way make-initial-ramdisk.py packs the
ramdisk.
- tools/make-xkeyboard-config.py: `fetch` downloads the pinned xkeyboard-config
release (2.44, sha256-verified), resolves the include graph for the configured
layouts, and vendors only the reached symbols files + keysymdef.h + COPYING +
PROVENANCE into library/xkeyboard-config/vendor/. `generate` parses that
(keycodes via a HID->xkb-name table, symbols with include/augment/override and
per-key type, keysymdef for keysym->Unicode) and emits generated/layouts.zig
deterministically.
- library/xkeyboard-config/xkeyboard-config.zig: the API over the generated data
— map(layout, hid_usage, mods) -> { keysym, character }, byName, and the
level-selection semantics (the generated tables stay pure data). Host tests
assert US letters/digits with Shift/Caps, GB £ vs US # on Shift+3, and French
AZERTY q-where-US-has-a — the end-to-end proof of the parse->emit->lookup path.
- build.zig: `xkeyboard-config` + `layouts` modules, the test wired into
`zig build test`, and a `zig build gen-xkeyboard-config` convenience step.
- Layouts: us, gb, de, fr, es, dvorak. Scope (documented): group 1, no dead-key
composition, curated key types. Standalone library; wiring it into the input
path to fill KeyEvent.character is a documented follow-up.
zig build test green (incl. the new keymap tests); regeneration is byte-identical;
full QEMU suite 48/48 (unaffected — no kernel/runtime/service change).
|
||
|---|---|---|
| .. | ||
| generated | ||
| vendor | ||
| README.md | ||
| xkeyboard-config.zig | ||
README.md
xkeyboard-config — X11 keyboard layouts, compiled to Zig
This module turns a physical key (a USB HID usage, as the input module
delivers in KeyEvent.keycode) plus a modifier state into a keysym and, when the key
produces one, a character (a Unicode scalar). It is what lets a keycode become a
character — a keymap — without danos shipping an X11 runtime.
The layout data comes from the X11 xkeyboard-config
database, but it is compiled to native Zig at build time rather than parsed at runtime.
tools/make-xkeyboard-config.py reads the vendored xkb data and emits pure-data tables into
generated/layouts.zig; xkeyboard-config.zig is the hand-written API over them. This is
the same build-time-codegen pattern as tools/make-initial-ramdisk.py.
Using it
const xkb = @import("xkeyboard-config");
const m = xkb.map(xkb.us, key_event.keycode, .{ .shift = shift_held, .caps_lock = caps });
if (m.character) |ch| { /* a printable Unicode scalar */ }
// m.keysym is always set (e.g. an X11 keysym for Return / F1 / a dead key).
const layout = xkb.byName("gb") orelse xkb.us; // choose a layout by name
for (xkb.all) |l| { /* enumerate available layouts */ }
Modifiers carries shift, caps_lock, level3 (AltGr), and control. map selects the
level from the key's XKB type (the generated data) and those modifiers (the policy, in
xkeyboard-config.zig), so data and semantics stay separable.
Layouts: us, gb, de, fr, es, dvorak.
Regenerating
python3 tools/make-xkeyboard-config.py fetch # network: download + vendor the data subset
python3 tools/make-xkeyboard-config.py generate # offline: emit generated/layouts.zig
# or, from the build:
zig build gen-xkeyboard-config
fetchdownloads the pinned xkeyboard-config release (version + sha256 in the script), resolves theincludegraph for the configured layouts, and vendors only the symbols files actually reached (pluskeysymdef.h,COPYING, andPROVENANCE.md) intovendor/. Run it when bumping the version or adding a layout.generateis deterministic and offline — same vendored input produces byte-identical output. To add a layout, extendTARGETS(andHID_TO_NAMEif a new physical key is involved), then re-runfetch(to vendor any new includes) andgenerate.
Scope
A pragmatic subset, enough for real Latin-script typing:
- Group 1 only — no multi-layout group switching.
- No dead-key / compose composition — a dead key returns its keysym with no
character(composing´+e→éis a higher layer's job). - Curated key types — the common XKB types (one/two-level, alphabetic, four-level, …); unmapped keys and unknown types fall back to level-by-shift.
- 6 layouts — extend via
TARGETSas above.
Licensing
xkeyboard-config and keysymdef.h (xorgproto) are MIT/X11 licensed. The vendored data
subset carries the upstream vendor/COPYING, and vendor/PROVENANCE.md records the exact
version, source URL, and sha256. The generated tables are a derived work under the same terms.