66 lines
3.2 KiB
Markdown
66 lines
3.2 KiB
Markdown
# xkeyboard-config — X11 keyboard layouts, compiled to Zig
|
||
|
||
This module turns a physical key (a **USB HID usage**, as the [input module](../../docs/device-driver-development/input.md)
|
||
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](https://gitlab.freedesktop.org/xkeyboard-config/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
|
||
|
||
```zig
|
||
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
|
||
|
||
```sh
|
||
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.
|