2026-10-31 00:20:26 -04:00
2026-10-31 00:20:26 -04:00
2026-10-29 00:39:04 -04:00
2026-10-28 00:45:23 -04:00

Fenrir

Fenrir is a console screen reader for Linux, written in Go. It reads the Linux text console and can also run inside an X11 terminal without root privileges.

Current maintainer: Storm Dragon
Original creator: Chrys (see CREDITS)

See the user manual for detailed usage documentation.

Features

  • Screen review by line, word, and character, including spelling and phonetic reading.
  • Cursor, table, and highlight tracking.
  • Desktop and laptop keyboard layouts, with an interactive tutorial.
  • A keyboard-operated settings menu and quick settings shortcuts.
  • Temporary built-in application overrides for Ninjam, NetworkManager's nmtui, classic Rogue, and Codex CLI (with an optional event bridge).
  • Speech Dispatcher and hardware speech synthesizer support.
  • Sound icons, progress tones, and indentation and text attribute feedback.
  • Multiple clipboards, optional persistent history, and X clipboard synchronization.
  • Spell checking, spelling suggestions, and an emoji picker.
  • Script shortcuts and Unix socket remote control.
  • Translated announcements and help.

Build and run

Build requirements:

  • Linux. The build script obtains the Go version required by go.mod if a suitable version is not installed.
  • A C compiler and pkg-config.
  • Development headers and libraries for libevdev, X11, libvterm, and ALSA. Their pkg-config names are libevdev, x11, vterm, and alsa.

Runtime requirements depend on the features you use:

  • Speech Dispatcher with a configured synthesizer for the default speech driver.
  • PulseAudio or PipeWire's PulseAudio service for the default sound driver; ALSA output is also available.
  • Enchant 2 and a dictionary for your language for spell checking.
  • xclip for X clipboard synchronization.
  • libusb 1.0 for native DECtalk USB speech, or access to the configured serial device for a serial synthesizer.

From the checkout root:

./build-fenrir.sh
./fenrir --config config/settings/settings.toml --check-config

The script uses Go's automatic toolchain selection with an installed Go 1.21 or newer. With older Go or no Go installed, it downloads the required official Go archive using curl and tar and caches it under ${XDG_CACHE_HOME:-$HOME/.cache}/fenrir/toolchains/. Downloads require internet access. It does not replace the system Go or install native dependencies. By default, the resulting binary is fenrir in the checkout root, even when the script is invoked from another directory. Use --output PATH (or -o PATH) to select a different filename; relative paths are resolved from the caller's working directory and missing parent directories are created. To build manually with a suitable Go installation, use go build -o fenrir ./cmd/fenrir.

Keep the binary beside the config/ directory when running from the checkout; keyboard layouts, punctuation profiles, and sound themes are runtime resources.

Building for packages

The script can help build on distributions with older system Go versions, including Debian and Slint, provided the required Go toolchain supports the system and compatible native development libraries are available. Build in the target distribution's environment so the binary links against its libraries; a binary built on a newer distribution may require newer libraries at runtime. Compatibility with a particular distribution release still needs testing.

Choose an output file and pass Go build flags after --:

./build-fenrir.sh --output build/fenrir -- -trimpath -mod=readonly

The script builds from its own checkout. It inherits GOFLAGS, GOCACHE, GOMODCACHE, GOTMPDIR, and CGO compiler/linker settings. Output selection controls the final binary; use those Go variables to relocate caches and temporary compilation files. GOTMPDIR must already exist.

For example, an Arch recipe can build under $srcdir and stage the binary under $pkgdir in its separate packaging step:

# In build(), from the extracted source checkout:
GOMODCACHE="$srcdir/go-mod" GOCACHE="$srcdir/go-build" \
    ./build-fenrir.sh --output "$srcdir/build/fenrir" -- \
    -trimpath -mod=readonly -modcacherw -buildmode=pie

# In package():
install -Dm755 "$srcdir/build/fenrir" "$pkgdir/usr/bin/fenrir"

