open-standards/aac/spec/keyboard.md
Transaction Science 3a4c8f25eb fix(aac-core, aac-web): the keyboard review — letter names by ear, standard layouts, keys that keep their size
The alphabet by ear
- Says each letter by its name (keyboard/letter_names.json), never the bare
  key a voice reads as a word, and the app's own words in the language. The
  names are data with a review: drafted, checked by an independent
  back-reading and a register check, disputes decided and checked again
  (rounds 2-3), then a voice check with espeak-ng
  (tools/keyboard/check_letter_names.py). 43 of 45 languages agreed; Amharic
  (ኸ) and Tagalog (z, v, e) are not, and there it says it is not ready yet.
  The readers were AI models, not native speakers, and the table says so.
- Its own speech path (tts::say_cue): the device voice of the language, no
  text_for_speech, and never over or cancelling the person's words; after
  Speak the next cue waits until the message has been said. It does not
  start without a voice that speaks the language, and says why.
- Offers a letter's marks, a kana's forms and an Ethiopic consonant's orders
  after it; reads a lone suggestion as the word; Stop is in the last group;
  a key reaches it from every keyboard. Each choice records whether a tap
  relayed it; "only my own switch or look" is a setting; a message spelled
  with relayed choices is learned only when the person keeps it (Item::Learn)
  with their own yes. A panel open takes the switch first.

Keyboards
- National layouts from published standards, both layers, read from
  xkeyboard-config (tools/keyboard/build_layouts.py): InScript (IS 13194) for
  the nine Indic languages, Kedmanee (TIS 820-2538) for Thai, CRULP phonetic
  for Urdu; Shift's layer is a page at the same positions.
- Defaults follow the access method (kbd::suggested): most used letters first
  for a switch, colour groups (or alphabetical, large keys) for gaze; a key
  size setting. A Board key leaves text mode. Amharic syllable pages have
  Back. Malayalam signs shown bare (WebKit drew two circles).
- Pinyin: each candidate covers its own letters, ranked by the likeliest
  split (不 + 舒服, not 部署 + 副); ▸▸ pages through them; capitals read as
  the letters; no conversion during a device IME's composition; a failed
  download is said once and retried with back-off; the note says exactly what
  it does.

Access and fit
- With the on-screen keys, the box never takes a switch's Space or Enter, and
  a chosen suggestion no longer moves the focus into it.
- A look must leave a key before it can choose again.
- Keys never shrink below 24 x 32 px: on a phone on its side the box goes
  beside the keys, and the keyboard scrolls with the scan's highlight kept in
  view; the colour frame's text keeps its end in view; the notes fold to a
  line; the colour marks sit on badges with 4.5:1 ink; toggles show in dark
  and high-contrast; dir=auto on the box and what by-ear shows.
- Phrases page: Add to bar and Recent. Unreadable keyboard settings are not
  overwritten at start. First letters keeps where it reads from when text
  mode comes back.

Credits: Settings -> Keyboard lists every word list's source and licence; the
pinyin licence file carries pypinyin's, pinyin-data's, phrase-pinyin-data's
and the Unicode notices in full (the generator pins pypinyin 0.55.0); the
compose table names the Unicode data it comes from. SPEC §12 and
spec/keyboard.md updated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 02:18:26 -04:00

8.2 KiB
Raw Permalink Blame History

AAC sub-spec — Keyboards and alphabet access

Normative refinement of SPEC §12 (proposed — draft for the version after 0.2.0). Reference: aac_core::keyboard::{keyboard, Keyboard, Page, Key, KeyAction, LayoutKind, colour_groups, by_ear, edit, hangul, kana, pinyin}.

1. Keyboard, page, key

A keyboard is a language's letters in one arrangement (LayoutKind: National | Alphabetical | Frequency | ColourGroups): a list of pages, page 0 first. A page is a grid of rows × cols positions, scanned and hit-tested as a board's (SPEC §5); each row is a list of keys whose spans (positions covered, ≥ 1) sum to cols. A key's weight is how wide it is drawn relative to its row; it never changes which position is which. A key carries a label (what it shows), a name (its accessible name and what an auditory cue says) and an action:

Type(text) · Mark(mark) (on the letter before) · Space · Backspace · DeleteWord · Clear · Speak · Shift · Page(n) · Prediction(n) (the n-th word suggestion) · Tool(SentenceHelper | FirstLetters | Phrases) (a control the client provides; without it the key keeps its place, empty) · Blank (a place kept).

2. Pages and what stays in place

  • Row 0 of a letter, numbers or syllable page holds the word suggestions, two positions each. A client that shows another row in its place (a sentence helper's, an abbreviation expander's) MUST keep every other key where it is, and its scan then covers rows 1 onward.
  • Every page of a keyboard has the same cols and the same number of rows, and its bottom rows hold the same controls at the same positions; Space and Backspace, where they are among the letters (alphabetical and frequency layouts), are at the same positions on every page.
  • A letter needing a page of its own (an Ethiopic consonant's orders, a colour group's second look) is on a page marked returns: after a letter there, the keyboard goes back to page 0.
  • A layout's pages MUST be a function of (language, LayoutKind) alone.

