Skip to content

Keyboard

Spec hygiene (canonical-spec.md rule 1). This document does not restate canonical values (key count, layout family, switch ecosystem, controller part, accelerometer host). Those live in the Canonical Hardware Specification — Keys + Accelerometer rows. Any value inline that contradicts canonical-spec.md is a bug — fix it there, then here.


The KN-86’s input subsystem is a stock Ferris Sweep (David Barr design) sourced from holykeebs as a Soldered kit, with 2× trackpoint pointing devices (one per index finger) and the LIS3DH accelerometer hosted on the master half. It connects internally to the Pi Zero 2 W as a single USB HID device through the internal USB hub.

For the canonical key count, layout family, switch ecosystem, controller part, and accelerometer host, see Canonical Hardware Specification — Keys + Accelerometer rows. The decisions behind this build live in ADR-0031 (Sweep adoption, layout, split topology) and ADR-0032 (2× trackpoint, LIS3DH I²C re-pin, permanent OLED skip).

Why the Sweep over a custom-fabricated board: a shipping community split keyboard satisfies the KN-86’s input spec as commodity parts and removes the entire custom-PCB fab/plate/debounce risk surface. The full rationale + options-considered analysis is in ADR-0031 Context + Options Considered; the corpus-level argument is in synthesis §2 (L7) and §4.

The TERM key is context-sensitive — default function is the terminal surface, with CIPHER-LINE seed-capture and additional contextual bindings overlaid per surface. The keyboard delivers the raw TERM scancode; nOSh resolves the binding (ADR-0016 §9, software/runtime/input-dispatch.md). TERM lives on the right outer thumb (RT1) per ADR-0031 §3.1.


The worked-out 34-key base layer — which canonical function lands on which physical Sweep position, with per-key placement rationale, the SHIFT layer, and the Nokia multi-tap letter map — is in synthesis §4.2–§4.5 and ratified in ADR-0031 §3.1 (the authoritative QMK layer manifest with per-key QMK→KN-86 keycode mapping). Do not restate the grid here — those two documents are the source of truth; reproduce them, do not redraw.

Summary of the logical mapping (positions defined in ADR-0031 §3.1):

  • LEFT half carries the 14 Lisp primitives function block (legends per ADR-0022 §1: NIL / INFO / LAMBDA-printed-FN / CONS / LINK on top; APPLY / BACK / CDR / CAR / QUOTE on home — pinky→index inner reach, per the ADR-0031 §3.1 2026-06-21 home-row revision: CAR/CDR are the index+middle rest-and-rock pair, each nav verb on its own finger; SYS / EQ / ATOM on bottom plus 2 reserved-for-v2 spares), with EVAL on the inner-thumb (LT0) and LSHIFT on the outer-thumb (LT1).
  • RIGHT half carries the digit 3×3 (1-2-3 top, 4-5-6 home, 7-8-9 bottom on the inner three columns) preserving the Nokia digit-to-letter binding (2=ABC … 9=WXYZ) from ADR-0016 §6, plus , . / ; - punctuation primaries and ENT on the outer two columns, with 0 on the inner-thumb (RT0) and TERM on the outer-thumb (RT1).
  • SHIFT layer (LSHIFT held, QMK MO(L1)) delivers the shift secondaries — full ASCII printable set per ADR-0031 §3.1 / synthesis §4.4.

Decisions closed by the layout (all per ADR-0031):

  • Shift gesture closed — LSHIFT is a physical thumb key held as a momentary modifier (MO(L1)); no long-press timing tax, no chord. Closes ADR-0022 §Known Unknowns #1 (ADR-0031 §3.2).
  • delete rebound — in :nemacs-literal / :prompt-text scopes, delete moves from the old * binding to BACK (L12). case-toggle stays on / (R01). The context-polymorphism contract from ADR-0016 §3 + ADR-0022 §7 is preserved; the active scope label on Row 24 + CIPHER-LINE Row 1 advertises the live behavior (ADR-0031 §3.3).
  • Phone-shape topology relaxes; digit-to-letter binding survives — the literal 16-key phone numpad is gone, but the 1-9 digit 3×3 preserves the spatial relationship and the Nokia muscle memory (the binding that mattered) is intact (ADR-0031 §3.1, synthesis §4.6). Copy must say “phone-style digit-to-letter mapping,” not “phone-style numpad.”