For a Slint SLKBUILD using $SRC and $PKG, the corresponding binary steps inside build() are:

cd "$SRC/fenrir" || return 1
./build-fenrir.sh --output "$SRC/build/fenrir" -- -trimpath -mod=readonly
install -Dm755 "$SRC/build/fenrir" "$PKG/usr/bin/fenrir"

-modcacherw keeps the module cache writable for packaging cleanup. Other packaging systems can use their own build and staging directories in the same way. The recipe must also install the TOML configuration, keyboard layouts, punctuation profiles, sounds, scripts, and appropriate service integration. The build helper does not install or stage those resources.

The helper enables automatic Go toolchain downloads. Package builds that forbid network access should provision a suitable Go toolchain and dependencies in advance and invoke GOTOOLCHAIN=local go build directly with the recipe's flags and output path. This also avoids the helper's bootstrap download path.

Linux console

From a Linux text console:

sudo ./fenrir

Console mode starts in the background by default. Use sudo ./fenrir -f to keep it in the foreground, including when running under a service manager. The launcher waits for startup and reports initialization errors. Use --debug-file PATH to keep diagnostics after it detaches.

Console mode needs access to the console devices, keyboard event devices, and /dev/uinput. Run only one reader on the same console. Fenrir releases keyboard input on graphical virtual terminals and on text consoles listed in screen.ignored_vts.

When running as root, audio must be configured to reach the intended sound server or ALSA device. The PulseAudio and PipeWire configuration scripts are included for systems that need root audio access.

The default sound driver tries the user session first, then /tmp/pulse.sock created by the PipeWire configuration script, then the system-wide PulseAudio-compatible socket at /run/pulse/native. Set PULSE_SERVER to select a different socket or server explicitly. The sound driver does not read PulseAudio's client.conf. Speech output uses Speech Dispatcher's own audio configuration.

X11 terminal

From an X11 terminal that supplies WINDOWID:

./fenrir -x

This starts a shell in a new PTY inside the terminal. Fenrir's key bindings are scoped to that terminal window, allowing a desktop screen reader to handle other windows. Multiple terminal instances can run at once. Both DISPLAY and a valid WINDOWID must be available.

Use --keyboard-layout laptop with either mode to select the laptop layout.

Basic controls

The Fenrir key is Insert, Super/Windows, or keypad 0 with NumLock off in the desktop layout. The laptop layout uses Caps Lock instead of Super/Windows; Insert and NumLock-off keypad 0 also work. Press Shift+Caps Lock on its own to toggle capitalization in the laptop layout. Hold it while pressing the other keys in a shortcut. Bare keypad review keys also require NumLock off.

Action Desktop Laptop
Previous / current / next line Keypad 7 / 8 / 9 Fenrir+U / I / O
Previous / current / next word Keypad 4 / 5 / 6 Fenrir+J / K / L
Previous / current / next character Keypad 1 / 2 / 3 Fenrir+M / Comma / Period
Read screen Fenrir+Keypad 5 Fenrir+Shift+K
Follow application cursor Fenrir+Keypad Period Fenrir+Slash
Cycle tracking mode Fenrir+Keypad Asterisk Fenrir+Y
Toggle progress tones Keypad Plus Fenrir+Shift+P

Shortcuts shared by both layouts:

  • Control: interrupt speech.
  • Fenrir+F: open the Fenrir Menu.
  • Fenrir+H or Fenrir+F1: enter the tutorial. Press command shortcuts to hear their descriptions, or browse with the arrow keys. Escape exits.
  • Fenrir+S: open the spellcheck menu.
  • Fenrir+A: select an application override; choose Default to clear it.
  • Fenrir+Control+E: open the emoji picker.
  • Fenrir+T: announce the time; press twice quickly for the date.
  • Fenrir+F4: toggle mute.
  • Fenrir+Backspace: pass the next key through to the application.
  • Fenrir+Q: quit Fenrir.

