danos/library/xkeyboard-config/README.md

3.2 KiB
Raw Blame History

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
  • fetch downloads the pinned xkeyboard-config release (version + sha256 in the script), resolves the include graph for the configured layouts, and vendors only the symbols files actually reached (plus keysymdef.h, COPYING, and PROVENANCE.md) into vendor/. Run it when bumping the version or adding a layout.
  • generate is deterministic and offline — same vendored input produces byte-identical output. To add a layout, extend TARGETS (and HID_TO_NAME if a new physical key is involved), then re-run fetch (to vendor any new includes) and generate.

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 TARGETS as 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.