Per ADR-0031 §2:

PropertyValue
HalvesTwo: LEFT (master) + RIGHT (slave). Each carries one KB2040 + 17 hotswap switch positions (15 main + 2 thumb) + one trackpoint.
Inter-half linkTRRS cable per Sweep convention. QMK split-keyboard serial transport carries matrix + pointing events from slave to master over the TRRS data line (typically GPIO1, fixed by the Sweep PCB).
Master = LEFTConvention from QMK split keyboards (Corne, Sweep, Lily58). The LIS3DH lives on master; the EVAL commit verb (LT0) lives on master — concentrating the keys nOSh dispatch cares about most on the master half avoids inter-half-RTT latency on EVAL.
USB to PiMaster half’s KB2040 USB-C → internal USB hub IC (ADR-0018 §5) → Pi Zero 2 W OTG. Single USB HID interface from Linux’s perspective.
Slave USB-CUsed only for flashing the slave KB2040 — not connected to the Pi during operation. The operator uses the master’s USB-C path for all normal use.
Matrix wiringFixed by the Sweep PCB. We do not author the matrix layout; we author the QMK keymap on top of the PCB’s matrix.

From QMK’s perspective the two physical halves are one logical keyboard: a single keymap source (LAYOUT_split_3x5_2(...)) covers all 34 keys, with master/slave handoff handled by the QMK split-keyboard subsystem. The device is not a split-ergo from the operator’s perspective in spirit — both halves seat into a unified 3D-printed bezel inside the Pelican 1170 shell — but the topology is an honest split (two halves, two MCUs, TRRS), not a split-PCB pretending to be unified.


Per ADR-0032 §1:

  • 2× holykeebs trackpoint modules — Sprintek SK8707-01 sensor + adapter PCB + red rubber cap, one per half, mounted between the alpha keys under each operator index finger. Operator-facing capability description in trackpoint-module.md.
  • Driver: stock QMK PS/2-mouse driver (pointing_device_driver = ps2_mouse), compiled for both halves; each half drives its own trackpoint over the PS/2 protocol on its KB2040’s D4/D5 pins (see Pin assignment below).
  • One cursor: the slave’s pointer events flow to the master over the TRRS link via QMK’s split-keyboard pointing-device transport; the master emits them on its USB HID interface alongside its own trackpoint events. From the Pi’s perspective there is one mouse cursor — either index finger can drive it. No second USB device, no separate evdev node beyond the standard mouse interface.
  • Click semantics (interim): QMK PS/2-mouse stock tap-vs-drag threshold (press-and-release the stem within ~150 ms → click; longer → drag). Final gesture deferred to firmware bring-up. Hard constraint: none of the four canonical thumb keys (LT0 EVAL, LT1 LSHIFT, RT0 0, RT1 TERM) is reassigned to mouse-click — click comes from the stem itself or a chord that sacrifices none of the four. Button #1 (primary) only in v0.1; right/middle-click deferred to v0.2.
  • cart-FFI: pointer state exposure to cart Lisp was deferred in ADR-0032 §5 and then opened in v0.1 by ADR-0035cursor-position, on-trackpoint-move, on-trackpoint-click, cursor-visible! land in the nOSh FFI surface (ADR-0005 Tier 1). The cursor is exposed in cell coordinates on the main 80×25 grid, clamped to content rows 1–23.
  • Soldering note: the trackpoint daughterboard is a delicate one-shot solder onto the KB2040 underside (“after this soldering it’ll become extremely hard to separate the two PCBs” — holykeebs). The order carries 1× spare KB2040 as build insurance and 4–6 spare red caps (caps wear faster than sensors). The trackpoint must be installed before the keyboard PCB is screwed into the case — the stem protrudes through the keyplate and alignment depends on case fit.

The LIS3DH lives on the master (LEFT) half’s KB2040 only, on I²C1 (KB2040 silkscreen D6/D7, RP2040 GP6/GP7) per ADR-0032 §3 — moved from the original I²C0 (D4/D5) assignment because the trackpoint’s PS/2 adapter now consumes D4/D5 on both halves. The INT1 line (originally reserved on D6) is released — v1 LIS3DH is polling-only at 25 Hz ODR.