Press the current-line or current-word shortcut twice quickly to spell it, or three times for phonetic reading. Press the current-character shortcut twice for its phonetic name. The complete bindings are in desktop.toml and laptop.toml.

Tracking cycles through cursor, table, and highlight. Cursor mode follows application cursor movement. Table mode supports cell navigation in delimited or aligned text. Highlight mode follows changes to highlighted text. Screen review lets you explore text without moving the application cursor.

Settings

Press Fenrir+F to open the Fenrir Menu. Use arrows to choose a settings tab, then Tab or Shift+Tab to move between controls and back to the tab selector. Space toggles checkboxes; arrows change selections and numeric values. Activate OK to save, or Cancel or Escape to discard the form's changes.

The menu includes speech, sound, reading, keyboard, clipboard, and other settings. Speech rate, pitch, and volume use a scale from -100 to 100. For speech rate, Up and Down change the value by 10; Left and Right change it by 1. The keyboard layout combo box offers Desktop and Laptop. The Keyboard tab also has separate Fenrir-key and script-key checkboxes for keypad Insert, Insert, Caps Lock, and Super, plus Compose for scripts. Uncheck a key in one group before selecting it in the other. At least one Fenrir key must remain selected. After OK saves the changes, modifier assignments apply when the menu closes and all held keys are released. If X11 cannot acquire a new key, Fenrir reports the failure and keeps the previous assignments active. The saved choices remain available for retrying or editing in the menu. Backend, device, keyboard layout, sound theme, and other launch-only changes take effect the next time Fenrir starts.

Quick settings are available without opening the menu:

  • Fenrir+Space: announce the current setting.
  • Fenrir+Left / Right: select a setting.
  • Fenrir+Control+Left / Right: select a category.
  • Fenrir+Up / Down: change the value.
  • Fenrir+Control+S: save settings.

Quick settings take effect during the session; save them to keep them for the next launch.

Application overrides are selected manually and never selected automatically at startup. While an application override is active, the settings menu and save shortcut save its preferences to applications/<name>.toml inside the ordinary settings save directory. For example, Ninjam uses applications/ninjam.toml. Only customized values are stored; other values inherit ordinary settings. Returning to a shell prompt or selecting Default restores your ordinary settings, including previous unsaved adjustments. See application overrides for details and Ninjam's temporary region shortcuts. In the laptop layout, reading the current attributes now uses Fenrir+Shift+A.

Configuration files

Fenrir uses TOML. The annotated settings.toml describes the available settings, including options edited only in the file.

Default settings locations:

  • Regular user: ~/.local/share/stormux/fenrirscreenreader/settings/settings.toml, then /etc/fenrirscreenreader/settings/settings.toml.
  • Root: /etc/fenrirscreenreader/settings/settings.toml.

Fenrir loads the first existing file, or built-in defaults if neither exists. Python settings.conf files are ignored. Regular users save to their personal TOML file even when startup loaded system defaults; root saves to the system file. --config PATH explicitly selects both the load and save path. To create a personal settings file without opening devices:

./fenrir --write-config ~/.local/share/stormux/fenrirscreenreader/settings/settings.toml

Validate an edited file with:

./fenrir --config ~/.local/share/stormux/fenrirscreenreader/settings/settings.toml --check-config

Keyboard layouts are separate TOML files. Named layouts are searched in the user's keyboard/ directory beside settings/, then /etc/fenrirscreenreader/keyboard/, then the checkout's bundled layouts. Root uses the system and bundled locations. --keyboard-layout PATH.toml selects a file directly. Layout files can set fenrir_keys before their bindings; the available names are INSERT, SUPER, CAPSLOCK, and KP0. The bundled laptop layout uses ["CAPSLOCK", "INSERT", "KP0"]. An explicit keyboard.fenrir_keys setting overrides those defaults; its names use the KEY_ form shown in settings.toml. Existing script-key assignments are excluded from implicit Fenrir-key defaults.