3. Arrangements

  • National — the letter rows of a standard physical layout, left to right as on the keys, script_order = false (they keep that order in a right-to-left script). Backspace at the end of the second row and Shift at the start of the third where they fit, as on a physical keyboard; the language's letters the layout reaches another way follow in rows of their own. The reference offers QWERTY, AZERTY, QWERTZ (German, Czech, Hungarian), the Nordic, Turkish Q, ЙЦУКЕН (Russian, Ukrainian), Greek, Hebrew SI-1452, Arabic, Persian ISIRI 9147 and Korean 2-set, and Japanese kana in the gojūon table. From published standards, with both layers (standard_layouts.rs, read from xkeyboard-config): InScript (IS 13194) for Hindi, Marathi, Bengali, Punjabi, Gujarati, Tamil, Telugu, Kannada and Malayalam, Kedmanee (TIS 820-2538) for Thai and CRULP's phonetic layout for Urdu — the layer as typed on page 0, the Shift layer on page 1 at the same positions (⇧ between them; a letter typed on page 1 returns to page 0), a key the language does not use left Blank, the number row only where it holds letters, Backspace at the end of the last row; the alphabet's letters a standard leaves out follow on page 1. Others are alphabetical, with a note saying so.
  • Alphabetical — the alphabet's own order, row by row, then Space and Backspace; an Indic script's consonants and vowel signs come first and its independent vowels on the next page. script_order = true.
  • Frequency — Space, then the letters most written first, placed in order of row-column scan steps: positions sorted by row + col, then by row; Backspace after the eighth letter. The orders are computed from a corpus of each language (the reference: its language packs' word lists, each word's probability times its letters) and fixed in the reference's source. script_order = true.
  • Colour groups — §5.

A language with no letter statistics gets Alphabetical for Frequency; one whose alphabet does not fit the colour frame gets Frequency for ColourGroups; both with a note (Keyboard::notes).

4. Writing systems

Keys type NFC text. edit::type_key composes Hangul jamo into syllables as the 2-set keyboard does (a consonant after a syllable without a final becomes its final; a vowel after a final takes it as its initial; compound vowels and finals combine), and edit::backspace removes one jamo. edit::mark puts a combining mark on the last letter (precomposed where Unicode has the letter: Vietnamese tones, Greek tonos and dialytika, Yoruba tones on vowels and nasals), and fails, changing nothing, when no letter can take it. Mark::KanaCycle steps the kana before it through its plain, small, voiced and half-voiced forms. Shift is a capital for one letter in a cased script (a capital at a sentence start is given by itself, except while first letters reads letters), a doubled consonant in Korean 2-set, and the katakana toggle for kana. Chinese is typed as toneless pinyin (v for ü; capitals read as the same letters); pinyin::Pinyin::convert offers each word the letters start with, ranked by the likeliest split of all the letters it leaves (the cost of a word grows with the log of its rank, plus a constant a word; letters left at the end cost more), each with the letters it stands for — never words the letters only begin unless the language's whole word list was chosen (SPEC §4.2). A client shows them a page at a time, the last place moving to the next page.

5. The colour frame

A 4 × 3 grid: row 0 holds three word suggestions (one look each), and rows 1–3 the frame. Its eight outer places, numbered clockwise from the top left, each have a colour and a mark (the reference: the Okabe–Ito palette, and ● ▲ ■ ◆ ★ ✚ ⬟ ♥, the mark drawn on a badge of its colour with ink of at least 4.5:1 against it, so the shape is told without the colour). The middle shows the text, its end in view, and is Blank (named colour_groups::MIDDLE_NAME). Page 0 (the first look): Space at the bottom middle and, when the alphabet allows, the most written letter at the top middle (one look each); six groups at the other places, in reading order, each listing (holds) its letters by the place each will have. A group's page (the second look): its letters at those places, Back at the bottom middle, its own place Blank. Letters are in alphabetical order across the groups, followed by Delete, Speak and More; More's page holds Clear (Undo just after it), the numbers (a frame of their own, built the same way), the person's phrases, Shift, the alphabet by ear and the way back to the board. An alphabet too large gives up the one-look letter for a seventh group at the top middle; one larger than seven groups hold (CAPACITY) has no colour frame, nor has Amharic (a syllable would need a third look). Korean's compound vowels are typed as two vowels.

6. The alphabet by ear

by_ear::letter_groups(language, n): Space, then the letters most written first, n to a group; then a group of Delete and Speak. ByEar says the word suggestions first (Entry::Words) when there are any, then each group; a yes on a group says its items one at a time, and a yes on an item chooses it, after which the top level starts again. A pass over a group without a yes returns to the top; max_passes whole passes without one pause it until the next yes. After a letter is chosen, then_for gives what it can still become (its marks, a kana's forms, an Ethiopic consonant's orders), offered first (Entry::Then) until the next choice; the last group is Delete, Speak and Stop; after a message spelled with relayed choices, Item::Learn keeps its words, chosen only by the person's own yes. The client says each cue in full, then waits the person's scan rate before the next; a yes is the person's own signal only (SPEC §12, item 7).

What is said comes from letter_names::LetterNames (letter_names.json): for each language, every letter's and sign's name, the marks' names, kana forms' names, and the client's words (space, delete, say it, words, deleted, stop, marks, forms, keep), with a review (status agreed or disputed, the round, the disputed keys). A group is its names joined by the language's comma. ready(language) is true only where the status is agreed.