For the sensor part, range, ODR, axis convention, motion-classification model, and the ambient CRT-glitch system it drives, see Canonical Hardware Specification — Accelerometer row, and ADR-0023.

Why master-half only: the sensor reports motion events to nOSh via a vendor-defined HID report on the master’s USB HID interface (ADR-0023 §6). Hosting it on the slave would force either routing motion events over TRRS (latency + bandwidth cost against ≤300 ms gesture windows) or enumerating the slave on the hub (breaking the single-USB-HID-interface invariant). One sensor on master is sufficient for the 4-bucket motion classification — the Pelican 1170 shell rigidly couples both halves’ inset-panel mounts, so a case-jostle propagates equally to both halves (ADR-0031 §5, ADR-0032 §3).


The Sweep PCB has an optional 128×32 SSD1306 mount slot. v0.x ships without it, permanently (ADR-0032 §2). The OLED mount and the trackpoint mount are mutually exclusive on the Sweep, and trackpoint wins on both halves. The CIPHER-LINE 256×64 SSD1322 (ADR-0015) is the authoritative — and only — auxiliary display; it covers status / modeline / palette / echo at higher fidelity than the Sweep’s small SSD1306 would. Re-introducing the Sweep OLED in any future revision requires a new ADR (ADR-0032 §2).


Build pattern per ADR-0018 §1 (commodity parts) + ADR-0031 §1 (Sweep specifics):

ElementChoiceNotes
PCBholykeebs Ferris Sweep pair, current hotswap revision (hotswap sockets + 1N4148 SMD diodes pre-populated)The modified-diode revision frees SDA/SCL from the matrix scan, which the trackpoint requires — already the holykeebs default.
Build tierSoldered kitSMD components pre-populated; switch-socket population + plate / case assembly remain ours.
Controllers2× Adafruit KB2040 (RP2040, USB-C, Pro Micro form factor) on custom low-profile 5 mm headersOne per half. Sea-Picro is the named fallback (ADR-0024). Order 1× spare KB2040 for trackpoint-solder insurance (ADR-0032 §1).
SwitchesKailh Choc v1, hot-swapSpecific switch family TBD via hotswap iteration; bring-up suggestion: Choc v1 brown (tactile, neutral).
Key spacingChoc 18 × 17 mmNot MX 19 × 19.
KeycapsMBK low-profile (canonical)Sculpted Choc documented as an operator-swap alternative, not v0.1 canonical.
Trackpoint2× holykeebs SK8707-01 module + red capOne per half. See Pointing section above.
OLEDSkipped (permanent for v0.x)See Sweep OLED section above.
Plates / caseSlim low-profile plate stack; 3D-printed case color-matched to the Pelican-1170 cyberdeck aestheticSpecific stack confirmed at order time. ferris-sweep-v2-case.md is the current candidate case STL.
TRRS cableIncluded in base kitInter-half link.

The full configured BOM checklist (every holykeebs order axis with the decided choice) is in holykeebs-buyers-guide.md §“KN-86 BOM checklist.” Confirm at order time that the shipped PCB is the hotswap (modified-diode) revision, not the older solder-direct revision.


Authoritative table in ADR-0032 §3 (which amends ADR-0031 §3). Matrix rows / cols / TRRS data are fixed by the Sweep PCB and not authored here; the KN-86-authored peripheral pins are:

HalfFunctionKB2040 silkscreenRP2040 pinNotes
LEFT (master)Trackpoint PS/2 clockD4 (silk: SDA)GP4PS/2 clock over the holykeebs adapter — not I²C SDA in this configuration.
LEFT (master)Trackpoint PS/2 dataD5 (silk: SCL)GP5PS/2 data over the holykeebs adapter — not I²C SCL.
LEFT (master)LIS3DH SDAD6GP6I²C1 SDA — moved from I²C0 (D4/D5) by ADR-0032 §3.
LEFT (master)LIS3DH SCLD7GP7I²C1 SCL — moved from I²C0 (D4/D5) by ADR-0032 §3.
LEFT (master)LIS3DH INT1(released)(released)Reservation released by ADR-0032 §3 — v1 is polling-only. v2 interrupt-driven motion would re-allocate (D8/GP8 is free).
LEFT (master)USB to PiUSB-CMaster is the USB host endpoint → internal hub → Pi.
RIGHT (slave)Trackpoint PS/2 clockD4 (silk: SDA)GP4Same pinout as master.
RIGHT (slave)Trackpoint PS/2 dataD5 (silk: SCL)GP5Same pinout as master.
RIGHT (slave)USB-CUSB-CFlashing only; not connected to the Pi in operation.
BothSWDSWCLK / SWDIOTest pads on the KB2040 PCB underside.

