Skip to content

Add a Glyph Script

Firmware protocol v10+ open-ended glyph-script index

A glyph script restyles the keycap letter and digit legends in an alternative script — Tengwar, runes, Braille and friends (see Glyph Scripts for the user-facing side). This HowTo adds a new one.

The best part: since firmware protocol v10 the glyph-script index is open-ended. The firmware accepts any script byte and simply draws the normal legend for one it doesn’t know, so adding a script does not bump the protocol — you add an enum value, a codepoint block, a font, and a host label. A keyboard that lacks the new font degrades gracefully to Latin.

All firmware paths are relative to keyboards/polykybd/ in the qmk_firmware fork; the glyphs ship in the fantasy font-pack bundle (see Font Packs & Resources).

How it works

Each script’s letters and digits are rendered into a dense private codepoint block (0x40 apart: Tengwar 0xE800, Runes 0xE840, …). A table in poly_keymap.c (glyph_script_blocks[], indexed by the poly_glyph_script enum) maps a script to its block base; letters a..z land at base+0..25, and scripts with their own numerals put digits at base+26..35. The render hook in render_key() swaps the legend for the block glyph when a script is active.

Steps

  1. Pick a license-clean font. The glyph shapes must be embeddable and redistributable (OFL, Apache, CC0, permissive). Keep user-facing script names generic where a script is a trademark, even though the fonts themselves are fine to embed. Add the source to the font downloader (fonts/dl-fonts.sh).

  2. Add the enum value. Append to enum poly_glyph_script in state.h — it is append-only and byte-identical to the host’s GlyphScript enum. Add a matching row to glyph_script_blocks[] in poly_keymap.c with the next free 0x40-spaced block base.

  3. Generate the font into its block. Add a fonts.yaml entry that emits the font at the new PUA block using fontconvert’s sequence remap, so a..z (and digits, if the script has them) land at base+0... Regenerate the headers, then rebuild the fantasy bundle and bump its content_version so the host re-flashes it on connect.

  4. Wire the host. In PolyKybdHost: add the same value to the GlyphScript enum (command_ids.py) and a label to GLYPH_SCRIPT_LABELS (host.py). That automatically adds it to the tray Glyph Script submenu and the polyctl glyph-script <name> choices — see the Command Line page.

  5. Reship the bundle. Copy the regenerated fantasy.plyf into polyhost/res/fontpack/ and update bundles.json with the new size, hash and version so the host ships the new glyphs and re-flashes them on the next connect. If the category headers are already committed you don’t even need fontconvert — the bundle derives from them deterministically.

  6. Build and test. Compile the firmware and select the new script from the tray menu or polyctl. With the fantasy bundle flashed the legends switch; without it, they stay Latin. The test rig has a min_protocol-gated round-trip test you can extend.

See Contributing for how to open the pull requests, and the HID Protocol Reference for the GLYPH_SCRIPT command.