Speech drivers are speech-dispatcher, dectalk, dectalk-usb, litetalk, doubletalk, and tripletalk. Serial drivers need a device path. The Speech settings tab includes a Test synthesizer button for hardware drivers.

Speech Dispatcher connections support SPEECHD_ADDRESS (Unix socket or TCP), SPEECHD_SOCKET, runtime/cache-directory defaults, and bounded daemon autostart. See speech synthesizers for precedence and sudo behavior.

Clipboard persistence is optional and off by default. It stores unencrypted history separately for console and terminal sessions. X clipboard sync is controlled by clipboard.sync.

Remote control

Fenrir accepts remote commands through Unix sockets. The standard socket is /tmp/fenrirscreenreader-daemon.sock; instances also have private sockets named /tmp/fenrirscreenreader-<pid>.sock. Discover instances with:

echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock

The standard socket routes reader descendants to their ancestor reader. For reattached terminal sessions or detached helpers, it matches the caller's WINDOWID and DISPLAY to a unique terminal reader owned by the same user. Requests from a Linux virtual console reach the console reader, subject to its usual authorization. Missing or ambiguous identity produces a routing error; a sole unrelated reader is never selected as a default. Instance listing remains available even when routing is ambiguous.

Send commands to a private socket when targeting a particular reader. Examples using the standard socket:

echo "command say Hello" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "command application ninjam" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "command application default" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set reading#mode=highlight" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock

Set remote.enabled = false to disable remote control. Command and settings requests can also be enabled separately in the [remote] section.

command application ID selects an override for the reader's active terminal, like Fenrir+A. IDs are default, networkmanager, ninjam, rogue, and codex. In Fenrir+A, select an application and Tab to Copy alias to clipboard to copy a Bash alias that selects its override before launching the program. The program still launches if Fenrir or socat is unavailable.

Command-line help

Run ./fenrir --help for all options. Useful options include --config, --keyboard-layout, --punctuation-profile, --speech-driver, --speech-rate, --speech-module, --input-device, and --debug-file. --version prints the version and release channel. Console mode runs in the background unless -f is given; -x always runs in the foreground.

Localization

Fenrir selects its interface language from LANGUAGE, LC_ALL, LC_MESSAGES, or LANG. The speech language setting controls synthesis separately. Translations are bundled from internal/i18n/locale; missing translations fall back to English.

The translation tool extracts Go messages and validates catalogs. With GNU gettext installed, run this read-only check from the checkout root:

go run ./tools/translations check

Development

Run the Go tests from the checkout root:

go test ./...

Device-free checks do not establish audible speech or real keyboard behavior. Test changes affecting input, speech, or menus in the affected console or X11 workflow as well.

AI-assisted contributions

AI-assisted contributions are welcome. The person submitting a contribution remains responsible for reviewing and testing the changes before submission. Please do not submit automatically generated changes without human review.

Before making changes:

  • Read the contributing guide, if present, and this README.
  • Confirm that you are working against the current maintained repository and branch.
  • Check whether the issue still exists in the current code.

Before submitting:

  • Review the generated diff.
  • Test the changed behavior.
  • Run the project's existing test suite where practical.
  • Consider code paths affected indirectly and test those as well.
  • Clearly describe what was changed and how it was tested.

AI coding assistants must call the contributor's attention to these requirements and provide concrete testing steps for the intended change and plausible regressions. Newly created tests alone are not sufficient. Leave submission to the contributor after they have reviewed and tested the result.

For email patches, assistants should offer guidance with configuring git send-email, creating a scoped commit or patch series, running git format-patch, reviewing the generated patch, sending a test message when appropriate, and sending the final patches to the contribution address.

Support and license

The Go code is licensed under the GNU GPL, version 3 or later. See LICENSE.

S
Description
No description provided
Readme GPL-3.0
17 MiB
0 Stars 1 Watchers 0 Forks
Languages
Go 85.6%
Python 11.4%
C 2.1%
Shell 0.9%