USB HID over USB 2.0 to the Pi via the internal USB hub IC (TUSB2036 / FE1.1s on the interior plate — see processor.md and ADR-0018 §5). The hub fans the Pi’s single OTG port out to the master KB2040 and the cartridge bridge IC (cartridge-interface.md). No externally routed USB cables.

SignalFromToNotes
USB upstreamMaster KB2040 (LEFT half)Internal USB hub downstream portShort USB pigtail.
USB upstreamInternal hub upstreamPi Zero 2 W OTGWired pigtail, no external cable.
TRRSSlave KB2040 (RIGHT half)Master KB2040 (LEFT half)QMK split-keyboard serial transport — matrix + pointing events from slave to master.

The Pi reads HID events via standard Linux evdev (/dev/input/event*) for the keyboard interface and the standard mouse interface for the merged trackpoint cursor. nOSh parses the keyboard events into the logical key model in software/runtime/input-dispatch.md.

Unchanged from the pre-Sweep build spec:

  1. GPIO header pin starvation against I2S and future peripherals.
  2. Userspace debounce / key-repeat / hold-detection already solved in stock QMK.
  3. Latency under Linux scheduling is bounded by USB enumeration, not by userspace scan loops.
  4. The mech-keeb ecosystem has solved every problem in our spec as commodity parts — the Sweep adoption (ADR-0031) takes this argument to its conclusion: PCB, hotswap, split topology, QMK firmware, HID enumeration, trackpoint integration, and keymap authoring all come from the community.

ADR-0011 “early-boot key-scan timing”: the attention gesture (SYS+LINK held at boot) cannot be detected by an early-boot GPIO scan because the keys are USB HID. The system-image-update gate waits for USB enumeration before scanning. Unaffected by the split topology — Linux still sees one keyboard interface.


QMK keymap source lives at firmware/kn86-keyboard/. Per ADR-0031 §4 + §F3 and ADR-0032 §4:

FileRole
keymap.cThe 34-key LAYOUT_split_3x5_2(...) keymap with the L0 BASE + L1 SHIFT layer manifest per ADR-0031 §3.1. Retargeted from the legacy handwired 31-key keymap.
config.hTrackpoint pin map (D4/D5 PS/2 per half), LIS3DH I²C1 init (D6/D7), QMK matrix dimensions, debounce, USB descriptor strings, NKRO toggle.
rules.mkMCU = rp2040, BOOTLOADER = rp2040, split-keyboard enable, pointing_device_driver = ps2_mouse, LIS3DH driver enable.
README.mdPer-file roles + the keyboards/handwired/kn86keyboards/ferris/sweep retarget note.
  • Target tree: keyboards/ferris/sweep (existing QMK community keyboard). Master/slave handoff via the QMK split-keyboard subsystem on the serial driver.
  • MCU / bootloader: rp2040 (both halves); drag-drop UF2 to the BOOTSEL volume.
  • USB: native RP2040 hardware Full Speed on master only; slave USB-C is flash-only.
  • Trackpoint: stock QMK PS/2-mouse driver on both halves; pointing events merged to one cursor over TRRS (ADR-0032 §4).
  • LIS3DH: unchanged driver behavior from ADR-0023 §5, re-pinned to I²C1; runs on master only; vendor HID report on the master’s USB HID interface.

The 34-key Sweep keymap.c rewrite + the QMK keyboard.json selection are tracked as ADR-0031 §F3 (keymap retarget) and ADR-0032 §F3 (trackpoint driver + LIS3DH I²C1 init), owned by Platform Engineering, blocked on the holykeebs hardware arriving.

Keyboard firmware stays dumb for the logical key surface: it delivers raw key-down / key-up events. LAMBDA hold, QUOTE bookmark slots, SYS hold abort, TERM context dispatch, hold detection, and macro replay remain nOSh-owned (ADR-0018 §6 doctrine, preserved). Two QMK firmware features are now used (where v0.1 previously used none): the SHIFT momentary layer (MO(L1), ADR-0031 §3.1) and the PS/2-mouse pointing-device driver (ADR-0032 §4) — both are stock QMK, authorized by their respective ADRs.


