Screenreader Common
Shared Go packages for the Cthulhu and Fenrir screen readers. The packages contain reader-independent data and behavior; each reader owns its input, presentation, localization, and operating-system integration.
Emoji catalog
emoji.Categories() returns the bundled emoji picker categories and entries.
It returns independent slices so callers can build and modify their own menus.
Emoji sequences and English labels are catalog data; readers decide how to
translate labels and what to do when an emoji is selected.
Import git.stormux.org/storm/screenreader-common/emoji and call
emoji.Categories() to build a reader-specific picker.
The module targets Go 1.24 or newer and has no external dependencies.
Quick settings
quicksettings.Menu is the quick settings menu shared by both readers:
categories of entries, a remembered position in each category, value stepping
and the spoken announcement. Entries are toggles (checked/unchecked), choices
and numeric ranges. Entries and categories wrap at both ends; ranges stop at
their limits. Readers describe their entries, report current values through a
Host, and apply each changed Result themselves, so each reader keeps its own
settings storage, profiles, persistence and key bindings. Replace reports when
the selected entry disappeared so a reader can refuse to change a different
setting by mistake. MessageIDs lists the menu's own English messages for
translation catalogs.
Both readers store rate, pitch and volume on Speech Dispatcher's -100..100
scale, which the hardware protocol also uses. speechdispatcher.DiscoverQuery
validates module and voice lists, drops repeated voice aliases and keeps
partial results; Discover returns the same data as a Catalog.
AI-assisted contributions
AI-assisted contributions are welcome. The person submitting a contribution must review the diff and test the changed behavior and plausible regressions before submission. Do not submit automatically generated changes without human review. Check the maintained branch and whether the change is still needed before editing. Describe what changed, the tests run, and remaining live reader checks. Leave submission to the contributor after their review and testing.
The shared quick menu and validated discovery API are available starting with v0.5.0. Both readers pin this version for standalone builds.
License
GPL-3.0-or-later. See LICENSE.
Internal UI toolkit
internalui is the single reader-independent toolkit. Form has either
FlatForm (one page without a tab strip) or TabForm layout. Both use the same
Session, controls, editor, validation and speech/braille presentation.
Controls include entries, protected entries, lists, grids, checkboxes, buttons, numeric fields and combo boxes. Forms support groups, hidden draft controls, disabled controls, required fields, entry length limits and dynamic choices. List and category-arrow navigation stops at boundaries; Tab/Shift+Tab cycles through enabled visible controls in the current dialog/page. Home/End selects list or category boundaries. Lists and grids support Page Up/Down.
Entries support Unicode caret movement, Control+Left/Right word movement, Shift selection, select-all, and host-mediated copy/cut/paste. The host must write the clipboard successfully before deleting a cut selection. Password fields mask speech and braille, refuse copy/cut, and drop their text references on Close. Values and Focused_control may contain plaintext secrets: use them only for submission, never generic logging or persistence. Go strings do not provide guaranteed memory erasure. Clipboard I/O remains a host operation. Fenrir uses its clipboard history; Cthulhu uses its existing desktop clipboard.
NewSession accepts a session-local Messages translator. Literal choices bypass translation. Result contains speech, braille and cursor information alongside activation and clipboard requests. Presentation styles affect wording, not control behavior. Hosts call Close on cancellation, replacement and shutdown; the toolkit closes itself on Escape. Sessions belong to one event-loop/worker and must not be accessed concurrently without external serialization.
interaction translates the existing Cthulhu form protocol into this toolkit,
retaining JSON kinds and external input limits. Its NewUnifiedSession exposes
rich forms to core reader features; Cthulhu's OpenUI returns typed Controls
keyed by page.control and preserves local-only authorization. The old
interaction/tabbed import is a compatibility alias. Neither adapter contains
an independent widget engine. Fenrir imports internalui through its local
localization adapter. New widgets belong in internalui, so either reader can
use them without another implementation. No date picker or general table
widget is included yet; external application table reading is separate.
Hosts retain keyboard capture, secure/local-only authorization, focus and session cancellation, clipboard I/O, action execution, settings persistence, and speech/braille delivery. The toolkit imports only the standard library and other packages within this module.
Run go test -race ./... here. Tests exercise both layouts, adapters, secrets,
editing, validation, independent sessions/catalogs and matching grid behavior.
Consumer repositories also retain application and input integration tests.
Local development and release
For sibling checkouts, create a local Go workspace in their parent directory:
go work init ./screenreader-common ./cthulhu ./fenrir
Do not commit machine-local workspace or replacement paths. A workspace makes
both local reader builds use these sources immediately. Published builds use
pinned module versions: after review and live acceptance, release/tag the
common module, then update go.mod and go.sum in both readers and test
with GOWORK=off. A shared source change does not update already installed
binaries; they must be rebuilt with the updated dependency.
Speech Dispatcher
speechdispatcher owns the shared SSIP client used by both readers: endpoint
resolution, optional daemon startup, speaking and independent cancellation
connections, settings, bounded reply parsing, discovery queries, and read-all
notifications. It has no service-manager dependency. Each reader supplies its
client identity and keeps its own admission, interruption, presentation, and
hardware-synthesizer behavior. Fenrir enables automatic system-socket fallback;
explicit socket/address choices never fall back to another server.
After a connection fails, the failed utterance is not replayed. The next fresh speech request rebuilds both channels and restores settings, priority, and the new cancellation target. Failed reconnection remains retryable on subsequent requests. Context cancellation bounds connection work; Close and Abort prevent reconnection. Fenrir additionally retains its worker's bounded background retry and outage-queue discard policy. An already accepted utterance whose reply was lost may have spoken before the failure; automatically replaying it is unsafe.
Speak normalizes desktop text; SpeakText preserves console-prepared whitespace
and line boundaries. SpeakCharacter sends character feedback. Query connections
are separate from speaking connections, and ordinary discovery never autostarts
a daemon. Startup can honor the invoking sudo user's credentials without
changing the reader process's credentials.
Run go test -race ./speechdispatcher for protocol and recovery fixtures.
CTHULHU_NATIVE_SPEECH_STARTUP=1 go test -race ./speechdispatcher additionally
starts and restarts private dummy-output daemons; it does not restart the user's
Speech Dispatcher. The environment variable retains the migrated test's name.
The shared client is available starting with v0.3.0. Both readers pin released
module versions for standalone builds; the sibling workspace remains useful
for local development. Verify released dependencies with GOWORK=off. Existing installed
binaries do not gain fixes until rebuilt. Live audible-speech, keyboard, and
braille acceptance is tracked separately from automated protocol tests.
Additional shared behavior
The following packages have one implementation used by both readers:
datetime: format presets, validation, option examples, locale-awarestrftimeformatting, and a non-CGO fallback.speechdispatcher.LanguageVoices: locale normalization, dialect/base-language matching, explicit-language selection, and ordering of eSpeak variants.phonetic: the spelling alphabet, includingwhiskeyandx ray. Reader presentation can capitalize the returned words and select uppercase voices.tones: native progress pitch/waveforms, the indentation triangle variant, PCM/WAV generation, and the existing sine-tone generator. Playback services, resampling to an output device, volume, pan, and queue admission stay local.hardware: one normalized -100..100 settings scale, native command encoding, ASCII text filtering, DECtalk command escaping, terminators, and per-device cancellation bytes. Serial DECtalk uses ETX to cancel and VT to submit text; DECtalk USB uses ACK to cancel. LiteTalk, DoubleTalk and TripleTalk share their control-A settings, CR terminator, and control-X cancellation.
Hardware commands use the previously tested Fenrir mapping in both readers.
DECtalk rate spans 75/180/650 and pitch spans 50/122/350 at minimum/midpoint/maximum;
volume uses dv g5 from 60 to 86. Cthulhu converts its legacy saved 0..99 rate
and 0..9 pitch/volume values at the boundary. It no longer has a separate
DECtalk encoding. Port opening, serial/USB I/O, flush timing and cancellation
synchronization remain the responsibility of the device-owning reader.
These additions are available starting with v0.4.0. Both readers pin this
version for standalone builds. Verify pinned dependencies with GOWORK=off;
physical keyboard, audible speech, braille, and hardware acceptance remain
separate live checks.