Both KB2040 controllers draw from USB bus power (5 V from the internal hub, regulated to 3.3 V on each controller); the slave is powered over the TRRS link from the master. No separate rail. The 2× trackpoint adds ~6.5 mA active / ~1.8 mA idle and the LIS3DH ~0.1 mA — within bring-up measurement noise against the CLAUDE.md Battery row envelope (ADR-0032 §6). Power topology lives in power.md.


Both Sweep halves seat into a 3D-printed bezel insert in the Pelican 1170 inset panel, above the primary display and the CIPHER-LINE OLED. The Pelican shell itself is not modified. Per ADR-0031 §Consequences + ADR-0032 §7, the bezel insert grows from the prior single-keyplate aperture to:

  • Two keyplate apertures (one per half),
  • A TRRS-cable pass-through between them,
  • 2× cutouts for the trackpoint stems to protrude through the keyplate between the alpha keys.

Bezel-insert re-design is tracked as ADR-0031 §F4 + ADR-0032 §F2 (Hardware-owned), designable in parallel from the holykeebs PCB dimensions + the Sprintek SK8707-01 datasheet. See enclosure.md.


Per ADR-0031 §F7 + ADR-0032 §F5, and Stage 3 in build-specification.md §4:

  1. Receive the holykeebs Soldered kit (2× Sweep halves, 2× KB2040, 2× trackpoint module, TRRS cable) + spares.
  2. Solder each trackpoint daughterboard onto its KB2040 underside (one-shot — use the spare KB2040 to absorb a failed join). Install the LIS3DH on the master half per §F2 (reflow on the Soldered-kit pass if holykeebs can, else ADA-2809 breakout on flying-lead I²C1).
  3. Flash stock QMK with the 34-key Sweep keymap.c per ADR-0031 §3.1 + the trackpoint/LIS3DH config per ADR-0032 §3–§4.
  4. Install Choc v1 switches in the hotswap sockets; install MBK keycaps (blank in v0.1).
  5. Mount the internal USB hub IC; wire master USB-C → hub downstream, hub upstream → Pi OTG. Connect the TRRS link between halves.
  6. Validate:
    • Both halves enumerate over TRRS as one logical keyboard; all 34 positions report unique scancodes (xxd /dev/input/event* / QMK tester).
    • Both trackpoints contribute to one cursor; click works (evtest).
    • LIS3DH is found on master I²C1; vendor HID report emits on /dev/hidraw*; the ambient CRT-glitch system drives correctly.

The configured order BOM is the holykeebs-buyers-guide.md §“KN-86 BOM checklist.” Order line items, decided:

  • Ferris Sweep PCB pair — black, current hotswap revision (hotswap sockets + 1N4148 SMD diodes pre-populated).
  • Build tier — Soldered kit.
  • 2× Adafruit KB2040 (~$8.95 ea) + 1× spare KB2040 (trackpoint-solder insurance). Sea-Picro named fallback.
  • 2× holykeebs trackpoint module (SK8707-01 + adapter PCB + red cap) — one per half + 4–6 spare red caps.
  • Controller mounting — custom low-profile 5 mm headers (saves 2.5 mm of internal stack height vs 7.5 mm machine headers).
  • Switches — Kailh Choc v1 hotswap (family TBD; bring-up suggestion Choc v1 brown).
  • Key spacing — Choc 18 × 17 mm.
  • Keycaps — MBK low-profile.
  • OLED — skip (permanent v0.x).
  • TRRS cable — included in base kit.
  • Plates / case — slim low-profile stack + 3D-printed case (or our own color-matched STL).
  • Internal USB 2.0 hub IC (TUSB2036 / FE1.1s / equivalent) + passives, and a short USB pigtail master → hub.

Suppliers: holykeebs (Sweep Soldered kit + trackpoint modules — one-stop), Adafruit / Amazon / AliExpress (spare KB2040, hub IC). The cross-references and trade-off notes for each axis are in holykeebs-buyers-guide.md. The custom-fab keyboard-PCB line from the prior build is retired — the Sweep PCB is fabricated by holykeebs.