Attempt to improve the multicharacter detection code.
This commit is contained in:
1 parent
6fc3416a1b
commit
3cf41e662c
12 files changed
+1135
-843
No files matched your search
@@ -1,15 +0,0 @@
|
|||||||
Please report bugs and feature requests to:
|
|
||||||
https://git.stormux.org/storm/fenrir/issues
|
|
||||||
|
|
||||||
For bugs, please provide a debug file that shows the issue.
|
|
||||||
How to create a debug file:
|
|
||||||
1. start fenrir in debug mode
|
|
||||||
sudo fenrir -d
|
|
||||||
<do your stuff>
|
|
||||||
2.
|
|
||||||
stop fenrir (fenrirKey + q)
|
|
||||||
the debug file is in /tmp/fenrir.log
|
|
||||||
if another Fenrir debug instance is already using it, check /tmp/fenrir2.log,
|
|
||||||
/tmp/fenrir3.log, etc.
|
|
||||||
|
|
||||||
please be as precise as possible to make it easy to solve the problem.
|
|
||||||
@@ -75,7 +75,8 @@ punctuation_profile = "default"
|
|||||||
punctuation_level = "some"
|
punctuation_level = "some"
|
||||||
# Whole whitespace-delimited emoticons, matching Python's names/boundaries.
|
# Whole whitespace-delimited emoticons, matching Python's names/boundaries.
|
||||||
emoticons = true
|
emoticons = true
|
||||||
# Optional summaries for whole repeated-symbol tokens, e.g. ##### -> 5 number.
|
# Optional summaries for repeated-symbol tokens, e.g. ##### -> 5 number.
|
||||||
|
# Matching brackets around a run are allowed, e.g. [#####].
|
||||||
# Only symbols named at the selected punctuation level are summarized.
|
# Only symbols named at the selected punctuation level are summarized.
|
||||||
repeated_symbols = false
|
repeated_symbols = false
|
||||||
# Minimum run length, 2–10000; default 4 means more than three repeats.
|
# Minimum run length, 2–10000; default 4 means more than three repeats.
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
Fenrir console audio
|
|
||||||
|
|
||||||
Fenrir's pulse sound driver uses PulseAudio or PipeWire's PulseAudio service.
|
|
||||||
The alsa driver opens the configured ALSA PCM device directly. Speech Dispatcher
|
|
||||||
has its own synthesis and audio configuration, separate from Fenrir's sound cues.
|
|
||||||
|
|
||||||
For an X11 terminal session, start Fenrir as the regular user with ./fenrir -x.
|
|
||||||
For console mode started through sudo, Fenrir uses SUDO_UID to find the invoking
|
|
||||||
user's PulseAudio and Speech Dispatcher sockets. An explicit PULSE_SERVER takes
|
|
||||||
precedence for sound cues; SPEECHD_ADDRESS with a unix_socket: address takes
|
|
||||||
precedence for Speech Dispatcher. The relevant services must already be running
|
|
||||||
and accessible to the reader process.
|
|
||||||
|
|
||||||
If root sound still needs separate configuration, the checkout includes
|
|
||||||
tools/configure_pulse.sh for PulseAudio and
|
|
||||||
tools/configure_pipewire.sh for PipeWire.
|
|
||||||
Read the appropriate script before running it. Each has a regular-user part
|
|
||||||
and a root part, and writes audio configuration files. The PulseAudio script
|
|
||||||
replaces the user's default.pa and configures an anonymously accessible socket
|
|
||||||
at /tmp/pulse.sock. The PipeWire script also changes WirePlumber settings.
|
|
||||||
These are system audio changes, not prerequisites for every Fenrir session.
|
|
||||||
|
|
||||||
For ALSA, select driver = "alsa" under [presentation.sound] in settings.toml
|
|
||||||
and set device to the desired PCM name, such as "default". Driver and device
|
|
||||||
changes apply at the next launch.
|
|
||||||
|
|
||||||
See README.md for build and startup instructions and docs/user.md for the Sound
|
|
||||||
settings and troubleshooting sections.
|
|
||||||
@@ -14,15 +14,13 @@ trap 'rm -rf -- "$tempDir"' EXIT
|
|||||||
# Generate every format successfully before replacing any existing output.
|
# Generate every format successfully before replacing any existing output.
|
||||||
pandoc "$docsDir/user.md" --from markdown --to plain --wrap=auto \
|
pandoc "$docsDir/user.md" --from markdown --to plain --wrap=auto \
|
||||||
| sed 's/[[:blank:]]*$//' > "$tempDir/user.txt"
|
| sed 's/[[:blank:]]*$//' > "$tempDir/user.txt"
|
||||||
pandoc "$docsDir/user.md" --from markdown --to asciidoc --wrap=auto \
|
|
||||||
--output "$tempDir/fenrir.adoc"
|
|
||||||
pandoc "$docsDir/user.md" --from markdown --to man --standalone \
|
pandoc "$docsDir/user.md" --from markdown --to man --standalone \
|
||||||
--lua-filter "$docsDir/man_tables.lua" \
|
--lua-filter "$docsDir/man_tables.lua" \
|
||||||
--metadata title=fenrir --metadata section=1 \
|
--metadata title=fenrir --metadata section=1 \
|
||||||
--metadata header="Fenrir User Manual" \
|
--metadata header="Fenrir User Manual" \
|
||||||
--output "$tempDir/fenrir.1"
|
--output "$tempDir/fenrir.1"
|
||||||
|
|
||||||
for manualFile in user.txt fenrir.adoc fenrir.1; do
|
for manualFile in user.txt fenrir.1; do
|
||||||
mv -- "$tempDir/$manualFile" "$docsDir/$manualFile"
|
mv -- "$tempDir/$manualFile" "$docsDir/$manualFile"
|
||||||
done
|
done
|
||||||
|
|
||||||
+495
-125
@@ -86,90 +86,68 @@ review.
|
|||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Previous / current / next line\f[R]
|
\f[B]Previous / current / next line\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Desktop:\f[R] Keypad 7 / 8 / 9
|
||||||
Desktop: Keypad 7 / 8 / 9
|
\f[B]Laptop:\f[R] Fenrir+U / I / O
|
||||||
.PP
|
|
||||||
Laptop: Fenrir+U / I / O
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Previous / current / next word\f[R]
|
\f[B]Previous / current / next word\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Desktop:\f[R] Keypad 4 / 5 / 6
|
||||||
Desktop: Keypad 4 / 5 / 6
|
\f[B]Laptop:\f[R] Fenrir+J / K / L
|
||||||
.PP
|
|
||||||
Laptop: Fenrir+J / K / L
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Previous / current / next character\f[R]
|
\f[B]Previous / current / next character\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Desktop:\f[R] Keypad 1 / 2 / 3
|
||||||
Desktop: Keypad 1 / 2 / 3
|
\f[B]Laptop:\f[R] Fenrir+M / Comma / Period
|
||||||
.PP
|
|
||||||
Laptop: Fenrir+M / Comma / Period
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Top / bottom of screen\f[R]
|
\f[B]Top / bottom of screen\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Desktop:\f[R] Fenrir+Keypad 7 / 9
|
||||||
Desktop: Fenrir+Keypad 7 / 9
|
\f[B]Laptop:\f[R] Fenrir+Shift+U / O
|
||||||
.PP
|
|
||||||
Laptop: Fenrir+Shift+U / O
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Line start / end\f[R]
|
\f[B]Line start / end\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Desktop:\f[R] Fenrir+Keypad 4 / 6
|
||||||
Desktop: Fenrir+Keypad 4 / 6
|
\f[B]Laptop:\f[R] Fenrir+Shift+J / L
|
||||||
.PP
|
|
||||||
Laptop: Fenrir+Shift+J / L
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]First / last text on line\f[R]
|
\f[B]First / last text on line\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Desktop:\f[R] Fenrir+Keypad 1 / 3
|
||||||
Desktop: Fenrir+Keypad 1 / 3
|
\f[B]Laptop:\f[R] Fenrir+Control+J / L
|
||||||
.PP
|
|
||||||
Laptop: Fenrir+Control+J / L
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Read screen\f[R]
|
\f[B]Read screen\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Desktop:\f[R] Fenrir+Keypad 5
|
||||||
Desktop: Fenrir+Keypad 5
|
\f[B]Laptop:\f[R] Fenrir+Shift+K
|
||||||
.PP
|
|
||||||
Laptop: Fenrir+Shift+K
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Screen before / after cursor\f[R]
|
\f[B]Screen before / after cursor\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Desktop:\f[R] Fenrir+Keypad 8 / 2
|
||||||
Desktop: Fenrir+Keypad 8 / 2
|
\f[B]Laptop:\f[R] Fenrir+Shift+I / Comma
|
||||||
.PP
|
|
||||||
Laptop: Fenrir+Shift+I / Comma
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Character above / below\f[R]
|
\f[B]Character above / below\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Desktop:\f[R] Fenrir+Control+Keypad 8 / 2
|
||||||
Desktop: Fenrir+Control+Keypad 8 / 2
|
\f[B]Laptop:\f[R] Fenrir+Control+I / Comma
|
||||||
.PP
|
|
||||||
Laptop: Fenrir+Control+I / Comma
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Follow cursor\f[R]
|
\f[B]Follow cursor\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Desktop:\f[R] Fenrir+Keypad Period
|
||||||
Desktop: Fenrir+Keypad Period
|
\f[B]Laptop:\f[R] Fenrir+Slash
|
||||||
.PP
|
|
||||||
Laptop: Fenrir+Slash
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Review position\f[R]
|
\f[B]Review position\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Desktop:\f[R] Keypad Period
|
||||||
Desktop: Keypad Period
|
\f[B]Laptop:\f[R] Fenrir+Shift+Period
|
||||||
.PP
|
|
||||||
Laptop: Fenrir+Shift+Period
|
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
Press the current\-line or current\-word shortcut twice quickly to spell
|
Press the current\-line or current\-word shortcut twice quickly to spell
|
||||||
@@ -215,7 +193,13 @@ application.
|
|||||||
Character echo, word echo, and cursor echo can be configured separately.
|
Character echo, word echo, and cursor echo can be configured separately.
|
||||||
Punctuation levels are \f[CR]none\f[R], \f[CR]some\f[R],
|
Punctuation levels are \f[CR]none\f[R], \f[CR]some\f[R],
|
||||||
\f[CR]most\f[R], and \f[CR]all\f[R].
|
\f[CR]most\f[R], and \f[CR]all\f[R].
|
||||||
Character review still names punctuation.
|
At \f[CR]some\f[R] and \f[CR]most\f[R], punctuation inside words, URLs,
|
||||||
|
email addresses, and filenames is also named.
|
||||||
|
Apostrophes within words and single numeric separators such as those in
|
||||||
|
\f[CR]3.14\f[R], \f[CR]1,000\f[R], and \f[CR]12:30\f[R] follow the
|
||||||
|
selected level.
|
||||||
|
Sentence punctuation follows the selected level too.
|
||||||
|
Character review always names punctuation.
|
||||||
Capital indicators, emoticons, repeated\-symbol summaries, indentation
|
Capital indicators, emoticons, repeated\-symbol summaries, indentation
|
||||||
feedback, and attribute feedback are configurable in Reading.
|
feedback, and attribute feedback are configurable in Reading.
|
||||||
.PP
|
.PP
|
||||||
@@ -239,7 +223,8 @@ Activate \f[B]OK\f[R] to save, or \f[B]Cancel\f[R] or Escape to discard
|
|||||||
the form\(cqs changes.
|
the form\(cqs changes.
|
||||||
.PP
|
.PP
|
||||||
Speech rate, pitch, and volume use a scale from \-100 to 100.
|
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.
|
For speech rate, Up and Down change the value by 10; Left and Right
|
||||||
|
change it by 1.
|
||||||
Sound volume is between 0.0 and 1.0.
|
Sound volume is between 0.0 and 1.0.
|
||||||
Backend, device, keyboard layout, sound theme, and other launch\-only
|
Backend, device, keyboard layout, sound theme, and other launch\-only
|
||||||
settings take effect on the next start.
|
settings take effect on the next start.
|
||||||
@@ -267,38 +252,374 @@ Quick settings work without opening the form:
|
|||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+Space\f[R]
|
\f[B]Fenrir+Space\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Announce current setting
|
||||||
Action: Announce current setting
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+Left / Right\f[R]
|
\f[B]Fenrir+Left / Right\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Previous / next setting
|
||||||
Action: Previous / next setting
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+Control+Left / Right\f[R]
|
\f[B]Fenrir+Control+Left / Right\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Previous / next category
|
||||||
Action: Previous / next category
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+Up / Down\f[R]
|
\f[B]Fenrir+Up / Down\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Change value
|
||||||
Action: Change value
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+Control+S\f[R]
|
\f[B]Fenrir+Control+S\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Save settings
|
||||||
Action: Save settings
|
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
Quick changes apply to the current session.
|
Quick changes apply to the current session.
|
||||||
Save to retain them for future launches.
|
Save to retain them for future launches.
|
||||||
Session controls such as mute and temporary silence are separate from
|
Session controls such as mute and temporary silence are separate from
|
||||||
saved startup preferences.
|
saved startup preferences.
|
||||||
|
.SS Application overrides
|
||||||
|
Press \f[B]Fenrir+A\f[R] to open \f[B]Applications\f[R].
|
||||||
|
Up and Down select an item; Enter activates it and closes the menu.
|
||||||
|
Escape or the Cancel button closes the menu without changing the
|
||||||
|
selection.
|
||||||
|
Tab and Shift+Tab move between the list, Copy alias to clipboard,
|
||||||
|
Cancel, and the tab selector.
|
||||||
|
The active override is initially selected.
|
||||||
|
.PP
|
||||||
|
Type the start of a name to jump to it: \f[B]n\f[R] selects
|
||||||
|
NetworkManager, then \f[B]i\f[R] selects Ninjam.
|
||||||
|
Searching ignores letter case and does not activate the item.
|
||||||
|
Backspace removes a search character; Control+Backspace clears the
|
||||||
|
search.
|
||||||
|
Up, Down, or moving focus away from the list also clears the search.
|
||||||
|
Unmatched characters announce \f[B]No matches\f[R] and leave the last
|
||||||
|
matching search intact.
|
||||||
|
.PP
|
||||||
|
Start the application normally, then select its override.
|
||||||
|
This menu does not launch programs.
|
||||||
|
Choose \f[B]Default\f[R] to restore the settings and reading regions
|
||||||
|
that were in effect before the override.
|
||||||
|
Overrides are built into Fenrir and are never selected automatically or
|
||||||
|
remembered across restarts.
|
||||||
|
.PP
|
||||||
|
To launch a program with its override, select its name in this list,
|
||||||
|
then Tab to \f[B]Copy alias to clipboard\f[R] and press Enter.
|
||||||
|
This copies a Bash alias into Fenrir\(cqs clipboard without selecting
|
||||||
|
the override or closing the menu.
|
||||||
|
Paste it into your Bash configuration, such as \f[CR]\(ti/.bashrc\f[R],
|
||||||
|
and load that configuration in a new shell.
|
||||||
|
The aliases use the executable names \f[CR]cninjam\f[R],
|
||||||
|
\f[CR]nmtui\f[R], \f[CR]rogue\f[R], and \f[CR]codex\f[R]; Default has no
|
||||||
|
alias.
|
||||||
|
Existing aliases with those names are replaced when you load the
|
||||||
|
definition.
|
||||||
|
.PP
|
||||||
|
The alias requests the override through \f[CR]socat\f[R], then launches
|
||||||
|
the real program with the arguments you supplied.
|
||||||
|
Errors remain visible, and the program still launches if the request
|
||||||
|
fails, remote control is disabled, or Fenrir or \f[CR]socat\f[R] is
|
||||||
|
missing.
|
||||||
|
Socket inactivity is limited to two seconds.
|
||||||
|
It uses the standard socket, or your configured
|
||||||
|
\f[CR]remote.socket_file\f[R], rather than a process\-specific socket
|
||||||
|
that changes at restart.
|
||||||
|
Paste with Fenrir\(cqs clipboard command; desktop clipboard
|
||||||
|
synchronization follows your normal clipboard settings.
|
||||||
|
.PP
|
||||||
|
While an override is active, \f[B]Fenrir+F\f[R] opens its application
|
||||||
|
settings, with the application name in the title.
|
||||||
|
\f[B]OK\f[R], \f[B]Fenrir+Control+S\f[R], and remote
|
||||||
|
\f[CR]SETTING SAVE\f[R] save that application\(cqs preferences.
|
||||||
|
Quick and remote changes remain temporary until saved.
|
||||||
|
Default settings are kept separately, including any unsaved adjustments
|
||||||
|
made before activating the override.
|
||||||
|
.PP
|
||||||
|
Profiles live in an \f[CR]applications/\f[R] subdirectory of the
|
||||||
|
ordinary settings save directory.
|
||||||
|
For example:
|
||||||
|
.IP \(bu 2
|
||||||
|
System settings:
|
||||||
|
\f[CR]/etc/fenrirscreenreader/settings/applications/ninjam.toml\f[R].
|
||||||
|
.IP \(bu 2
|
||||||
|
Personal settings:
|
||||||
|
\f[CR]\(ti/.local/share/stormux/fenrirscreenreader/settings/applications/ninjam.toml\f[R].
|
||||||
|
.IP \(bu 2
|
||||||
|
With \f[CR]\-\-config /path/settings.toml\f[R]:
|
||||||
|
\f[CR]/path/applications/ninjam.toml\f[R].
|
||||||
|
.PP
|
||||||
|
NetworkManager uses \f[CR]networkmanager.toml\f[R]; Rogue uses
|
||||||
|
\f[CR]rogue.toml\f[R]; Codex uses \f[CR]codex.toml\f[R].
|
||||||
|
The directory and file are created on the first successful save.
|
||||||
|
Files contain only customized settings; omitted values inherit ordinary
|
||||||
|
settings followed by the built\-in application defaults.
|
||||||
|
A customized voice selection saves module, language, and voice together
|
||||||
|
so a later change to the ordinary voice does not break that selection.
|
||||||
|
Profiles are loaded when their override first recognizes the
|
||||||
|
application; restarting Fenrir still starts with Default.
|
||||||
|
Reselect the application to reload an edited file.
|
||||||
|
.PP
|
||||||
|
Application settings include voice, rate, pitch, volume, reading
|
||||||
|
behavior, sound enablement/volume, and typing echo.
|
||||||
|
Startup settings such as speech driver, serial device, keyboard layout,
|
||||||
|
and sound theme remain in the default menu; clipboard storage and
|
||||||
|
console routing also remain global.
|
||||||
|
Session mute and the temporary automatic\-reading toggle are not
|
||||||
|
implicitly saved.
|
||||||
|
Remote \f[CR]SAVEAS\f[R] and \f[CR]screen#ignore_screen\f[R] are
|
||||||
|
unavailable while an application is active.
|
||||||
|
Saving is blocked during context transitions or failed voice
|
||||||
|
restoration.
|
||||||
|
A malformed profile or unavailable voice leaves ordinary settings in
|
||||||
|
effect and reports an error.
|
||||||
|
Select the application again after correcting the file.
|
||||||
|
.PP
|
||||||
|
For example, a rate\-only profile contains current TOML setting names,
|
||||||
|
with no top\-level \f[CR]version\f[R] field:
|
||||||
|
.IP
|
||||||
|
.EX
|
||||||
|
\f[B][presentation.speech]\f[R]
|
||||||
|
rate = 40
|
||||||
|
.EE
|
||||||
|
.PP
|
||||||
|
To make a saved value inherit again, remove that setting from the
|
||||||
|
application file and reselect the override.
|
||||||
|
Removing the file restores complete inheritance.
|
||||||
|
.PP
|
||||||
|
An override belongs to its terminal.
|
||||||
|
Switching VTs or leaving the terminal suspends its effects; returning
|
||||||
|
resumes it when the application screen is recognized.
|
||||||
|
Unrecognized screens use ordinary reading.
|
||||||
|
A fresh shell prompt on the cursor row, with the application interface
|
||||||
|
absent, clears the selection and announces \f[B]Default settings
|
||||||
|
restored\f[R].
|
||||||
|
This works from screen contents, so it does not require access to remote
|
||||||
|
processes over SSH or inside GNU Screen.
|
||||||
|
Unusual prompts may require selecting Default manually.
|
||||||
|
Password prompts, confirmation questions, and old shell prompts in
|
||||||
|
scrollback do not clear it.
|
||||||
|
Split windows, heavily customized application colors, and localized or
|
||||||
|
unfamiliar layouts may prevent recognition; Default is always available.
|
||||||
|
.PP
|
||||||
|
\f[B]NetworkManager\f[R] targets \f[CR]nmtui\f[R] and temporarily
|
||||||
|
selects highlight tracking.
|
||||||
|
.PP
|
||||||
|
\f[B]Ninjam\f[R] targets the \f[CR]cninjam\f[R] curses client.
|
||||||
|
It announces selected controls with master, metronome, or channel
|
||||||
|
context; mute, transmit, and receive controls are spoken as states.
|
||||||
|
While adjusting a volume/pan control, Left/Right announces only the pan
|
||||||
|
percentage and direction, or center; Up/Down announces only the volume,
|
||||||
|
with minus and plus spoken explicitly.
|
||||||
|
Peak meters and the interval bar remain quiet.
|
||||||
|
Navigating the application\(cqs controls after manual review resumes
|
||||||
|
tracking; passive updates leave review in place.
|
||||||
|
Incoming chat is announced independently of control changes.
|
||||||
|
The following shortcuts temporarily replace numbered region reads:
|
||||||
|
.IP \(bu 2
|
||||||
|
\f[B]Fenrir+1\f[R]
|
||||||
|
.RS 2
|
||||||
|
\f[B]Ninjam information:\f[R] Latest new chat message received since
|
||||||
|
activation
|
||||||
|
.RE
|
||||||
|
.IP \(bu 2
|
||||||
|
\f[B]Fenrir+2\f[R]
|
||||||
|
.RS 2
|
||||||
|
\f[B]Ninjam information:\f[R] Selected channel or control
|
||||||
|
.RE
|
||||||
|
.IP \(bu 2
|
||||||
|
\f[B]Fenrir+3\f[R]
|
||||||
|
.RS 2
|
||||||
|
\f[B]Ninjam information:\f[R] Connection, tempo, and interval position
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
Fenrir+Shift+B lists these application assignments.
|
||||||
|
Existing user regions are preserved and restored when the override ends.
|
||||||
|
Review, Read Screen, and copying continue to expose the actual terminal
|
||||||
|
text, including its literal \f[CR]X\f[R] marks.
|
||||||
|
Chat history is baselined on activation, resize, buffer changes, and
|
||||||
|
history paging to avoid announcing old messages as new.
|
||||||
|
Messages that appear and disappear between screen captures cannot be
|
||||||
|
recovered reliably.
|
||||||
|
.PP
|
||||||
|
The laptop shortcut for reading attributes is \f[B]Fenrir+Shift+A\f[R];
|
||||||
|
Fenrir+A opens Applications in both layouts.
|
||||||
|
.PP
|
||||||
|
\f[B]Rogue\f[R] targets the classic English Rogue 5.4 terminal game,
|
||||||
|
including the 5.4.4 package.
|
||||||
|
Start \f[CR]rogue\f[R], then select \f[B]Rogue\f[R] with
|
||||||
|
\f[B]Fenrir+A\f[R] (type \f[B]r\f[R], then Enter).
|
||||||
|
The override announces messages and prompts, including \f[B]More; press
|
||||||
|
Space\f[R], changes in health, hunger, dungeon level, strength, armor,
|
||||||
|
and experience level, and newly visible monsters, objects, doors,
|
||||||
|
stairs, and traps.
|
||||||
|
Ordinary map redraws stay quiet.
|
||||||
|
Moving monsters are compared by letter and count to reduce repeated
|
||||||
|
announcements.
|
||||||
|
Their current positions remain available on request.
|
||||||
|
Appearing and disappearing messages between captures, or one monster
|
||||||
|
replacing another of the same letter without a count change, cannot
|
||||||
|
reliably be distinguished from the visible display alone.
|
||||||
|
.IP \(bu 2
|
||||||
|
\f[B]Fenrir+1\f[R]
|
||||||
|
.RS 2
|
||||||
|
\f[B]Rogue information:\f[R] Health, for example \(lqHealth: 12 of
|
||||||
|
12\(rq
|
||||||
|
.RE
|
||||||
|
.IP \(bu 2
|
||||||
|
\f[B]Fenrir+2\f[R]
|
||||||
|
.RS 2
|
||||||
|
\f[B]Rogue information:\f[R] Full status line
|
||||||
|
.RE
|
||||||
|
.IP \(bu 2
|
||||||
|
\f[B]Fenrir+3\f[R]
|
||||||
|
.RS 2
|
||||||
|
\f[B]Rogue information:\f[R] Latest message or prompt
|
||||||
|
.RE
|
||||||
|
.IP \(bu 2
|
||||||
|
\f[B]Fenrir+4\f[R]
|
||||||
|
.RS 2
|
||||||
|
\f[B]Rogue information:\f[R] Eight neighboring cells, clockwise from
|
||||||
|
north
|
||||||
|
.RE
|
||||||
|
.IP \(bu 2
|
||||||
|
\f[B]Fenrir+5\f[R]
|
||||||
|
.RS 2
|
||||||
|
\f[B]Rogue information:\f[R] Visible monsters and their positions
|
||||||
|
relative to you
|
||||||
|
.RE
|
||||||
|
.IP \(bu 2
|
||||||
|
\f[B]Fenrir+6\f[R]
|
||||||
|
.RS 2
|
||||||
|
\f[B]Rogue information:\f[R] Visible objects and landmarks, with
|
||||||
|
relative positions
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
These explicit reads include their region names.
|
||||||
|
Names are supported by the shared application\-region API, so other
|
||||||
|
overrides can use them as needed.
|
||||||
|
\f[B]Fenrir+Shift+B\f[R] lists the assignments.
|
||||||
|
Slots 7 through 10 remain available for manual regions.
|
||||||
|
Existing user regions are preserved while the override is active and
|
||||||
|
restored when it ends, as with Ninjam.
|
||||||
|
.PP
|
||||||
|
Directions give cell offsets, for example \(lqbat, north 2, east 3.\(rq
|
||||||
|
Descriptions use only displayed symbols; they do not reveal hidden
|
||||||
|
monsters, secret doors, or unidentified items.
|
||||||
|
Blank cells are described as unseen, and hallucination or disguised
|
||||||
|
monsters can make the displayed symbols misleading.
|
||||||
|
The playfield uses the first 24 rows and 80 columns even in a larger
|
||||||
|
terminal, with status on row 24.
|
||||||
|
Inventory, help, and options pages use ordinary reading and review; map
|
||||||
|
regions report information unavailable on those pages.
|
||||||
|
Slow inventory uses the ordinary message region.
|
||||||
|
Read Screen, review, and copying retain the actual terminal text.
|
||||||
|
Unrecognized screens return to ordinary reading.
|
||||||
|
.PP
|
||||||
|
Developers can exercise an installed classic Rogue in private PTYs
|
||||||
|
without touching the active reader:
|
||||||
|
.IP
|
||||||
|
.EX
|
||||||
|
FENRIR_ROGUE_TEST_BINARY=/usr/bin/rogue go test ./internal/terminal \-run TestRogueLiveOverride \-v
|
||||||
|
.EE
|
||||||
|
.SS Codex CLI
|
||||||
|
The \f[B]Codex\f[R] override replaces automatic terminal diffs with
|
||||||
|
completed assistant messages.
|
||||||
|
It suppresses tool output, streaming fragments, and redraws.
|
||||||
|
Manual screen review remains available, and typing echo is limited to
|
||||||
|
the composer.
|
||||||
|
Messages are retained in memory even while speech is muted or automatic
|
||||||
|
reading is disabled.
|
||||||
|
Existing lifecycle alerts remain separate from reply reading.
|
||||||
|
Left/Right navigation retains character feedback inside the composer.
|
||||||
|
While Codex is working, the existing activity tone sounds once every
|
||||||
|
four seconds without requiring redraws.
|
||||||
|
It stops for approval/question waits and completion, respects the sound
|
||||||
|
and progress toggles, and remains independent of speech mute.
|
||||||
|
.IP \(bu 2
|
||||||
|
\f[B]Fenrir+1 through Fenrir+9\f[R]
|
||||||
|
.RS 2
|
||||||
|
\f[B]Codex information:\f[R] Recent completed assistant messages, newest
|
||||||
|
first
|
||||||
|
.RE
|
||||||
|
.IP \(bu 2
|
||||||
|
\f[B]Fenrir+0\f[R]
|
||||||
|
.RS 2
|
||||||
|
\f[B]Codex information:\f[R] Working, ready, waiting for approval or an
|
||||||
|
answer, finished, or interrupted
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
Select \f[B]Codex\f[R] with \f[B]Fenrir+A\f[R], type \f[B]c\f[R], then
|
||||||
|
Enter.
|
||||||
|
Select \f[B]Default\f[R] to leave the override.
|
||||||
|
Without its bridge, the override suppresses automatic screen changes and
|
||||||
|
the status shortcut says \f[B]Waiting for Codex bridge\f[R].
|
||||||
|
.PP
|
||||||
|
The optional bridge requires Python 3 and Fenrir remote command control
|
||||||
|
enabled.
|
||||||
|
Merge a command hook invoking
|
||||||
|
\f[CR]python3 /absolute/path/to/fenrir/tools/codex_bridge.py\f[R] into
|
||||||
|
each of these events in \f[CR]\(ti/.codex/hooks.json\f[R]:
|
||||||
|
\f[CR]SessionStart\f[R], \f[CR]UserPromptSubmit\f[R],
|
||||||
|
\f[CR]PermissionRequest\f[R], \f[CR]PostToolUse\f[R], \f[CR]Stop\f[R],
|
||||||
|
\f[CR]Interrupt\f[R], and \f[CR]SessionEnd\f[R].
|
||||||
|
For example, one event entry is:
|
||||||
|
.IP
|
||||||
|
.EX
|
||||||
|
{
|
||||||
|
\(dqhooks\(dq: {
|
||||||
|
\(dqSessionStart\(dq: [{\(dqhooks\(dq: [{\(dqtype\(dq: \(dqcommand\(dq, \(dqcommand\(dq: \(dqpython3 /absolute/path/to/fenrir/tools/codex_bridge.py\(dq, \(dqtimeout\(dq: 3}]}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.EE
|
||||||
|
.PP
|
||||||
|
Preserve existing hooks.
|
||||||
|
Review and trust the added hooks through Codex\(cqs \f[CR]/hooks\f[R]
|
||||||
|
interface; restart or resume Codex if required by the installed version.
|
||||||
|
Starting or resuming a conversation starts a detached bridge follower;
|
||||||
|
submitting a prompt also restarts it if necessary.
|
||||||
|
The bridge never speaks or answers approvals.
|
||||||
|
.PP
|
||||||
|
The follower reads only the transcript path supplied by that
|
||||||
|
conversation\(cqs hook and verifies its session identifier.
|
||||||
|
It accepts completed assistant events, never tool results, reasoning, or
|
||||||
|
streamed deltas.
|
||||||
|
It keeps the nine latest replies in memory and writes only status,
|
||||||
|
conversation identifiers, and lock files to a private runtime directory.
|
||||||
|
Switching conversations replaces the terminal binding; packets from an
|
||||||
|
older conversation cannot overwrite the new history.
|
||||||
|
Existing history is loaded silently on attachment or bridge restart.
|
||||||
|
Long replies are transported in chunks and announced only after
|
||||||
|
assembly; the current per\-message limit is 1 MiB.
|
||||||
|
The worker stops when Codex exits or a \f[CR]SessionEnd\f[R] hook runs.
|
||||||
|
.PP
|
||||||
|
X11 routing requires the same \f[CR]WINDOWID\f[R] as the Fenrir
|
||||||
|
instance; Linux console routing uses Codex\(cqs controlling VT and the
|
||||||
|
reader\(cqs existing authorization.
|
||||||
|
Other windows and consoles do not receive the replies.
|
||||||
|
This local bridge does not forward SSH audio or attach a remote Codex
|
||||||
|
server to a local terminal.
|
||||||
|
.PP
|
||||||
|
The transcript parser was checked against Codex CLI 0.165.0.
|
||||||
|
It uses Codex\(cqs local completed\-event records, rather than a public
|
||||||
|
subscription API; a changed record format may require an update.
|
||||||
|
Status comes from hooks and recorded turn events, not the terminal\(cqs
|
||||||
|
animated activity label.
|
||||||
|
Check \f[B]Fenrir+0\f[R] after resuming.
|
||||||
|
.PP
|
||||||
|
For a private protocol and keyboard test without live speech or Codex
|
||||||
|
requests:
|
||||||
|
.IP
|
||||||
|
.EX
|
||||||
|
go build \-o fenrir ./cmd/fenrir
|
||||||
|
python3 \-m unittest discover \-s tests \-p test_codex_bridge.py
|
||||||
|
xvfb\-run \-a env FENRIR_PRIVATE_X11=1 python3 tests/native_codex.py
|
||||||
|
.EE
|
||||||
|
.PP
|
||||||
|
Real acceptance still needs a Codex reply spoken once after completion,
|
||||||
|
working status on demand, history review, composer typing,
|
||||||
|
approval/question handling, and returning to ordinary reading after
|
||||||
|
choosing Default or exiting Codex.
|
||||||
.SS Clipboard
|
.SS Clipboard
|
||||||
Use review navigation to place two marks around text with
|
Use review navigation to place two marks around text with
|
||||||
\f[B]Fenrir+X\f[R], then press \f[B]Fenrir+C\f[R] to copy it.
|
\f[B]Fenrir+X\f[R], then press \f[B]Fenrir+C\f[R] to copy it.
|
||||||
@@ -306,68 +627,57 @@ In table mode Fenrir+X sets headers instead.
|
|||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+Shift+X\f[R]
|
\f[B]Fenrir+Shift+X\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Read marked text
|
||||||
Action: Read marked text
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+Control+Shift+X\f[R]
|
\f[B]Fenrir+Control+Shift+X\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Remove marks
|
||||||
Action: Remove marks
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+C\f[R]
|
\f[B]Fenrir+C\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Copy marked text
|
||||||
Action: Copy marked text
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+Control+C\f[R]
|
\f[B]Fenrir+Control+C\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Copy last presented text
|
||||||
Action: Copy last presented text
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+Shift+C\f[R]
|
\f[B]Fenrir+Shift+C\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Read selected clipboard
|
||||||
Action: Read selected clipboard
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+Control+Shift+C\f[R]
|
\f[B]Fenrir+Control+Shift+C\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Clear selected clipboard
|
||||||
Action: Clear selected clipboard
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+Home / End\f[R]
|
\f[B]Fenrir+Home / End\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] First / last clipboard
|
||||||
Action: First / last clipboard
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+PageUp / PageDown\f[R]
|
\f[B]Fenrir+PageUp / PageDown\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Previous / next clipboard
|
||||||
Action: Previous / next clipboard
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+V\f[R]
|
\f[B]Fenrir+V\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Paste selected clipboard
|
||||||
Action: Paste selected clipboard
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+F5 / F6\f[R]
|
\f[B]Fenrir+F5 / F6\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Import from / export to file
|
||||||
Action: Import from / export to file
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]Fenrir+F7 / F8\f[R]
|
\f[B]Fenrir+F7 / F8\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Action:\f[R] Import from / export to X clipboard
|
||||||
Action: Import from / export to X clipboard
|
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\f[CR]clipboard.number_of_clipboards\f[R] limits history; the default is
|
\f[CR]clipboard.number_of_clipboards\f[R] limits history; the default is
|
||||||
@@ -442,6 +752,39 @@ Select the driver and theme in Sound settings.
|
|||||||
The ALSA device name is set with \f[CR]presentation.sound.device\f[R] in
|
The ALSA device name is set with \f[CR]presentation.sound.device\f[R] in
|
||||||
the file.
|
the file.
|
||||||
.PP
|
.PP
|
||||||
|
Speech Dispatcher has its own synthesis and audio configuration,
|
||||||
|
separate from Fenrir\(cqs sound cues.
|
||||||
|
For an X11 terminal session, run \f[CR]./fenrir \-x\f[R] as your regular
|
||||||
|
user.
|
||||||
|
With sudo, Fenrir uses \f[CR]SUDO_UID\f[R] to locate the invoking
|
||||||
|
user\(cqs PulseAudio socket.
|
||||||
|
The default sound driver tries the user session, then
|
||||||
|
\f[CR]/tmp/pulse.sock\f[R], then \f[CR]/run/pulse/native\f[R].
|
||||||
|
Set \f[CR]PULSE_SERVER\f[R] to select an explicit server; the sound
|
||||||
|
driver does not read PulseAudio\(cqs \f[CR]client.conf\f[R].
|
||||||
|
The sound service must already be running and accessible to the reader.
|
||||||
|
See Speech synthesizers for Speech Dispatcher addresses and autostart
|
||||||
|
behavior.
|
||||||
|
.PP
|
||||||
|
If root sound needs additional configuration, the checkout includes
|
||||||
|
configure_pulse.sh for PulseAudio and configure_pipewire.sh for
|
||||||
|
PipeWire.
|
||||||
|
Read the appropriate script before running it.
|
||||||
|
Each has a regular\-user part and a root part, and writes audio
|
||||||
|
configuration files.
|
||||||
|
The PulseAudio script replaces the user\(cqs \f[CR]default.pa\f[R] and
|
||||||
|
configures an anonymously accessible socket at
|
||||||
|
\f[CR]/tmp/pulse.sock\f[R].
|
||||||
|
The PipeWire script also changes WirePlumber settings.
|
||||||
|
These scripts change system audio configuration and are only needed when
|
||||||
|
the existing audio setup does not provide the required access.
|
||||||
|
.PP
|
||||||
|
For ALSA, select \f[CR]driver = \(dqalsa\(dq\f[R] under
|
||||||
|
\f[CR][presentation.sound]\f[R] in \f[CR]settings.toml\f[R] and set
|
||||||
|
\f[CR]device\f[R] to the desired PCM name, such as
|
||||||
|
\f[CR]\(dqdefault\(dq\f[R].
|
||||||
|
Driver and device changes apply at the next launch.
|
||||||
|
.PP
|
||||||
Personal themes are searched under
|
Personal themes are searched under
|
||||||
\f[CR]\(ti/.local/stormux/fenrir/sounds/\f[R] before bundled and system
|
\f[CR]\(ti/.local/stormux/fenrir/sounds/\f[R] before bundled and system
|
||||||
themes.
|
themes.
|
||||||
@@ -471,8 +814,8 @@ If default files are absent, Fenrir uses built\-in defaults.
|
|||||||
Python \f[CR]settings.conf\f[R] files are ignored.
|
Python \f[CR]settings.conf\f[R] files are ignored.
|
||||||
Regular users save to their personal TOML file, including when startup
|
Regular users save to their personal TOML file, including when startup
|
||||||
loaded system defaults; root saves to the system file.
|
loaded system defaults; root saves to the system file.
|
||||||
\f[CR]\-\-config PATH\f[R] explicitly selects both the load and save path,
|
\f[CR]\-\-config PATH\f[R] explicitly selects both the load and save
|
||||||
and that file must exist at startup.
|
path, and that file must exist at startup.
|
||||||
.PP
|
.PP
|
||||||
Create a personal settings file and validate it without opening devices:
|
Create a personal settings file and validate it without opening devices:
|
||||||
.IP
|
.IP
|
||||||
@@ -494,6 +837,32 @@ The default driver is \f[CR]speech\-dispatcher\f[R].
|
|||||||
Select its module, language, and voice in Speech settings; empty values
|
Select its module, language, and voice in Speech settings; empty values
|
||||||
use server defaults.
|
use server defaults.
|
||||||
.PP
|
.PP
|
||||||
|
Fenrir uses \f[CR]SPEECHD_ADDRESS\f[R] when set:
|
||||||
|
\f[CR]unix_socket:/absolute/path\f[R] selects a Unix socket, and
|
||||||
|
\f[CR]inet_socket:HOST:PORT\f[R] selects TCP (default host
|
||||||
|
\f[CR]127.0.0.1\f[R], port \f[CR]6560\f[R]).
|
||||||
|
Invalid addresses report an error.
|
||||||
|
Otherwise, \f[CR]SPEECHD_SOCKET\f[R] selects a Unix socket.
|
||||||
|
Without either variable, Fenrir uses
|
||||||
|
\f[CR]$XDG_RUNTIME_DIR/speech\-dispatcher/speechd.sock\f[R], falling
|
||||||
|
back to \f[CR]$XDG_CACHE_HOME/speech\-dispatcher/speechd.sock\f[R] or
|
||||||
|
\f[CR]\(ti/.cache/speech\-dispatcher/speechd.sock\f[R] when the runtime
|
||||||
|
directory is unset.
|
||||||
|
With sudo, the default remains
|
||||||
|
\f[CR]/run/user/$SUDO_UID/speech\-dispatcher/speechd.sock\f[R].
|
||||||
|
Sudo may remove address variables; preserve them explicitly if needed.
|
||||||
|
.PP
|
||||||
|
When opening speech, Fenrir first tries the selected server.
|
||||||
|
If its socket is missing or refuses connections, Fenrir requests
|
||||||
|
\f[CR]speech\-dispatcher \-\-spawn\f[R] and briefly retries.
|
||||||
|
The daemon\(cqs configuration controls whether spawning is allowed.
|
||||||
|
\f[CR]SPEECHD_CMD\f[R] can select another executable.
|
||||||
|
Autostart is limited to Unix sockets and local loopback TCP servers.
|
||||||
|
When sudo changes the account, start Speech Dispatcher as the invoking
|
||||||
|
user first; Fenrir will not launch a root\-owned daemon for that user.
|
||||||
|
Settings discovery never starts a daemon or interrupts the active
|
||||||
|
speaking client.
|
||||||
|
.PP
|
||||||
Hardware driver IDs are \f[CR]dectalk\f[R], \f[CR]dectalk\-usb\f[R],
|
Hardware driver IDs are \f[CR]dectalk\f[R], \f[CR]dectalk\-usb\f[R],
|
||||||
\f[CR]litetalk\f[R], \f[CR]doubletalk\f[R], and \f[CR]tripletalk\f[R].
|
\f[CR]litetalk\f[R], \f[CR]doubletalk\f[R], and \f[CR]tripletalk\f[R].
|
||||||
Serial drivers require \f[CR]presentation.speech.hardware_device\f[R],
|
Serial drivers require \f[CR]presentation.speech.hardware_device\f[R],
|
||||||
@@ -553,6 +922,17 @@ Other supported operations include:
|
|||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[CR]command exportclipboard\f[R]: export the selected clipboard.
|
\f[CR]command exportclipboard\f[R]: export the selected clipboard.
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
|
\f[CR]command application ID\f[R]: select \f[CR]default\f[R],
|
||||||
|
\f[CR]networkmanager\f[R], \f[CR]ninjam\f[R], \f[CR]rogue\f[R], or
|
||||||
|
\f[CR]codex\f[R] for this reader\(cqs active terminal, like Fenrir+A.
|
||||||
|
This requires command remote control.
|
||||||
|
An empty reply means selection succeeded; invalid IDs, busy settings,
|
||||||
|
and restoration failures return an error.
|
||||||
|
Application recognition and profile loading happen later, when the
|
||||||
|
application appears; this command does not launch it.
|
||||||
|
\f[CR]default\f[R] restores ordinary settings.
|
||||||
|
Use a private socket when targeting a particular reader.
|
||||||
|
.IP \(bu 2
|
||||||
\f[CR]command window X1 Y1 X2 Y2\f[R]: set a reading window, using
|
\f[CR]command window X1 Y1 X2 Y2\f[R]: set a reading window, using
|
||||||
zero\-based, inclusive coordinates.
|
zero\-based, inclusive coordinates.
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
@@ -574,89 +954,77 @@ self\-voicing also allows an account logged into the active console.
|
|||||||
Fenrir runs as \f[CR]fenrir [options]\f[R].
|
Fenrir runs as \f[CR]fenrir [options]\f[R].
|
||||||
Use \f[CR]\-\-help\f[R] for the built\-in reference.
|
Use \f[CR]\-\-help\f[R] for the built\-in reference.
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-\-help\f[R]
|
\f[B]\f[CB]\-\-help\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Show usage and options
|
||||||
Purpose: Show usage and options
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-\-version\f[R]
|
\f[B]\f[CB]\-\-version\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Print version and release channel
|
||||||
Purpose: Print version and release channel
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-f\f[R]
|
\f[B]\f[CB]\-f\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Keep console mode in the foreground (always enabled
|
||||||
Purpose: Keep console mode in the foreground (always enabled with
|
with \f[CR]\-x\f[R])
|
||||||
\f[CR]\-x\f[R])
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-x\f[R]
|
\f[B]\f[CB]\-x\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Start a shell inside this X11 terminal
|
||||||
Purpose: Start a shell inside this X11 terminal
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-\-config PATH\f[R]
|
\f[B]\f[CB]\-\-config PATH\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Load a specific TOML settings file
|
||||||
Purpose: Load a specific TOML settings file
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-\-keyboard\-layout NAME_OR_PATH\f[R]
|
\f[B]\f[CB]\-\-keyboard\-layout NAME_OR_PATH\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Select a named layout or TOML file
|
||||||
Purpose: Select a named layout or TOML file
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-\-punctuation\-profile NAME_OR_PATH\f[R]
|
\f[B]\f[CB]\-\-punctuation\-profile NAME_OR_PATH\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Select a punctuation profile
|
||||||
Purpose: Select a punctuation profile
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-\-check\-config\f[R]
|
\f[B]\f[CB]\-\-check\-config\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Validate settings, layout, and punctuation without
|
||||||
Purpose: Validate settings, layout, and punctuation without opening devices
|
opening devices
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-\-write\-config PATH\f[R]
|
\f[B]\f[CB]\-\-write\-config PATH\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Write effective settings to a file and exit
|
||||||
Purpose: Write effective settings to a file and exit
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-\-speech\-driver ID\f[R]
|
\f[B]\f[CB]\-\-speech\-driver ID\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Override the configured speech driver
|
||||||
Purpose: Override the configured speech driver
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-\-speech\-rate NUMBER\f[R]
|
\f[B]\f[CB]\-\-speech\-rate NUMBER\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Override rate, from \-100 to 100
|
||||||
Purpose: Override rate, from \-100 to 100
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-\-speech\-module NAME\f[R]
|
\f[B]\f[CB]\-\-speech\-module NAME\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Select a Speech Dispatcher module
|
||||||
Purpose: Select a Speech Dispatcher module
|
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-\-input\-device PATH\f[R]
|
\f[B]\f[CB]\-\-input\-device PATH\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Select a console keyboard event device; may be
|
||||||
Purpose: Select a console keyboard event device; may be repeated
|
repeated
|
||||||
.RE
|
.RE
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\f[B]\-\-debug\-file PATH\f[R]
|
\f[B]\f[CB]\-\-debug\-file PATH\f[B]\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
\f[B]Purpose:\f[R] Append timing and reader\-decision diagnostics
|
||||||
Purpose: Append timing and reader\-decision diagnostics
|
|
||||||
.RE
|
.RE
|
||||||
.SS Troubleshooting
|
.SS Troubleshooting
|
||||||
.SS Speech or sound is missing
|
.SS Speech or sound is missing
|
||||||
@@ -693,9 +1061,11 @@ problem.
|
|||||||
.SS Documentation maintenance and support
|
.SS Documentation maintenance and support
|
||||||
\f[CR]docs/user.md\f[R] is the shared manual source.
|
\f[CR]docs/user.md\f[R] is the shared manual source.
|
||||||
With Pandoc installed, run \f[CR]./docs/create_manpage.sh\f[R] to
|
With Pandoc installed, run \f[CR]./docs/create_manpage.sh\f[R] to
|
||||||
regenerate \f[CR]docs/user.txt\f[R], \f[CR]docs/fenrir.adoc\f[R], and
|
regenerate \f[CR]docs/user.txt\f[R] and \f[CR]docs/fenrir.1\f[R].
|
||||||
\f[CR]docs/fenrir.1\f[R].
|
|
||||||
The script can run from any working directory.
|
The script can run from any working directory.
|
||||||
|
Edit the Markdown source rather than the generated files.
|
||||||
|
The bundled \f[CR]docs/man_tables.lua\f[R] filter renders man\-page
|
||||||
|
tables as labeled lists for narrow terminals.
|
||||||
.PP
|
.PP
|
||||||
Please review documentation and test instructions for the affected
|
Please review documentation and test instructions for the affected
|
||||||
workflow before submitting a change, as described in the README\(cqs
|
workflow before submitting a change, as described in the README\(cqs
|
||||||
|
|||||||
@@ -1,491 +0,0 @@
|
|||||||
== Fenrir User Manual
|
|
||||||
|
|
||||||
Fenrir is a Linux console screen reader written in Go. It reads Linux
|
|
||||||
text consoles and can run in an X11 terminal as a regular user.
|
|
||||||
|
|
||||||
*Current maintainer:* Storm Dragon +
|
|
||||||
*Original creator:* Chrys (see link:../CREDITS[CREDITS])
|
|
||||||
|
|
||||||
For build requirements and setup, see the link:../README.md[README].
|
|
||||||
|
|
||||||
=== Starting and stopping
|
|
||||||
|
|
||||||
Run these commands from the checkout root after building `fenrir`:
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
# Linux text console, with console and keyboard device access
|
|
||||||
sudo ./fenrir
|
|
||||||
|
|
||||||
# Linux console in the foreground (also use -f with service managers)
|
|
||||||
sudo ./fenrir -f
|
|
||||||
|
|
||||||
# X11 terminal, as your regular user
|
|
||||||
./fenrir -x
|
|
||||||
|
|
||||||
# Either mode can select the laptop layout
|
|
||||||
./fenrir -x --keyboard-layout laptop
|
|
||||||
----
|
|
||||||
|
|
||||||
Console mode starts in the background by default. Add `-f` to keep it in
|
|
||||||
the foreground, including under a service manager. The launcher returns
|
|
||||||
after the reader initializes and reports startup failures in the
|
|
||||||
launching terminal. Use `--debug-file PATH` to retain diagnostics after
|
|
||||||
detaching. Help, version, and configuration-only commands always run in
|
|
||||||
the foreground.
|
|
||||||
|
|
||||||
X11 mode (`-x`) always stays in the foreground because it owns the
|
|
||||||
terminal and its child shell. Press *Fenrir{plus}Q* to quit either mode.
|
|
||||||
Run only one reader on a given Linux console. Separate X11 terminal
|
|
||||||
instances can run at once.
|
|
||||||
|
|
||||||
X11 mode starts a shell in a new PTY. The launching terminal must supply
|
|
||||||
valid `DISPLAY` and `WINDOWID` environment variables. Keyboard
|
|
||||||
interception is scoped to that terminal window; a desktop screen reader
|
|
||||||
can handle other windows.
|
|
||||||
|
|
||||||
Console mode needs access to console devices, keyboard event devices,
|
|
||||||
and `/dev/uinput`. It releases keyboard input on graphical virtual
|
|
||||||
terminals and on text consoles selected in `screen.ignored++_++vts`.
|
|
||||||
|
|
||||||
=== Keyboard layouts and help
|
|
||||||
|
|
||||||
The *Fenrir key* is Insert, Super/Windows, or keypad 0 with NumLock off.
|
|
||||||
Hold it while pressing the other keys in a shortcut. Bare keypad review
|
|
||||||
keys also require NumLock off.
|
|
||||||
|
|
||||||
The desktop layout uses the numeric keypad. The laptop layout uses
|
|
||||||
Fenrir chords on the main keyboard. Select a layout with
|
|
||||||
`--keyboard-layout desktop` or `--keyboard-layout laptop`, or set
|
|
||||||
`keyboard.layout` in the settings file.
|
|
||||||
|
|
||||||
Press *Fenrir{plus}H* or *Fenrir{plus}F1* to enter the tutorial. Command
|
|
||||||
shortcuts are announced and described instead of executed. Up and Down
|
|
||||||
browse commands; Left and Right switch between active actions, unbound
|
|
||||||
actions, and scripts. Space repeats the current item. Escape or
|
|
||||||
Fenrir{plus}F1 exits.
|
|
||||||
|
|
||||||
The complete layouts are
|
|
||||||
link:../config/keyboard/desktop.toml[desktop.toml] and
|
|
||||||
link:../config/keyboard/laptop.toml[laptop.toml].
|
|
||||||
|
|
||||||
=== Screen review
|
|
||||||
|
|
||||||
Review moves Fenrir’s reading position without moving the application’s
|
|
||||||
cursor. Return to the application cursor with the Follow cursor
|
|
||||||
shortcut. By default, application cursor movement or a screen change
|
|
||||||
also leaves review.
|
|
||||||
|
|
||||||
[width="100%",cols="34%,33%,33%",options="header",]
|
|
||||||
|===
|
|
||||||
|Action |Desktop |Laptop
|
|
||||||
|Previous / current / next line |Keypad 7 / 8 / 9 |Fenrir{plus}U / I / O
|
|
||||||
|
|
||||||
|Previous / current / next word |Keypad 4 / 5 / 6 |Fenrir{plus}J / K / L
|
|
||||||
|
|
||||||
|Previous / current / next character |Keypad 1 / 2 / 3 |Fenrir{plus}M /
|
|
||||||
Comma / Period
|
|
||||||
|
|
||||||
|Top / bottom of screen |Fenrir{plus}Keypad 7 / 9
|
|
||||||
|Fenrir{plus}Shift{plus}U / O
|
|
||||||
|
|
||||||
|Line start / end |Fenrir{plus}Keypad 4 / 6 |Fenrir{plus}Shift{plus}J /
|
|
||||||
L
|
|
||||||
|
|
||||||
|First / last text on line |Fenrir{plus}Keypad 1 / 3
|
|
||||||
|Fenrir{plus}Control{plus}J / L
|
|
||||||
|
|
||||||
|Read screen |Fenrir{plus}Keypad 5 |Fenrir{plus}Shift{plus}K
|
|
||||||
|
|
||||||
|Screen before / after cursor |Fenrir{plus}Keypad 8 / 2
|
|
||||||
|Fenrir{plus}Shift{plus}I / Comma
|
|
||||||
|
|
||||||
|Character above / below |Fenrir{plus}Control{plus}Keypad 8 / 2
|
|
||||||
|Fenrir{plus}Control{plus}I / Comma
|
|
||||||
|
|
||||||
|Follow cursor |Fenrir{plus}Keypad Period |Fenrir{plus}Slash
|
|
||||||
|
|
||||||
|Review position |Keypad Period |Fenrir{plus}Shift{plus}Period
|
|
||||||
|===
|
|
||||||
|
|
||||||
Press the current-line or current-word shortcut twice quickly to spell
|
|
||||||
the text, or three times for phonetic reading. Press the
|
|
||||||
current-character shortcut twice for its phonetic name. The default
|
|
||||||
interval between presses is 200 ms;
|
|
||||||
`keyboard.multi++_++press++_++timeout++_++ms` changes it at launch.
|
|
||||||
|
|
||||||
=== Tracking modes
|
|
||||||
|
|
||||||
Cycle through *cursor*, *table*, and *highlight* with
|
|
||||||
*Fenrir{plus}Keypad Asterisk* on desktop or *Fenrir{plus}Y* on laptop.
|
|
||||||
The startup selection is `reading.mode`.
|
|
||||||
|
|
||||||
* *Cursor*: follows application cursor movement.
|
|
||||||
* *Table*: treats delimited or space-aligned text as cells.
|
|
||||||
* *Highlight*: follows changes to highlighted text, such as menu
|
|
||||||
selections.
|
|
||||||
|
|
||||||
In table mode, word navigation moves between cells, line start/end moves
|
|
||||||
to the first/last cell, and first/last text moves to the first/last
|
|
||||||
character in the current cell. Place review on a header row and press
|
|
||||||
*Fenrir{plus}X* to use its cells as column headers. Outside table mode,
|
|
||||||
Fenrir{plus}X places a text-selection mark.
|
|
||||||
|
|
||||||
=== Speech and automatic reading
|
|
||||||
|
|
||||||
* *Control* interrupts speech.
|
|
||||||
* *Fenrir{plus}F4* toggles mute.
|
|
||||||
* *Keypad Enter* on desktop temporarily silences speech. Speech can
|
|
||||||
return on the next keypress or a newly recognized prompt or completion.
|
|
||||||
* *Fenrir{plus}Keypad Enter* on desktop, or *Fenrir{plus}Enter* on
|
|
||||||
laptop, toggles automatic reading of new text.
|
|
||||||
* *Fenrir{plus}Backspace* passes the next key through to the
|
|
||||||
application.
|
|
||||||
|
|
||||||
Character echo, word echo, and cursor echo can be configured separately.
|
|
||||||
Punctuation levels are `none`, `some`, `most`, and `all`. Character
|
|
||||||
review still names punctuation. Capital indicators, emoticons,
|
|
||||||
repeated-symbol summaries, indentation feedback, and attribute feedback
|
|
||||||
are configurable in Reading.
|
|
||||||
|
|
||||||
*Fenrir{plus}T* announces the time; press twice quickly for the date.
|
|
||||||
*Fenrir{plus}Shift{plus}V* announces the Fenrir version.
|
|
||||||
|
|
||||||
=== Fenrir Menu and quick settings
|
|
||||||
|
|
||||||
Press *Fenrir{plus}F* to open the Fenrir Menu. It contains settings tabs
|
|
||||||
for presentation, speech, sound, reading, keyboard, internal UI, clipboard, and other
|
|
||||||
options. The form captures its navigation keys until it closes.
|
|
||||||
|
|
||||||
* At the tab selector, use arrows to choose a tab.
|
|
||||||
* Tab and Shift{plus}Tab move between controls and the tab selector.
|
|
||||||
* Space or Enter toggles a checkbox.
|
|
||||||
* Arrows change list selections and numeric values.
|
|
||||||
* Activate *OK* to save, or *Cancel* or Escape to discard the form’s
|
|
||||||
changes.
|
|
||||||
|
|
||||||
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. Sound
|
|
||||||
volume is between 0.0 and 1.0. Backend, device, keyboard layout, sound
|
|
||||||
theme, and other launch-only settings take effect on the next start.
|
|
||||||
|
|
||||||
The *Internal UI* tab controls speech in Fenrir’s own menus and dialogs.
|
|
||||||
*Announce grid row and column* and *Announce item position* are
|
|
||||||
independent checkboxes, both enabled by default. Disable coordinates to
|
|
||||||
omit “row 1, column 2”; disable item position to omit “2 of 20”. Item
|
|
||||||
names and grid navigation remain available with both disabled. Saved
|
|
||||||
changes apply immediately to Emoji and Spellcheck grids and persist
|
|
||||||
across launches. These are global settings, so this tab is omitted from
|
|
||||||
application settings. The TOML keys are
|
|
||||||
`internal++_++ui.announce++_++grid++_++coordinates` and
|
|
||||||
`internal++_++ui.announce++_++item++_++position`.
|
|
||||||
|
|
||||||
Settings saves use mode `644` for the standard system settings file at
|
|
||||||
`/etc/fenrirscreenreader/settings/settings.toml`, so other users can
|
|
||||||
read it as a startup fallback. Personal settings and application
|
|
||||||
profiles use mode `600`.
|
|
||||||
|
|
||||||
Quick settings work without opening the form:
|
|
||||||
|
|
||||||
[cols=",",options="header",]
|
|
||||||
|===
|
|
||||||
|Shortcut |Action
|
|
||||||
|Fenrir{plus}Space |Announce current setting
|
|
||||||
|Fenrir{plus}Left / Right |Previous / next setting
|
|
||||||
|Fenrir{plus}Control{plus}Left / Right |Previous / next category
|
|
||||||
|Fenrir{plus}Up / Down |Change value
|
|
||||||
|Fenrir{plus}Control{plus}S |Save settings
|
|
||||||
|===
|
|
||||||
|
|
||||||
Quick changes apply to the current session. Save to retain them for
|
|
||||||
future launches. Session controls such as mute and temporary silence are
|
|
||||||
separate from saved startup preferences.
|
|
||||||
|
|
||||||
=== Clipboard
|
|
||||||
|
|
||||||
Use review navigation to place two marks around text with
|
|
||||||
*Fenrir{plus}X*, then press *Fenrir{plus}C* to copy it. In table mode
|
|
||||||
Fenrir{plus}X sets headers instead.
|
|
||||||
|
|
||||||
[cols=",",options="header",]
|
|
||||||
|===
|
|
||||||
|Shortcut |Action
|
|
||||||
|Fenrir{plus}Shift{plus}X |Read marked text
|
|
||||||
|Fenrir{plus}Control{plus}Shift{plus}X |Remove marks
|
|
||||||
|Fenrir{plus}C |Copy marked text
|
|
||||||
|Fenrir{plus}Control{plus}C |Copy last presented text
|
|
||||||
|Fenrir{plus}Shift{plus}C |Read selected clipboard
|
|
||||||
|Fenrir{plus}Control{plus}Shift{plus}C |Clear selected clipboard
|
|
||||||
|Fenrir{plus}Home / End |First / last clipboard
|
|
||||||
|Fenrir{plus}PageUp / PageDown |Previous / next clipboard
|
|
||||||
|Fenrir{plus}V |Paste selected clipboard
|
|
||||||
|Fenrir{plus}F5 / F6 |Import from / export to file
|
|
||||||
|Fenrir{plus}F7 / F8 |Import from / export to X clipboard
|
|
||||||
|===
|
|
||||||
|
|
||||||
`clipboard.number++_++of++_++clipboards` limits history; the default is
|
|
||||||
200. `clipboard.export++_++path` selects the import/export file,
|
|
||||||
initially `/tmp/fenrirClipboard`. `clipboard.sync` enables automatic X
|
|
||||||
clipboard synchronization, which requires `xclip` and access to the X
|
|
||||||
display.
|
|
||||||
|
|
||||||
Persistent history is optional and off by default. Set
|
|
||||||
`clipboard.persistent` to retain unencrypted history across launches.
|
|
||||||
Terminal sessions use `~/.local/state/fenrir/clipboard/terminal.json`;
|
|
||||||
console sessions use `/var/lib/fenrir/clipboard/tty.json`. Same-user
|
|
||||||
readers of the same mode share persistent history.
|
|
||||||
|
|
||||||
=== Spell checking and emoji
|
|
||||||
|
|
||||||
Automatic spell checking uses Enchant 2 and a dictionary matching the
|
|
||||||
session language. Reading settings control word repetition, spoken
|
|
||||||
misspelling feedback, and misspelling sounds.
|
|
||||||
|
|
||||||
Press *Fenrir{plus}S* to open the Spellcheck Menu for the current word.
|
|
||||||
The Suggestions tab lets you edit the word and choose a suggested
|
|
||||||
spelling. The Exceptions tab lets you add words, remove selected entries
|
|
||||||
with Delete, and undo a removal. Selecting a suggestion copies it to
|
|
||||||
Fenrir’s clipboard; paste it with Fenrir{plus}V.
|
|
||||||
|
|
||||||
Press *Fenrir{plus}Control{plus}E* to open the Emoji Menu. Choose a
|
|
||||||
category at the tab selector, then Tab to the emoji grid. Arrows
|
|
||||||
navigate, typing filters by name prefix, and Control{plus}Backspace
|
|
||||||
clears the filter. Enter copies the selected emoji to Fenrir’s
|
|
||||||
clipboard. Escape closes the menu.
|
|
||||||
|
|
||||||
=== Reading windows and live regions
|
|
||||||
|
|
||||||
Reading regions belong to the current terminal and last for the reader
|
|
||||||
session. A reading window restricts automatic reading to a rectangle.
|
|
||||||
Live regions exclude changing areas from automatic speech while allowing
|
|
||||||
explicit reading and progress monitoring.
|
|
||||||
|
|
||||||
Outside table mode, place two marks with *Fenrir{plus}X* to define
|
|
||||||
opposite corners. Press *Fenrir{plus}Keypad Slash* on desktop or
|
|
||||||
*Fenrir{plus}Control{plus}8* on laptop to set a reading window. Press
|
|
||||||
the shortcut twice quickly to clear it.
|
|
||||||
|
|
||||||
To create a live region, place one mark for the rest of that line, or
|
|
||||||
two marks for a rectangle, then press *Fenrir{plus}B*. Fenrir assigns
|
|
||||||
the first free slot, up to ten. Region creation clears the marks.
|
|
||||||
|
|
||||||
* *Fenrir{plus}1* through *Fenrir{plus}0* read live regions 1 through
|
|
||||||
10.
|
|
||||||
* *Fenrir{plus}Shift{plus}1* through *Fenrir{plus}Shift{plus}0* clear
|
|
||||||
individual live regions.
|
|
||||||
* *Fenrir{plus}Shift{plus}B* lists the current reading regions.
|
|
||||||
* *Fenrir{plus}Control{plus}B* clears all live regions.
|
|
||||||
* *Fenrir{plus}Control{plus}Shift{plus}B* clears both the reading window
|
|
||||||
and live regions.
|
|
||||||
|
|
||||||
=== Sound and progress
|
|
||||||
|
|
||||||
Sound output uses `pulse` for PulseAudio or PipeWire’s PulseAudio
|
|
||||||
service, or `alsa` for an ALSA PCM device. Select the driver and theme
|
|
||||||
in Sound settings. The ALSA device name is set with
|
|
||||||
`presentation.sound.device` in the file.
|
|
||||||
|
|
||||||
Personal themes are searched under `~/.local/stormux/fenrir/sounds/`
|
|
||||||
before bundled and system themes. A theme contains WAV files and
|
|
||||||
`soundicons.toml`.
|
|
||||||
|
|
||||||
Progress tones are controlled separately from speech and automatic
|
|
||||||
reading. Press *Keypad Plus* on desktop or *Fenrir{plus}Shift{plus}P* on
|
|
||||||
laptop to toggle them. Fenrir recognizes percentages, fractions,
|
|
||||||
progress bars, and activity indicators; tones rise with progress.
|
|
||||||
Startup behavior is set by `presentation.progress.enabled`.
|
|
||||||
|
|
||||||
=== Configuration files
|
|
||||||
|
|
||||||
Settings are TOML. The annotated
|
|
||||||
link:../config/settings/settings.toml[settings.toml] lists all available
|
|
||||||
options. Fenrir loads one settings file rather than merging files.
|
|
||||||
|
|
||||||
* Regular users: first
|
|
||||||
`~/.local/share/stormux/fenrirscreenreader/settings/settings.toml`, then
|
|
||||||
`/etc/fenrirscreenreader/settings/settings.toml`.
|
|
||||||
* Root: `/etc/fenrirscreenreader/settings/settings.toml`.
|
|
||||||
* `--config PATH`: use that file explicitly.
|
|
||||||
|
|
||||||
If default files are absent, Fenrir uses built-in defaults. An
|
|
||||||
explicitly selected file must exist. Saving targets the selected file;
|
|
||||||
if startup used built-in defaults, saving creates the first default path
|
|
||||||
for that account.
|
|
||||||
|
|
||||||
Create a personal settings file and validate it without opening devices:
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
./fenrir --write-config ~/.local/share/stormux/fenrirscreenreader/settings/settings.toml
|
|
||||||
./fenrir --config ~/.local/share/stormux/fenrirscreenreader/settings/settings.toml --check-config
|
|
||||||
----
|
|
||||||
|
|
||||||
Named keyboard layouts are searched in the regular user’s
|
|
||||||
`~/.local/share/stormux/fenrirscreenreader/keyboard/`, then
|
|
||||||
`/etc/fenrirscreenreader/keyboard/`, then `config/keyboard/` beside the
|
|
||||||
binary. Root searches the system and bundled locations. An explicit TOML
|
|
||||||
path selects one file. Custom layouts replace the complete layout; they
|
|
||||||
are not overlays. See the link:../config/keyboard/Readme.md[keyboard
|
|
||||||
guide] for an example.
|
|
||||||
|
|
||||||
=== Speech synthesizers
|
|
||||||
|
|
||||||
The default driver is `speech-dispatcher`. Select its module, language,
|
|
||||||
and voice in Speech settings; empty values use server defaults.
|
|
||||||
|
|
||||||
Hardware driver IDs are `dectalk`, `dectalk-usb`, `litetalk`,
|
|
||||||
`doubletalk`, and `tripletalk`. Serial drivers require
|
|
||||||
`presentation.speech.hardware++_++device`, for example `/dev/ttyUSB0`,
|
|
||||||
and default to 9600 baud when `hardware++_++baud++_++rate = 0`.
|
|
||||||
DoubleTalk support targets the external LT device. TripleTalk USB
|
|
||||||
devices need to expose a serial tty.
|
|
||||||
|
|
||||||
Native `dectalk-usb` uses libusb 1.0 and ignores serial settings. The
|
|
||||||
process needs access to the device. The Speech form’s *Test synthesizer*
|
|
||||||
button previews hardware choices before saving. Driver and port changes
|
|
||||||
apply at launch.
|
|
||||||
|
|
||||||
=== Script shortcuts
|
|
||||||
|
|
||||||
Fenrir searches `~/.local/stormux/fenrir/`, the configured
|
|
||||||
`general.script++_++path` (default
|
|
||||||
`/usr/share/fenrirscreenreader/scripts`), and the bundled
|
|
||||||
`config/scripts/` beside the binary. Earlier directories take priority.
|
|
||||||
|
|
||||||
A filename such as `example++__++-++__++key++_++y.sh` assigns the script
|
|
||||||
key plus Y. The script key defaults to Compose and is configured by
|
|
||||||
`general.script++_++keys`. Scripts must be executable to run. Fenrir
|
|
||||||
invokes them directly and passes the current account name as the first
|
|
||||||
argument. Commands appear in the tutorial’s script list.
|
|
||||||
|
|
||||||
=== Remote control
|
|
||||||
|
|
||||||
Unix socket remote control is enabled by default. The standard socket is
|
|
||||||
`/tmp/fenrirscreenreader-daemon.sock`, and instances also have private
|
|
||||||
sockets `/tmp/fenrirscreenreader-++<++pid++>++.sock`. Set
|
|
||||||
`remote.socket++_++file` for a custom socket.
|
|
||||||
|
|
||||||
Use `ls` to discover instances. Use a private socket to address one
|
|
||||||
reader:
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
|
|
||||||
echo "command say Hello" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
|
|
||||||
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
|
|
||||||
echo "setting set reading#mode=highlight" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
|
|
||||||
----
|
|
||||||
|
|
||||||
Remote requests use `section++#++setting=value` syntax independently of
|
|
||||||
TOML. Remote speech rate, pitch, and volume use *0.0 to 1.0*, mapped to
|
|
||||||
the -100 to 100 scale used in settings files and menus. For example,
|
|
||||||
`speech++#++rate=0.8` selects rate 60.
|
|
||||||
|
|
||||||
Other supported operations include:
|
|
||||||
|
|
||||||
* `command tempdisablespeech`: temporarily silence speech.
|
|
||||||
* `command clipboard TEXT`: add text to the clipboard.
|
|
||||||
* `command exportclipboard`: export the selected clipboard.
|
|
||||||
* `command window X1 Y1 X2 Y2`: set a reading window, using zero-based,
|
|
||||||
inclusive coordinates.
|
|
||||||
* `command resetwindow`: clear the window.
|
|
||||||
* `setting save`: save settings.
|
|
||||||
* `setting reset`: clear quick and remote overrides back to the last
|
|
||||||
loaded or successfully saved settings.
|
|
||||||
* `command quitapplication`: quit Fenrir.
|
|
||||||
|
|
||||||
Set `remote.enabled = false` to disable the service. Command and setting
|
|
||||||
requests have separate switches, `enable++_++command++_++remote` and
|
|
||||||
`enable++_++settings++_++remote`. Requests are authorized against the
|
|
||||||
caller’s account; console self-voicing also allows an account logged
|
|
||||||
into the active console.
|
|
||||||
|
|
||||||
=== Command-line options
|
|
||||||
|
|
||||||
Fenrir runs as `fenrir ++[++options++]++`. Use `--help` for the built-in
|
|
||||||
reference.
|
|
||||||
|
|
||||||
[width="100%",cols="50%,50%",options="header",]
|
|
||||||
|===
|
|
||||||
|Option |Purpose
|
|
||||||
|`--help` |Show usage and options
|
|
||||||
|
|
||||||
|`--version` |Print version and release channel
|
|
||||||
|
|
||||||
|`-f` |Keep console mode in the foreground (always enabled with `-x`)
|
|
||||||
|
|
||||||
|`-x` |Start a shell inside this X11 terminal
|
|
||||||
|
|
||||||
|`--config PATH` |Load a specific TOML settings file
|
|
||||||
|
|
||||||
|`--keyboard-layout NAME++_++OR++_++PATH` |Select a named layout or TOML
|
|
||||||
file
|
|
||||||
|
|
||||||
|`--punctuation-profile NAME++_++OR++_++PATH` |Select a punctuation
|
|
||||||
profile
|
|
||||||
|
|
||||||
|`--check-config` |Validate settings, layout, and punctuation without
|
|
||||||
opening devices
|
|
||||||
|
|
||||||
|`--write-config PATH` |Write effective settings to a file and exit
|
|
||||||
|
|
||||||
|`--speech-driver ID` |Override the configured speech driver
|
|
||||||
|
|
||||||
|`--speech-rate NUMBER` |Override rate, from -100 to 100
|
|
||||||
|
|
||||||
|`--speech-module NAME` |Select a Speech Dispatcher module
|
|
||||||
|
|
||||||
|`--input-device PATH` |Select a console keyboard event device; may be
|
|
||||||
repeated
|
|
||||||
|
|
||||||
|`--debug-file PATH` |Append timing and reader-decision diagnostics
|
|
||||||
|===
|
|
||||||
|
|
||||||
=== Troubleshooting
|
|
||||||
|
|
||||||
==== Speech or sound is missing
|
|
||||||
|
|
||||||
Check that speech and sound are enabled, and that the selected backend
|
|
||||||
is available. Speech Dispatcher needs a configured synthesizer. Pulse
|
|
||||||
output needs access to a running PulseAudio service, including
|
|
||||||
PipeWire’s PulseAudio service; ALSA needs access to its selected PCM
|
|
||||||
device. Root console sessions may need separate audio configuration; see
|
|
||||||
the README’s setup section.
|
|
||||||
|
|
||||||
For hardware speech, check the driver, device path, device permissions,
|
|
||||||
and serial baud rate. Use *Test synthesizer* before saving a new
|
|
||||||
hardware selection.
|
|
||||||
|
|
||||||
==== Keyboard input or X11 mode fails
|
|
||||||
|
|
||||||
In console mode, check access to keyboard event devices and
|
|
||||||
`/dev/uinput`. In X11 mode, check `DISPLAY`, `WINDOWID`, and competing
|
|
||||||
grabs on the terminal. Use NumLock off for bare keypad review. A
|
|
||||||
configured `keyboard.devices` list or `--input-device` applies to
|
|
||||||
console mode and cannot be used with `-x`.
|
|
||||||
|
|
||||||
==== Check configuration and collect diagnostics
|
|
||||||
|
|
||||||
Validate an edited settings file with `--config PATH --check-config`.
|
|
||||||
For reader diagnostics, add `--debug-file /tmp/fenrir-debug.log` to the
|
|
||||||
launch command. This appends timing and reader decisions without screen
|
|
||||||
text or key values. `./fenrir --version` identifies the build when
|
|
||||||
reporting a problem.
|
|
||||||
|
|
||||||
=== Documentation maintenance and support
|
|
||||||
|
|
||||||
`docs/user.md` is the shared manual source. With Pandoc installed, run
|
|
||||||
`./docs/create++_++manpage.sh` to regenerate `docs/user.txt`,
|
|
||||||
`docs/fenrir.adoc`, and `docs/fenrir.1`. The script can run from any
|
|
||||||
working directory.
|
|
||||||
|
|
||||||
Please review documentation and test instructions for the affected
|
|
||||||
workflow before submitting a change, as described in the README’s
|
|
||||||
contribution policy.
|
|
||||||
|
|
||||||
* https://git.stormux.org/storm/fenrir[Project repository and issue
|
|
||||||
tracker]
|
|
||||||
* https://git.stormux.org/storm/fenrir/wiki[Fenrir Wiki]
|
|
||||||
* Email list: `stormux{plus}subscribe@groups.io`, with the subject
|
|
||||||
`subscribe`.
|
|
||||||
* IRC: `irc.stormux.org`, channel `++#++stormux`.
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
-- Render manual tables as labeled lists so shortcuts remain readable at narrow
|
||||||
|
-- terminal widths. Keep cell contents as Pandoc elements to preserve formatting.
|
||||||
|
function Table(manualTable)
|
||||||
|
local columnNames = {}
|
||||||
|
local headerRow = manualTable.head.rows[1]
|
||||||
|
if headerRow then
|
||||||
|
for columnIndex, cell in ipairs(headerRow.cells) do
|
||||||
|
columnNames[columnIndex] = pandoc.utils.stringify(cell.contents)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local listItems = {}
|
||||||
|
local function append_row(row)
|
||||||
|
local itemBlocks = pandoc.List()
|
||||||
|
for columnIndex, cell in ipairs(row.cells) do
|
||||||
|
local cellBlocks = cell.contents:clone()
|
||||||
|
if columnIndex == 1 then
|
||||||
|
cellBlocks = cellBlocks:walk({
|
||||||
|
Plain = function(block)
|
||||||
|
return pandoc.Para({pandoc.Strong(block.content)})
|
||||||
|
end,
|
||||||
|
Para = function(block)
|
||||||
|
return pandoc.Para({pandoc.Strong(block.content)})
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
elseif columnNames[columnIndex] then
|
||||||
|
local label = pandoc.Strong({pandoc.Str(columnNames[columnIndex] .. ":")})
|
||||||
|
local firstBlock = cellBlocks[1]
|
||||||
|
if firstBlock and (firstBlock.t == "Plain" or firstBlock.t == "Para") then
|
||||||
|
firstBlock.content:insert(1, pandoc.Space())
|
||||||
|
firstBlock.content:insert(1, label)
|
||||||
|
else
|
||||||
|
cellBlocks:insert(1, pandoc.Para({label}))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
itemBlocks:extend(cellBlocks)
|
||||||
|
end
|
||||||
|
listItems[#listItems + 1] = itemBlocks
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, body in ipairs(manualTable.bodies) do
|
||||||
|
for _, row in ipairs(body.head) do
|
||||||
|
append_row(row)
|
||||||
|
end
|
||||||
|
for _, row in ipairs(body.body) do
|
||||||
|
append_row(row)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, row in ipairs(manualTable.foot.rows) do
|
||||||
|
append_row(row)
|
||||||
|
end
|
||||||
|
return pandoc.BulletList(listItems)
|
||||||
|
end
|
||||||
+190
-164
@@ -8,6 +8,168 @@ consoles and can run in an X11 terminal as a regular user.
|
|||||||
|
|
||||||
For build requirements and setup, see the [README](../README.md).
|
For build requirements and setup, see the [README](../README.md).
|
||||||
|
|
||||||
|
## Starting and stopping
|
||||||
|
|
||||||
|
Run these commands from the checkout root after building `fenrir`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Linux text console, with console and keyboard device access
|
||||||
|
sudo ./fenrir
|
||||||
|
|
||||||
|
# Linux console in the foreground (also use -f with service managers)
|
||||||
|
sudo ./fenrir -f
|
||||||
|
|
||||||
|
# X11 terminal, as your regular user
|
||||||
|
./fenrir -x
|
||||||
|
|
||||||
|
# Either mode can select the laptop layout
|
||||||
|
./fenrir -x --keyboard-layout laptop
|
||||||
|
```
|
||||||
|
|
||||||
|
Console mode starts in the background by default. Add `-f` to keep it in the
|
||||||
|
foreground, including under a service manager. The launcher returns after the
|
||||||
|
reader initializes and reports startup failures in the launching terminal.
|
||||||
|
Use `--debug-file PATH` to retain diagnostics after detaching. Help, version,
|
||||||
|
and configuration-only commands always run in the foreground.
|
||||||
|
|
||||||
|
X11 mode (`-x`) always stays in the foreground because it owns the terminal
|
||||||
|
and its child shell. Press **Fenrir+Q** to quit either mode. Run only one
|
||||||
|
reader on a given Linux console. Separate X11 terminal instances can run at
|
||||||
|
once.
|
||||||
|
|
||||||
|
X11 mode starts a shell in a new PTY. The launching terminal must supply valid
|
||||||
|
`DISPLAY` and `WINDOWID` environment variables. Keyboard interception is scoped
|
||||||
|
to that terminal window; a desktop screen reader can handle other windows.
|
||||||
|
|
||||||
|
Console mode needs access to console devices, keyboard event devices, and
|
||||||
|
`/dev/uinput`. It releases keyboard input on graphical virtual terminals and
|
||||||
|
on text consoles selected in `screen.ignored_vts`.
|
||||||
|
|
||||||
|
## Keyboard layouts and help
|
||||||
|
|
||||||
|
The **Fenrir key** is Insert, Super/Windows, or keypad 0 with NumLock off.
|
||||||
|
Hold it while pressing the other keys in a shortcut. Bare keypad review keys
|
||||||
|
also require NumLock off.
|
||||||
|
|
||||||
|
The desktop layout uses the numeric keypad. The laptop layout uses Fenrir
|
||||||
|
chords on the main keyboard. Select a layout with `--keyboard-layout desktop`
|
||||||
|
or `--keyboard-layout laptop`, or set `keyboard.layout` in the settings file.
|
||||||
|
|
||||||
|
Press **Fenrir+H** or **Fenrir+F1** to enter the tutorial. Command shortcuts are
|
||||||
|
announced and described instead of executed. Up and Down browse commands;
|
||||||
|
Left and Right switch between active actions, unbound actions, and scripts.
|
||||||
|
Space repeats the current item. Escape or Fenrir+F1 exits.
|
||||||
|
|
||||||
|
The complete layouts are [desktop.toml](../config/keyboard/desktop.toml) and
|
||||||
|
[laptop.toml](../config/keyboard/laptop.toml).
|
||||||
|
|
||||||
|
## Screen review
|
||||||
|
|
||||||
|
Review moves Fenrir's reading position without moving the application's cursor.
|
||||||
|
Return to the application cursor with the Follow cursor shortcut. By default,
|
||||||
|
application cursor movement or a screen change also leaves review.
|
||||||
|
|
||||||
|
| 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 |
|
||||||
|
| Top / bottom of screen | Fenrir+Keypad 7 / 9 | Fenrir+Shift+U / O |
|
||||||
|
| Line start / end | Fenrir+Keypad 4 / 6 | Fenrir+Shift+J / L |
|
||||||
|
| First / last text on line | Fenrir+Keypad 1 / 3 | Fenrir+Control+J / L |
|
||||||
|
| Read screen | Fenrir+Keypad 5 | Fenrir+Shift+K |
|
||||||
|
| Screen before / after cursor | Fenrir+Keypad 8 / 2 | Fenrir+Shift+I / Comma |
|
||||||
|
| Character above / below | Fenrir+Control+Keypad 8 / 2 | Fenrir+Control+I / Comma |
|
||||||
|
| Follow cursor | Fenrir+Keypad Period | Fenrir+Slash |
|
||||||
|
| Review position | Keypad Period | Fenrir+Shift+Period |
|
||||||
|
|
||||||
|
Press the current-line or current-word shortcut twice quickly to spell the
|
||||||
|
text, or three times for phonetic reading. Press the current-character shortcut
|
||||||
|
twice for its phonetic name. The default interval between presses is 200 ms;
|
||||||
|
`keyboard.multi_press_timeout_ms` changes it at launch.
|
||||||
|
|
||||||
|
## Tracking modes
|
||||||
|
|
||||||
|
Cycle through **cursor**, **table**, and **highlight** with
|
||||||
|
**Fenrir+Keypad Asterisk** on desktop or **Fenrir+Y** on laptop.
|
||||||
|
The startup selection is `reading.mode`.
|
||||||
|
|
||||||
|
- **Cursor**: follows application cursor movement.
|
||||||
|
- **Table**: treats delimited or space-aligned text as cells.
|
||||||
|
- **Highlight**: follows changes to highlighted text, such as menu selections.
|
||||||
|
|
||||||
|
In table mode, word navigation moves between cells, line start/end moves to the
|
||||||
|
first/last cell, and first/last text moves to the first/last character in the
|
||||||
|
current cell. Place review on a header row and press **Fenrir+X** to use its
|
||||||
|
cells as column headers. Outside table mode, Fenrir+X places a text-selection
|
||||||
|
mark.
|
||||||
|
|
||||||
|
## Speech and automatic reading
|
||||||
|
|
||||||
|
- **Control** interrupts speech.
|
||||||
|
- **Fenrir+F4** toggles mute.
|
||||||
|
- **Keypad Enter** on desktop temporarily silences speech. Speech can return on
|
||||||
|
the next keypress or a newly recognized prompt or completion.
|
||||||
|
- **Fenrir+Keypad Enter** on desktop, or **Fenrir+Enter** on laptop, toggles
|
||||||
|
automatic reading of new text.
|
||||||
|
- **Fenrir+Backspace** passes the next key through to the application.
|
||||||
|
|
||||||
|
Character echo, word echo, and cursor echo can be configured separately.
|
||||||
|
Punctuation levels are `none`, `some`, `most`, and `all`. At `some` and `most`,
|
||||||
|
punctuation inside words, URLs, email addresses, and filenames is also named.
|
||||||
|
Apostrophes within words and single numeric separators such as those in `3.14`,
|
||||||
|
`1,000`, and `12:30` follow the selected level. Sentence punctuation follows the
|
||||||
|
selected level too. Character review always names punctuation.
|
||||||
|
Capital indicators, emoticons, repeated-symbol summaries,
|
||||||
|
indentation feedback, and attribute feedback are configurable in Reading.
|
||||||
|
|
||||||
|
**Fenrir+T** announces the time; press twice quickly for the date.
|
||||||
|
**Fenrir+Shift+V** announces the Fenrir version.
|
||||||
|
|
||||||
|
## Fenrir Menu and quick settings
|
||||||
|
|
||||||
|
Press **Fenrir+F** to open the Fenrir Menu. It contains settings tabs for
|
||||||
|
presentation, speech, sound, reading, keyboard, internal UI, clipboard, and other options.
|
||||||
|
The form captures its navigation keys until it closes.
|
||||||
|
|
||||||
|
- At the tab selector, use arrows to choose a tab.
|
||||||
|
- Tab and Shift+Tab move between controls and the tab selector.
|
||||||
|
- Space or Enter toggles a checkbox.
|
||||||
|
- Arrows change list selections and numeric values.
|
||||||
|
- Activate **OK** to save, or **Cancel** or Escape to discard the form's changes.
|
||||||
|
|
||||||
|
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. Sound volume is
|
||||||
|
between 0.0 and 1.0. Backend, device, keyboard layout, sound theme, and other
|
||||||
|
launch-only settings take effect on the next start.
|
||||||
|
|
||||||
|
The **Internal UI** tab controls speech in Fenrir's own menus and dialogs.
|
||||||
|
**Announce grid row and column** and **Announce item position** are independent
|
||||||
|
checkboxes, both enabled by default. Disable coordinates to omit “row 1, column 2”;
|
||||||
|
disable item position to omit “2 of 20”. Item names and grid navigation remain
|
||||||
|
available with both disabled. Saved changes apply immediately to Emoji and
|
||||||
|
Spellcheck grids and persist across launches. These are global settings, so this
|
||||||
|
tab is omitted from application settings. The TOML keys are
|
||||||
|
`internal_ui.announce_grid_coordinates` and `internal_ui.announce_item_position`.
|
||||||
|
|
||||||
|
Settings saves use mode `644` for the standard system settings file at
|
||||||
|
`/etc/fenrirscreenreader/settings/settings.toml`, so other users can read it as a
|
||||||
|
startup fallback. Personal settings and application profiles use mode `600`.
|
||||||
|
|
||||||
|
Quick settings work without opening the form:
|
||||||
|
|
||||||
|
| Shortcut | Action |
|
||||||
|
| --- | --- |
|
||||||
|
| Fenrir+Space | Announce current setting |
|
||||||
|
| Fenrir+Left / Right | Previous / next setting |
|
||||||
|
| Fenrir+Control+Left / Right | Previous / next category |
|
||||||
|
| Fenrir+Up / Down | Change value |
|
||||||
|
| Fenrir+Control+S | Save settings |
|
||||||
|
|
||||||
|
Quick changes apply to the current session. Save to retain them for future
|
||||||
|
launches. Session controls such as mute and temporary silence are separate
|
||||||
|
from saved startup preferences.
|
||||||
|
|
||||||
## Application overrides
|
## Application overrides
|
||||||
|
|
||||||
Press **Fenrir+A** to open **Applications**. Up and Down select an item; Enter
|
Press **Fenrir+A** to open **Applications**. Up and Down select an item; Enter
|
||||||
@@ -241,168 +403,6 @@ Real acceptance still needs a Codex reply spoken once after completion, working
|
|||||||
status on demand, history review, composer typing, approval/question handling,
|
status on demand, history review, composer typing, approval/question handling,
|
||||||
and returning to ordinary reading after choosing Default or exiting Codex.
|
and returning to ordinary reading after choosing Default or exiting Codex.
|
||||||
|
|
||||||
## Starting and stopping
|
|
||||||
|
|
||||||
Run these commands from the checkout root after building `fenrir`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Linux text console, with console and keyboard device access
|
|
||||||
sudo ./fenrir
|
|
||||||
|
|
||||||
# Linux console in the foreground (also use -f with service managers)
|
|
||||||
sudo ./fenrir -f
|
|
||||||
|
|
||||||
# X11 terminal, as your regular user
|
|
||||||
./fenrir -x
|
|
||||||
|
|
||||||
# Either mode can select the laptop layout
|
|
||||||
./fenrir -x --keyboard-layout laptop
|
|
||||||
```
|
|
||||||
|
|
||||||
Console mode starts in the background by default. Add `-f` to keep it in the
|
|
||||||
foreground, including under a service manager. The launcher returns after the
|
|
||||||
reader initializes and reports startup failures in the launching terminal.
|
|
||||||
Use `--debug-file PATH` to retain diagnostics after detaching. Help, version,
|
|
||||||
and configuration-only commands always run in the foreground.
|
|
||||||
|
|
||||||
X11 mode (`-x`) always stays in the foreground because it owns the terminal
|
|
||||||
and its child shell. Press **Fenrir+Q** to quit either mode. Run only one
|
|
||||||
reader on a given Linux console. Separate X11 terminal instances can run at
|
|
||||||
once.
|
|
||||||
|
|
||||||
X11 mode starts a shell in a new PTY. The launching terminal must supply valid
|
|
||||||
`DISPLAY` and `WINDOWID` environment variables. Keyboard interception is scoped
|
|
||||||
to that terminal window; a desktop screen reader can handle other windows.
|
|
||||||
|
|
||||||
Console mode needs access to console devices, keyboard event devices, and
|
|
||||||
`/dev/uinput`. It releases keyboard input on graphical virtual terminals and
|
|
||||||
on text consoles selected in `screen.ignored_vts`.
|
|
||||||
|
|
||||||
## Keyboard layouts and help
|
|
||||||
|
|
||||||
The **Fenrir key** is Insert, Super/Windows, or keypad 0 with NumLock off.
|
|
||||||
Hold it while pressing the other keys in a shortcut. Bare keypad review keys
|
|
||||||
also require NumLock off.
|
|
||||||
|
|
||||||
The desktop layout uses the numeric keypad. The laptop layout uses Fenrir
|
|
||||||
chords on the main keyboard. Select a layout with `--keyboard-layout desktop`
|
|
||||||
or `--keyboard-layout laptop`, or set `keyboard.layout` in the settings file.
|
|
||||||
|
|
||||||
Press **Fenrir+H** or **Fenrir+F1** to enter the tutorial. Command shortcuts are
|
|
||||||
announced and described instead of executed. Up and Down browse commands;
|
|
||||||
Left and Right switch between active actions, unbound actions, and scripts.
|
|
||||||
Space repeats the current item. Escape or Fenrir+F1 exits.
|
|
||||||
|
|
||||||
The complete layouts are [desktop.toml](../config/keyboard/desktop.toml) and
|
|
||||||
[laptop.toml](../config/keyboard/laptop.toml).
|
|
||||||
|
|
||||||
## Screen review
|
|
||||||
|
|
||||||
Review moves Fenrir's reading position without moving the application's cursor.
|
|
||||||
Return to the application cursor with the Follow cursor shortcut. By default,
|
|
||||||
application cursor movement or a screen change also leaves review.
|
|
||||||
|
|
||||||
| 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 |
|
|
||||||
| Top / bottom of screen | Fenrir+Keypad 7 / 9 | Fenrir+Shift+U / O |
|
|
||||||
| Line start / end | Fenrir+Keypad 4 / 6 | Fenrir+Shift+J / L |
|
|
||||||
| First / last text on line | Fenrir+Keypad 1 / 3 | Fenrir+Control+J / L |
|
|
||||||
| Read screen | Fenrir+Keypad 5 | Fenrir+Shift+K |
|
|
||||||
| Screen before / after cursor | Fenrir+Keypad 8 / 2 | Fenrir+Shift+I / Comma |
|
|
||||||
| Character above / below | Fenrir+Control+Keypad 8 / 2 | Fenrir+Control+I / Comma |
|
|
||||||
| Follow cursor | Fenrir+Keypad Period | Fenrir+Slash |
|
|
||||||
| Review position | Keypad Period | Fenrir+Shift+Period |
|
|
||||||
|
|
||||||
Press the current-line or current-word shortcut twice quickly to spell the
|
|
||||||
text, or three times for phonetic reading. Press the current-character shortcut
|
|
||||||
twice for its phonetic name. The default interval between presses is 200 ms;
|
|
||||||
`keyboard.multi_press_timeout_ms` changes it at launch.
|
|
||||||
|
|
||||||
## Tracking modes
|
|
||||||
|
|
||||||
Cycle through **cursor**, **table**, and **highlight** with
|
|
||||||
**Fenrir+Keypad Asterisk** on desktop or **Fenrir+Y** on laptop.
|
|
||||||
The startup selection is `reading.mode`.
|
|
||||||
|
|
||||||
- **Cursor**: follows application cursor movement.
|
|
||||||
- **Table**: treats delimited or space-aligned text as cells.
|
|
||||||
- **Highlight**: follows changes to highlighted text, such as menu selections.
|
|
||||||
|
|
||||||
In table mode, word navigation moves between cells, line start/end moves to the
|
|
||||||
first/last cell, and first/last text moves to the first/last character in the
|
|
||||||
current cell. Place review on a header row and press **Fenrir+X** to use its
|
|
||||||
cells as column headers. Outside table mode, Fenrir+X places a text-selection
|
|
||||||
mark.
|
|
||||||
|
|
||||||
## Speech and automatic reading
|
|
||||||
|
|
||||||
- **Control** interrupts speech.
|
|
||||||
- **Fenrir+F4** toggles mute.
|
|
||||||
- **Keypad Enter** on desktop temporarily silences speech. Speech can return on
|
|
||||||
the next keypress or a newly recognized prompt or completion.
|
|
||||||
- **Fenrir+Keypad Enter** on desktop, or **Fenrir+Enter** on laptop, toggles
|
|
||||||
automatic reading of new text.
|
|
||||||
- **Fenrir+Backspace** passes the next key through to the application.
|
|
||||||
|
|
||||||
Character echo, word echo, and cursor echo can be configured separately.
|
|
||||||
Punctuation levels are `none`, `some`, `most`, and `all`. At `some` and `most`,
|
|
||||||
punctuation inside words, URLs, email addresses, and filenames is also named.
|
|
||||||
Apostrophes within words and single numeric separators such as those in `3.14`,
|
|
||||||
`1,000`, and `12:30` follow the selected level. Sentence punctuation follows the
|
|
||||||
selected level too. Character review always names punctuation.
|
|
||||||
Capital indicators, emoticons, repeated-symbol summaries,
|
|
||||||
indentation feedback, and attribute feedback are configurable in Reading.
|
|
||||||
|
|
||||||
**Fenrir+T** announces the time; press twice quickly for the date.
|
|
||||||
**Fenrir+Shift+V** announces the Fenrir version.
|
|
||||||
|
|
||||||
## Fenrir Menu and quick settings
|
|
||||||
|
|
||||||
Press **Fenrir+F** to open the Fenrir Menu. It contains settings tabs for
|
|
||||||
presentation, speech, sound, reading, keyboard, internal UI, clipboard, and other options.
|
|
||||||
The form captures its navigation keys until it closes.
|
|
||||||
|
|
||||||
- At the tab selector, use arrows to choose a tab.
|
|
||||||
- Tab and Shift+Tab move between controls and the tab selector.
|
|
||||||
- Space or Enter toggles a checkbox.
|
|
||||||
- Arrows change list selections and numeric values.
|
|
||||||
- Activate **OK** to save, or **Cancel** or Escape to discard the form's changes.
|
|
||||||
|
|
||||||
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. Sound volume is
|
|
||||||
between 0.0 and 1.0. Backend, device, keyboard layout, sound theme, and other
|
|
||||||
launch-only settings take effect on the next start.
|
|
||||||
|
|
||||||
The **Internal UI** tab controls speech in Fenrir's own menus and dialogs.
|
|
||||||
**Announce grid row and column** and **Announce item position** are independent
|
|
||||||
checkboxes, both enabled by default. Disable coordinates to omit “row 1, column 2”;
|
|
||||||
disable item position to omit “2 of 20”. Item names and grid navigation remain
|
|
||||||
available with both disabled. Saved changes apply immediately to Emoji and
|
|
||||||
Spellcheck grids and persist across launches. These are global settings, so this
|
|
||||||
tab is omitted from application settings. The TOML keys are
|
|
||||||
`internal_ui.announce_grid_coordinates` and `internal_ui.announce_item_position`.
|
|
||||||
|
|
||||||
Settings saves use mode `644` for the standard system settings file at
|
|
||||||
`/etc/fenrirscreenreader/settings/settings.toml`, so other users can read it as a
|
|
||||||
startup fallback. Personal settings and application profiles use mode `600`.
|
|
||||||
|
|
||||||
Quick settings work without opening the form:
|
|
||||||
|
|
||||||
| Shortcut | Action |
|
|
||||||
| --- | --- |
|
|
||||||
| Fenrir+Space | Announce current setting |
|
|
||||||
| Fenrir+Left / Right | Previous / next setting |
|
|
||||||
| Fenrir+Control+Left / Right | Previous / next category |
|
|
||||||
| Fenrir+Up / Down | Change value |
|
|
||||||
| Fenrir+Control+S | Save settings |
|
|
||||||
|
|
||||||
Quick changes apply to the current session. Save to retain them for future
|
|
||||||
launches. Session controls such as mute and temporary silence are separate
|
|
||||||
from saved startup preferences.
|
|
||||||
|
|
||||||
## Clipboard
|
## Clipboard
|
||||||
|
|
||||||
Use review navigation to place two marks around text with **Fenrir+X**, then
|
Use review navigation to place two marks around text with **Fenrir+X**, then
|
||||||
@@ -477,6 +477,30 @@ Sound output uses `pulse` for PulseAudio or PipeWire's PulseAudio service, or
|
|||||||
`alsa` for an ALSA PCM device. Select the driver and theme in Sound settings.
|
`alsa` for an ALSA PCM device. Select the driver and theme in Sound settings.
|
||||||
The ALSA device name is set with `presentation.sound.device` in the file.
|
The ALSA device name is set with `presentation.sound.device` in the file.
|
||||||
|
|
||||||
|
Speech Dispatcher has its own synthesis and audio configuration, separate
|
||||||
|
from Fenrir's sound cues. For an X11 terminal session, run `./fenrir -x` as
|
||||||
|
your regular user. With sudo, Fenrir uses `SUDO_UID` to locate the invoking
|
||||||
|
user's PulseAudio socket. The default sound driver tries the user session,
|
||||||
|
then `/tmp/pulse.sock`, then `/run/pulse/native`. Set `PULSE_SERVER` to select
|
||||||
|
an explicit server; the sound driver does not read PulseAudio's `client.conf`.
|
||||||
|
The sound service must already be running and accessible to the reader.
|
||||||
|
See [Speech synthesizers](#speech-synthesizers) for Speech Dispatcher addresses
|
||||||
|
and autostart behavior.
|
||||||
|
|
||||||
|
If root sound needs additional configuration, the checkout includes
|
||||||
|
[configure_pulse.sh](../tools/configure_pulse.sh) for PulseAudio and
|
||||||
|
[configure_pipewire.sh](../tools/configure_pipewire.sh) for PipeWire.
|
||||||
|
Read the appropriate script before running it. Each has a regular-user part
|
||||||
|
and a root part, and writes audio configuration files. The PulseAudio script
|
||||||
|
replaces the user's `default.pa` and configures an anonymously accessible socket
|
||||||
|
at `/tmp/pulse.sock`. The PipeWire script also changes WirePlumber settings.
|
||||||
|
These scripts change system audio configuration and are only needed when the
|
||||||
|
existing audio setup does not provide the required access.
|
||||||
|
|
||||||
|
For ALSA, select `driver = "alsa"` under `[presentation.sound]` in
|
||||||
|
`settings.toml` and set `device` to the desired PCM name, such as `"default"`.
|
||||||
|
Driver and device changes apply at the next launch.
|
||||||
|
|
||||||
Personal themes are searched under `~/.local/stormux/fenrir/sounds/` before
|
Personal themes are searched under `~/.local/stormux/fenrir/sounds/` before
|
||||||
bundled and system themes. A theme contains WAV files and `soundicons.toml`.
|
bundled and system themes. A theme contains WAV files and `soundicons.toml`.
|
||||||
|
|
||||||
@@ -660,8 +684,10 @@ values. `./fenrir --version` identifies the build when reporting a problem.
|
|||||||
## Documentation maintenance and support
|
## Documentation maintenance and support
|
||||||
|
|
||||||
`docs/user.md` is the shared manual source. With Pandoc installed, run
|
`docs/user.md` is the shared manual source. With Pandoc installed, run
|
||||||
`./docs/create_manpage.sh` to regenerate `docs/user.txt`, `docs/fenrir.adoc`, and
|
`./docs/create_manpage.sh` to regenerate `docs/user.txt` and `docs/fenrir.1`.
|
||||||
`docs/fenrir.1`. The script can run from any working directory.
|
The script can run from any working directory. Edit the Markdown source rather
|
||||||
|
than the generated files. The bundled `docs/man_tables.lua` filter renders
|
||||||
|
man-page tables as labeled lists for narrow terminals.
|
||||||
|
|
||||||
Please review documentation and test instructions for the affected workflow
|
Please review documentation and test instructions for the affected workflow
|
||||||
before submitting a change, as described in the README's contribution policy.
|
before submitting a change, as described in the README's contribution policy.
|
||||||
|
|||||||
+326
-12
@@ -135,7 +135,11 @@ Speech and automatic reading
|
|||||||
- Fenrir+Backspace passes the next key through to the application.
|
- Fenrir+Backspace passes the next key through to the application.
|
||||||
|
|
||||||
Character echo, word echo, and cursor echo can be configured separately.
|
Character echo, word echo, and cursor echo can be configured separately.
|
||||||
Punctuation levels are none, some, most, and all. Character review still
|
Punctuation levels are none, some, most, and all. At some and most,
|
||||||
|
punctuation inside words, URLs, email addresses, and filenames is also
|
||||||
|
named. Apostrophes within words and single numeric separators such as
|
||||||
|
those in 3.14, 1,000, and 12:30 follow the selected level. Sentence
|
||||||
|
punctuation follows the selected level too. Character review always
|
||||||
names punctuation. Capital indicators, emoticons, repeated-symbol
|
names punctuation. Capital indicators, emoticons, repeated-symbol
|
||||||
summaries, indentation feedback, and attribute feedback are configurable
|
summaries, indentation feedback, and attribute feedback are configurable
|
||||||
in Reading.
|
in Reading.
|
||||||
@@ -146,8 +150,9 @@ Fenrir+Shift+V announces the Fenrir version.
|
|||||||
Fenrir Menu and quick settings
|
Fenrir Menu and quick settings
|
||||||
|
|
||||||
Press Fenrir+F to open the Fenrir Menu. It contains settings tabs for
|
Press Fenrir+F to open the Fenrir Menu. It contains settings tabs for
|
||||||
presentation, speech, sound, reading, keyboard, internal UI, clipboard, and other
|
presentation, speech, sound, reading, keyboard, internal UI, clipboard,
|
||||||
options. The form captures its navigation keys until it closes.
|
and other options. The form captures its navigation keys until it
|
||||||
|
closes.
|
||||||
|
|
||||||
- At the tab selector, use arrows to choose a tab.
|
- At the tab selector, use arrows to choose a tab.
|
||||||
- Tab and Shift+Tab move between controls and the tab selector.
|
- Tab and Shift+Tab move between controls and the tab selector.
|
||||||
@@ -157,9 +162,10 @@ options. The form captures its navigation keys until it closes.
|
|||||||
changes.
|
changes.
|
||||||
|
|
||||||
Speech rate, pitch, and volume use a scale from -100 to 100. For speech
|
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. Sound
|
rate, Up and Down change the value by 10; Left and Right change it by 1.
|
||||||
volume is between 0.0 and 1.0. Backend, device, keyboard layout, sound
|
Sound volume is between 0.0 and 1.0. Backend, device, keyboard layout,
|
||||||
theme, and other launch-only settings take effect on the next start.
|
sound theme, and other launch-only settings take effect on the next
|
||||||
|
start.
|
||||||
|
|
||||||
The Internal UI tab controls speech in Fenrir’s own menus and dialogs.
|
The Internal UI tab controls speech in Fenrir’s own menus and dialogs.
|
||||||
Announce grid row and column and Announce item position are independent
|
Announce grid row and column and Announce item position are independent
|
||||||
@@ -190,6 +196,259 @@ Quick changes apply to the current session. Save to retain them for
|
|||||||
future launches. Session controls such as mute and temporary silence are
|
future launches. Session controls such as mute and temporary silence are
|
||||||
separate from saved startup preferences.
|
separate from saved startup preferences.
|
||||||
|
|
||||||
|
Application overrides
|
||||||
|
|
||||||
|
Press Fenrir+A to open Applications. Up and Down select an item; Enter
|
||||||
|
activates it and closes the menu. Escape or the Cancel button closes the
|
||||||
|
menu without changing the selection. Tab and Shift+Tab move between the
|
||||||
|
list, Copy alias to clipboard, Cancel, and the tab selector. The active
|
||||||
|
override is initially selected.
|
||||||
|
|
||||||
|
Type the start of a name to jump to it: n selects NetworkManager, then i
|
||||||
|
selects Ninjam. Searching ignores letter case and does not activate the
|
||||||
|
item. Backspace removes a search character; Control+Backspace clears the
|
||||||
|
search. Up, Down, or moving focus away from the list also clears the
|
||||||
|
search. Unmatched characters announce No matches and leave the last
|
||||||
|
matching search intact.
|
||||||
|
|
||||||
|
Start the application normally, then select its override. This menu does
|
||||||
|
not launch programs. Choose Default to restore the settings and reading
|
||||||
|
regions that were in effect before the override. Overrides are built
|
||||||
|
into Fenrir and are never selected automatically or remembered across
|
||||||
|
restarts.
|
||||||
|
|
||||||
|
To launch a program with its override, select its name in this list,
|
||||||
|
then Tab to Copy alias to clipboard and press Enter. This copies a Bash
|
||||||
|
alias into Fenrir’s clipboard without selecting the override or closing
|
||||||
|
the menu. Paste it into your Bash configuration, such as ~/.bashrc, and
|
||||||
|
load that configuration in a new shell. The aliases use the executable
|
||||||
|
names cninjam, nmtui, rogue, and codex; Default has no alias. Existing
|
||||||
|
aliases with those names are replaced when you load the definition.
|
||||||
|
|
||||||
|
The alias requests the override through socat, then launches the real
|
||||||
|
program with the arguments you supplied. Errors remain visible, and the
|
||||||
|
program still launches if the request fails, remote control is disabled,
|
||||||
|
or Fenrir or socat is missing. Socket inactivity is limited to two
|
||||||
|
seconds. It uses the standard socket, or your configured
|
||||||
|
remote.socket_file, rather than a process-specific socket that changes
|
||||||
|
at restart. Paste with Fenrir’s clipboard command; desktop clipboard
|
||||||
|
synchronization follows your normal clipboard settings.
|
||||||
|
|
||||||
|
While an override is active, Fenrir+F opens its application settings,
|
||||||
|
with the application name in the title. OK, Fenrir+Control+S, and remote
|
||||||
|
SETTING SAVE save that application’s preferences. Quick and remote
|
||||||
|
changes remain temporary until saved. Default settings are kept
|
||||||
|
separately, including any unsaved adjustments made before activating the
|
||||||
|
override.
|
||||||
|
|
||||||
|
Profiles live in an applications/ subdirectory of the ordinary settings
|
||||||
|
save directory. For example:
|
||||||
|
|
||||||
|
- System settings:
|
||||||
|
/etc/fenrirscreenreader/settings/applications/ninjam.toml.
|
||||||
|
- Personal settings:
|
||||||
|
~/.local/share/stormux/fenrirscreenreader/settings/applications/ninjam.toml.
|
||||||
|
- With --config /path/settings.toml: /path/applications/ninjam.toml.
|
||||||
|
|
||||||
|
NetworkManager uses networkmanager.toml; Rogue uses rogue.toml; Codex
|
||||||
|
uses codex.toml. The directory and file are created on the first
|
||||||
|
successful save. Files contain only customized settings; omitted values
|
||||||
|
inherit ordinary settings followed by the built-in application defaults.
|
||||||
|
A customized voice selection saves module, language, and voice together
|
||||||
|
so a later change to the ordinary voice does not break that selection.
|
||||||
|
Profiles are loaded when their override first recognizes the
|
||||||
|
application; restarting Fenrir still starts with Default. Reselect the
|
||||||
|
application to reload an edited file.
|
||||||
|
|
||||||
|
Application settings include voice, rate, pitch, volume, reading
|
||||||
|
behavior, sound enablement/volume, and typing echo. Startup settings
|
||||||
|
such as speech driver, serial device, keyboard layout, and sound theme
|
||||||
|
remain in the default menu; clipboard storage and console routing also
|
||||||
|
remain global. Session mute and the temporary automatic-reading toggle
|
||||||
|
are not implicitly saved. Remote SAVEAS and screen#ignore_screen are
|
||||||
|
unavailable while an application is active. Saving is blocked during
|
||||||
|
context transitions or failed voice restoration. A malformed profile or
|
||||||
|
unavailable voice leaves ordinary settings in effect and reports an
|
||||||
|
error. Select the application again after correcting the file.
|
||||||
|
|
||||||
|
For example, a rate-only profile contains current TOML setting names,
|
||||||
|
with no top-level version field:
|
||||||
|
|
||||||
|
[presentation.speech]
|
||||||
|
rate = 40
|
||||||
|
|
||||||
|
To make a saved value inherit again, remove that setting from the
|
||||||
|
application file and reselect the override. Removing the file restores
|
||||||
|
complete inheritance.
|
||||||
|
|
||||||
|
An override belongs to its terminal. Switching VTs or leaving the
|
||||||
|
terminal suspends its effects; returning resumes it when the application
|
||||||
|
screen is recognized. Unrecognized screens use ordinary reading. A fresh
|
||||||
|
shell prompt on the cursor row, with the application interface absent,
|
||||||
|
clears the selection and announces Default settings restored. This works
|
||||||
|
from screen contents, so it does not require access to remote processes
|
||||||
|
over SSH or inside GNU Screen. Unusual prompts may require selecting
|
||||||
|
Default manually. Password prompts, confirmation questions, and old
|
||||||
|
shell prompts in scrollback do not clear it. Split windows, heavily
|
||||||
|
customized application colors, and localized or unfamiliar layouts may
|
||||||
|
prevent recognition; Default is always available.
|
||||||
|
|
||||||
|
NetworkManager targets nmtui and temporarily selects highlight tracking.
|
||||||
|
|
||||||
|
Ninjam targets the cninjam curses client. It announces selected controls
|
||||||
|
with master, metronome, or channel context; mute, transmit, and receive
|
||||||
|
controls are spoken as states. While adjusting a volume/pan control,
|
||||||
|
Left/Right announces only the pan percentage and direction, or center;
|
||||||
|
Up/Down announces only the volume, with minus and plus spoken
|
||||||
|
explicitly. Peak meters and the interval bar remain quiet. Navigating
|
||||||
|
the application’s controls after manual review resumes tracking; passive
|
||||||
|
updates leave review in place. Incoming chat is announced independently
|
||||||
|
of control changes. The following shortcuts temporarily replace numbered
|
||||||
|
region reads:
|
||||||
|
|
||||||
|
Shortcut Ninjam information
|
||||||
|
---------- ---------------------------------------------------
|
||||||
|
Fenrir+1 Latest new chat message received since activation
|
||||||
|
Fenrir+2 Selected channel or control
|
||||||
|
Fenrir+3 Connection, tempo, and interval position
|
||||||
|
|
||||||
|
Fenrir+Shift+B lists these application assignments. Existing user
|
||||||
|
regions are preserved and restored when the override ends. Review, Read
|
||||||
|
Screen, and copying continue to expose the actual terminal text,
|
||||||
|
including its literal X marks. Chat history is baselined on activation,
|
||||||
|
resize, buffer changes, and history paging to avoid announcing old
|
||||||
|
messages as new. Messages that appear and disappear between screen
|
||||||
|
captures cannot be recovered reliably.
|
||||||
|
|
||||||
|
The laptop shortcut for reading attributes is Fenrir+Shift+A; Fenrir+A
|
||||||
|
opens Applications in both layouts.
|
||||||
|
|
||||||
|
Rogue targets the classic English Rogue 5.4 terminal game, including the
|
||||||
|
5.4.4 package. Start rogue, then select Rogue with Fenrir+A (type r,
|
||||||
|
then Enter). The override announces messages and prompts, including
|
||||||
|
More; press Space, changes in health, hunger, dungeon level, strength,
|
||||||
|
armor, and experience level, and newly visible monsters, objects, doors,
|
||||||
|
stairs, and traps. Ordinary map redraws stay quiet. Moving monsters are
|
||||||
|
compared by letter and count to reduce repeated announcements. Their
|
||||||
|
current positions remain available on request. Appearing and
|
||||||
|
disappearing messages between captures, or one monster replacing another
|
||||||
|
of the same letter without a count change, cannot reliably be
|
||||||
|
distinguished from the visible display alone.
|
||||||
|
|
||||||
|
Shortcut Rogue information
|
||||||
|
---------- --------------------------------------------------------
|
||||||
|
Fenrir+1 Health, for example “Health: 12 of 12”
|
||||||
|
Fenrir+2 Full status line
|
||||||
|
Fenrir+3 Latest message or prompt
|
||||||
|
Fenrir+4 Eight neighboring cells, clockwise from north
|
||||||
|
Fenrir+5 Visible monsters and their positions relative to you
|
||||||
|
Fenrir+6 Visible objects and landmarks, with relative positions
|
||||||
|
|
||||||
|
These explicit reads include their region names. Names are supported by
|
||||||
|
the shared application-region API, so other overrides can use them as
|
||||||
|
needed. Fenrir+Shift+B lists the assignments. Slots 7 through 10 remain
|
||||||
|
available for manual regions. Existing user regions are preserved while
|
||||||
|
the override is active and restored when it ends, as with Ninjam.
|
||||||
|
|
||||||
|
Directions give cell offsets, for example “bat, north 2, east 3.”
|
||||||
|
Descriptions use only displayed symbols; they do not reveal hidden
|
||||||
|
monsters, secret doors, or unidentified items. Blank cells are described
|
||||||
|
as unseen, and hallucination or disguised monsters can make the
|
||||||
|
displayed symbols misleading. The playfield uses the first 24 rows and
|
||||||
|
80 columns even in a larger terminal, with status on row 24. Inventory,
|
||||||
|
help, and options pages use ordinary reading and review; map regions
|
||||||
|
report information unavailable on those pages. Slow inventory uses the
|
||||||
|
ordinary message region. Read Screen, review, and copying retain the
|
||||||
|
actual terminal text. Unrecognized screens return to ordinary reading.
|
||||||
|
|
||||||
|
Developers can exercise an installed classic Rogue in private PTYs
|
||||||
|
without touching the active reader:
|
||||||
|
|
||||||
|
FENRIR_ROGUE_TEST_BINARY=/usr/bin/rogue go test ./internal/terminal -run TestRogueLiveOverride -v
|
||||||
|
|
||||||
|
Codex CLI
|
||||||
|
|
||||||
|
The Codex override replaces automatic terminal diffs with completed
|
||||||
|
assistant messages. It suppresses tool output, streaming fragments, and
|
||||||
|
redraws. Manual screen review remains available, and typing echo is
|
||||||
|
limited to the composer. Messages are retained in memory even while
|
||||||
|
speech is muted or automatic reading is disabled. Existing lifecycle
|
||||||
|
alerts remain separate from reply reading. Left/Right navigation retains
|
||||||
|
character feedback inside the composer. While Codex is working, the
|
||||||
|
existing activity tone sounds once every four seconds without requiring
|
||||||
|
redraws. It stops for approval/question waits and completion, respects
|
||||||
|
the sound and progress toggles, and remains independent of speech mute.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Shortcut Codex information
|
||||||
|
----------------------------------- -----------------------------------
|
||||||
|
Fenrir+1 through Fenrir+9 Recent completed assistant
|
||||||
|
messages, newest first
|
||||||
|
|
||||||
|
Fenrir+0 Working, ready, waiting for
|
||||||
|
approval or an answer, finished, or
|
||||||
|
interrupted
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Select Codex with Fenrir+A, type c, then Enter. Select Default to leave
|
||||||
|
the override. Without its bridge, the override suppresses automatic
|
||||||
|
screen changes and the status shortcut says Waiting for Codex bridge.
|
||||||
|
|
||||||
|
The optional bridge requires Python 3 and Fenrir remote command control
|
||||||
|
enabled. Merge a command hook invoking
|
||||||
|
python3 /absolute/path/to/fenrir/tools/codex_bridge.py into each of
|
||||||
|
these events in ~/.codex/hooks.json: SessionStart, UserPromptSubmit,
|
||||||
|
PermissionRequest, PostToolUse, Stop, Interrupt, and SessionEnd. For
|
||||||
|
example, one event entry is:
|
||||||
|
|
||||||
|
{
|
||||||
|
"hooks": {
|
||||||
|
"SessionStart": [{"hooks": [{"type": "command", "command": "python3 /absolute/path/to/fenrir/tools/codex_bridge.py", "timeout": 3}]}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Preserve existing hooks. Review and trust the added hooks through
|
||||||
|
Codex’s /hooks interface; restart or resume Codex if required by the
|
||||||
|
installed version. Starting or resuming a conversation starts a detached
|
||||||
|
bridge follower; submitting a prompt also restarts it if necessary. The
|
||||||
|
bridge never speaks or answers approvals.
|
||||||
|
|
||||||
|
The follower reads only the transcript path supplied by that
|
||||||
|
conversation’s hook and verifies its session identifier. It accepts
|
||||||
|
completed assistant events, never tool results, reasoning, or streamed
|
||||||
|
deltas. It keeps the nine latest replies in memory and writes only
|
||||||
|
status, conversation identifiers, and lock files to a private runtime
|
||||||
|
directory. Switching conversations replaces the terminal binding;
|
||||||
|
packets from an older conversation cannot overwrite the new history.
|
||||||
|
Existing history is loaded silently on attachment or bridge restart.
|
||||||
|
Long replies are transported in chunks and announced only after
|
||||||
|
assembly; the current per-message limit is 1 MiB. The worker stops when
|
||||||
|
Codex exits or a SessionEnd hook runs.
|
||||||
|
|
||||||
|
X11 routing requires the same WINDOWID as the Fenrir instance; Linux
|
||||||
|
console routing uses Codex’s controlling VT and the reader’s existing
|
||||||
|
authorization. Other windows and consoles do not receive the replies.
|
||||||
|
This local bridge does not forward SSH audio or attach a remote Codex
|
||||||
|
server to a local terminal.
|
||||||
|
|
||||||
|
The transcript parser was checked against Codex CLI 0.165.0. It uses
|
||||||
|
Codex’s local completed-event records, rather than a public subscription
|
||||||
|
API; a changed record format may require an update. Status comes from
|
||||||
|
hooks and recorded turn events, not the terminal’s animated activity
|
||||||
|
label. Check Fenrir+0 after resuming.
|
||||||
|
|
||||||
|
For a private protocol and keyboard test without live speech or Codex
|
||||||
|
requests:
|
||||||
|
|
||||||
|
go build -o fenrir ./cmd/fenrir
|
||||||
|
python3 -m unittest discover -s tests -p test_codex_bridge.py
|
||||||
|
xvfb-run -a env FENRIR_PRIVATE_X11=1 python3 tests/native_codex.py
|
||||||
|
|
||||||
|
Real acceptance still needs a Codex reply spoken once after completion,
|
||||||
|
working status on demand, history review, composer typing,
|
||||||
|
approval/question handling, and returning to ordinary reading after
|
||||||
|
choosing Default or exiting Codex.
|
||||||
|
|
||||||
Clipboard
|
Clipboard
|
||||||
|
|
||||||
Use review navigation to place two marks around text with Fenrir+X, then
|
Use review navigation to place two marks around text with Fenrir+X, then
|
||||||
@@ -267,6 +526,30 @@ or alsa for an ALSA PCM device. Select the driver and theme in Sound
|
|||||||
settings. The ALSA device name is set with presentation.sound.device in
|
settings. The ALSA device name is set with presentation.sound.device in
|
||||||
the file.
|
the file.
|
||||||
|
|
||||||
|
Speech Dispatcher has its own synthesis and audio configuration,
|
||||||
|
separate from Fenrir’s sound cues. For an X11 terminal session, run
|
||||||
|
./fenrir -x as your regular user. With sudo, Fenrir uses SUDO_UID to
|
||||||
|
locate the invoking user’s PulseAudio socket. The default sound driver
|
||||||
|
tries the user session, then /tmp/pulse.sock, then /run/pulse/native.
|
||||||
|
Set PULSE_SERVER to select an explicit server; the sound driver does not
|
||||||
|
read PulseAudio’s client.conf. The sound service must already be running
|
||||||
|
and accessible to the reader. See Speech synthesizers for Speech
|
||||||
|
Dispatcher addresses and autostart behavior.
|
||||||
|
|
||||||
|
If root sound needs additional configuration, the checkout includes
|
||||||
|
configure_pulse.sh for PulseAudio and configure_pipewire.sh for
|
||||||
|
PipeWire. Read the appropriate script before running it. Each has a
|
||||||
|
regular-user part and a root part, and writes audio configuration files.
|
||||||
|
The PulseAudio script replaces the user’s default.pa and configures an
|
||||||
|
anonymously accessible socket at /tmp/pulse.sock. The PipeWire script
|
||||||
|
also changes WirePlumber settings. These scripts change system audio
|
||||||
|
configuration and are only needed when the existing audio setup does not
|
||||||
|
provide the required access.
|
||||||
|
|
||||||
|
For ALSA, select driver = "alsa" under [presentation.sound] in
|
||||||
|
settings.toml and set device to the desired PCM name, such as "default".
|
||||||
|
Driver and device changes apply at the next launch.
|
||||||
|
|
||||||
Personal themes are searched under ~/.local/stormux/fenrir/sounds/
|
Personal themes are searched under ~/.local/stormux/fenrir/sounds/
|
||||||
before bundled and system themes. A theme contains WAV files and
|
before bundled and system themes. A theme contains WAV files and
|
||||||
soundicons.toml.
|
soundicons.toml.
|
||||||
@@ -289,10 +572,10 @@ options. Fenrir loads one settings file rather than merging files.
|
|||||||
- --config PATH: use that file explicitly.
|
- --config PATH: use that file explicitly.
|
||||||
|
|
||||||
If default files are absent, Fenrir uses built-in defaults. Python
|
If default files are absent, Fenrir uses built-in defaults. Python
|
||||||
settings.conf files are ignored. Regular users save to their personal TOML
|
settings.conf files are ignored. Regular users save to their personal
|
||||||
file, including when startup loaded system defaults; root saves to the system
|
TOML file, including when startup loaded system defaults; root saves to
|
||||||
file. --config PATH explicitly selects both the load and save path, and that
|
the system file. --config PATH explicitly selects both the load and save
|
||||||
file must exist at startup.
|
path, and that file must exist at startup.
|
||||||
|
|
||||||
Create a personal settings file and validate it without opening devices:
|
Create a personal settings file and validate it without opening devices:
|
||||||
|
|
||||||
@@ -311,6 +594,27 @@ Speech synthesizers
|
|||||||
The default driver is speech-dispatcher. Select its module, language,
|
The default driver is speech-dispatcher. Select its module, language,
|
||||||
and voice in Speech settings; empty values use server defaults.
|
and voice in Speech settings; empty values use server defaults.
|
||||||
|
|
||||||
|
Fenrir uses SPEECHD_ADDRESS when set: unix_socket:/absolute/path selects
|
||||||
|
a Unix socket, and inet_socket:HOST:PORT selects TCP (default host
|
||||||
|
127.0.0.1, port 6560). Invalid addresses report an error. Otherwise,
|
||||||
|
SPEECHD_SOCKET selects a Unix socket. Without either variable, Fenrir
|
||||||
|
uses $XDG_RUNTIME_DIR/speech-dispatcher/speechd.sock, falling back to
|
||||||
|
$XDG_CACHE_HOME/speech-dispatcher/speechd.sock or
|
||||||
|
~/.cache/speech-dispatcher/speechd.sock when the runtime directory is
|
||||||
|
unset. With sudo, the default remains
|
||||||
|
/run/user/$SUDO_UID/speech-dispatcher/speechd.sock. Sudo may remove
|
||||||
|
address variables; preserve them explicitly if needed.
|
||||||
|
|
||||||
|
When opening speech, Fenrir first tries the selected server. If its
|
||||||
|
socket is missing or refuses connections, Fenrir requests
|
||||||
|
speech-dispatcher --spawn and briefly retries. The daemon’s
|
||||||
|
configuration controls whether spawning is allowed. SPEECHD_CMD can
|
||||||
|
select another executable. Autostart is limited to Unix sockets and
|
||||||
|
local loopback TCP servers. When sudo changes the account, start Speech
|
||||||
|
Dispatcher as the invoking user first; Fenrir will not launch a
|
||||||
|
root-owned daemon for that user. Settings discovery never starts a
|
||||||
|
daemon or interrupts the active speaking client.
|
||||||
|
|
||||||
Hardware driver IDs are dectalk, dectalk-usb, litetalk, doubletalk, and
|
Hardware driver IDs are dectalk, dectalk-usb, litetalk, doubletalk, and
|
||||||
tripletalk. Serial drivers require presentation.speech.hardware_device,
|
tripletalk. Serial drivers require presentation.speech.hardware_device,
|
||||||
for example /dev/ttyUSB0, and default to 9600 baud when
|
for example /dev/ttyUSB0, and default to 9600 baud when
|
||||||
@@ -360,6 +664,14 @@ Other supported operations include:
|
|||||||
- command tempdisablespeech: temporarily silence speech.
|
- command tempdisablespeech: temporarily silence speech.
|
||||||
- command clipboard TEXT: add text to the clipboard.
|
- command clipboard TEXT: add text to the clipboard.
|
||||||
- command exportclipboard: export the selected clipboard.
|
- command exportclipboard: export the selected clipboard.
|
||||||
|
- command application ID: select default, networkmanager, ninjam, rogue,
|
||||||
|
or codex for this reader’s active terminal, like Fenrir+A. This
|
||||||
|
requires command remote control. An empty reply means selection
|
||||||
|
succeeded; invalid IDs, busy settings, and restoration failures return
|
||||||
|
an error. Application recognition and profile loading happen later,
|
||||||
|
when the application appears; this command does not launch it. default
|
||||||
|
restores ordinary settings. Use a private socket when targeting a
|
||||||
|
particular reader.
|
||||||
- command window X1 Y1 X2 Y2: set a reading window, using zero-based,
|
- command window X1 Y1 X2 Y2: set a reading window, using zero-based,
|
||||||
inclusive coordinates.
|
inclusive coordinates.
|
||||||
- command resetwindow: clear the window.
|
- command resetwindow: clear the window.
|
||||||
@@ -451,8 +763,10 @@ problem.
|
|||||||
Documentation maintenance and support
|
Documentation maintenance and support
|
||||||
|
|
||||||
docs/user.md is the shared manual source. With Pandoc installed, run
|
docs/user.md is the shared manual source. With Pandoc installed, run
|
||||||
./docs/create_manpage.sh to regenerate docs/user.txt, docs/fenrir.adoc,
|
./docs/create_manpage.sh to regenerate docs/user.txt and docs/fenrir.1.
|
||||||
and docs/fenrir.1. The script can run from any working directory.
|
The script can run from any working directory. Edit the Markdown source
|
||||||
|
rather than the generated files. The bundled docs/man_tables.lua filter
|
||||||
|
renders man-page tables as labeled lists for narrow terminals.
|
||||||
|
|
||||||
Please review documentation and test instructions for the affected
|
Please review documentation and test instructions for the affected
|
||||||
workflow before submitting a change, as described in the README’s
|
workflow before submitting a change, as described in the README’s
|
||||||
|
|||||||
@@ -66,6 +66,28 @@ func TestURLSpeechKeepsEmbeddedPunctuationAndOriginalClipboardText(t *testing.T)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPackageProgressBarSpeechKeepsOriginalClipboardText(t *testing.T) {
|
||||||
|
processor, _, err := punctuation.Load([]string{"../../config/punctuation/default.toml"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
settings := config.Defaults()
|
||||||
|
settings.Reading.RepeatedSymbols = true
|
||||||
|
voice := &fakeVoice{}
|
||||||
|
echo := &echoSpeaker{Speaker: voice, punctuation: processor, punctuationLevel: "some", settings: &settings}
|
||||||
|
text := "(123/189) upgrading nodejs-lts-jod" + strings.Repeat(" ", 157) + "[" + strings.Repeat("#", 120) + "] 100%"
|
||||||
|
echo.Say(text)
|
||||||
|
if len(voice.messages) != 1 {
|
||||||
|
t.Fatal("missing progress speech", voice.messages)
|
||||||
|
}
|
||||||
|
if got := strings.Join(strings.Fields(voice.messages[0]), " "); got != "123 slash 189 upgrading nodejs dash lts dash jod 120 number 100" {
|
||||||
|
t.Fatal("progress bar did not summarize", got)
|
||||||
|
}
|
||||||
|
if echo.last != text {
|
||||||
|
t.Fatal("clipboard echo lost original progress bar", echo.last)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestReviewCharactersUseProfileRegardlessOfLevelAndKeepBoundaries(t *testing.T) {
|
func TestReviewCharactersUseProfileRegardlessOfLevelAndKeepBoundaries(t *testing.T) {
|
||||||
processor, _, err := punctuation.Load([]string{"../../config/punctuation/fr.toml"})
|
processor, _, err := punctuation.Load([]string{"../../config/punctuation/fr.toml"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -47,10 +47,24 @@ func (p *Processor) process_token(token, level string, options TextOptions) stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if options.RepeatedSymbols && options.RepeatedSymbolsMin >= 2 && token != "" {
|
if options.RepeatedSymbols && options.RepeatedSymbolsMin >= 2 && token != "" {
|
||||||
char, _ := utf8.DecodeRuneInString(token)
|
repeated := token
|
||||||
|
prefix, suffix := "", ""
|
||||||
|
// Progress bars commonly enclose a repeated run in brackets. Keep
|
||||||
|
// those delimiters under ordinary punctuation handling, and require
|
||||||
|
// the entire interior to repeat so paths and mixed tokens stay literal.
|
||||||
|
if len(token) >= 2 {
|
||||||
|
for _, pair := range []string{"[]", "()", "{}", "<>"} {
|
||||||
|
if token[0] == pair[0] && token[len(token)-1] == pair[1] {
|
||||||
|
prefix, suffix = token[:1], token[len(token)-1:]
|
||||||
|
repeated = token[1 : len(token)-1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char, _ := utf8.DecodeRuneInString(repeated)
|
||||||
if p.levels[level][char] && (unicode.IsPunct(char) || unicode.IsSymbol(char)) {
|
if p.levels[level][char] && (unicode.IsPunct(char) || unicode.IsSymbol(char)) {
|
||||||
count := 0
|
count := 0
|
||||||
for _, next := range token {
|
for _, next := range repeated {
|
||||||
if next != char {
|
if next != char {
|
||||||
return p.Text(token, level)
|
return p.Text(token, level)
|
||||||
}
|
}
|
||||||
@@ -66,7 +80,7 @@ func (p *Processor) process_token(token, level string, options TextOptions) stri
|
|||||||
name = i18n.T(name)
|
name = i18n.T(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i18n.Format("{0} {1}", strconv.Itoa(count), name)
|
return p.Text(prefix, level) + i18n.Format("{0} {1}", strconv.Itoa(count), name) + p.Text(suffix, level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,13 +28,17 @@ func TestTextSubstitutionsAndBoundaries(t *testing.T) {
|
|||||||
{"#### ####", "4 number 4 number"},
|
{"#### ####", "4 number 4 number"},
|
||||||
{"##### title #####", "5 number title 5 number"},
|
{"##### title #####", "5 number title 5 number"},
|
||||||
{"////", "4 slash"},
|
{"////", "4 slash"},
|
||||||
|
{"[#####]", " 5 number "},
|
||||||
|
{"(#####)", " 5 number "},
|
||||||
|
{"{#####}", " 5 number "},
|
||||||
|
{"<#####>", " 5 number "},
|
||||||
{"Oo", "WTF?"},
|
{"Oo", "WTF?"},
|
||||||
} {
|
} {
|
||||||
if got := processor.Process_text(trial.text, "some", options); got != trial.want {
|
if got := processor.Process_text(trial.text, "some", options); got != trial.want {
|
||||||
t.Errorf("%q: %q, want %q", trial.text, got, trial.want)
|
t.Errorf("%q: %q, want %q", trial.text, got, trial.want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, text := range []string{"hello :)!", "path/to:)file", "https://example.invalid/:)", "https://example.invalid/:-/", "(o_O)", "###", "##--##", "a####b", "../....", "https://example.invalid/####", "10000", "aaaa", "🙂🙂🙂🙂", ""} {
|
for _, text := range []string{"hello :)!", "path/to:)file", "https://example.invalid/:)", "https://example.invalid/:-/", "(o_O)", "###", "##--##", "a####b", "../....", "https://example.invalid/####", "10000", "aaaa", "🙂🙂🙂🙂", "", "[]", "[###]", "[####)", "[##--##]", "[a####b]", "[../....]", "[https://example.invalid/####]"} {
|
||||||
for _, level := range Levels() {
|
for _, level := range Levels() {
|
||||||
if got, want := processor.Process_text(text, level, options), processor.Text(text, level); got != want {
|
if got, want := processor.Process_text(text, level, options), processor.Text(text, level); got != want {
|
||||||
t.Errorf("%q, %s changed ordinary processing: %q, want %q", text, level, got, want)
|
t.Errorf("%q, %s changed ordinary processing: %q, want %q", text, level, got, want)
|
||||||
@@ -101,6 +105,30 @@ func TestSubstitutionOptionsAndProfileNames(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBracketedRepeatedSymbolsRespectOptionsAndLevels(t *testing.T) {
|
||||||
|
processor, _, err := Load([]string{"../../config/punctuation/default.toml"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, level := range Levels() {
|
||||||
|
for _, options := range []TextOptions{
|
||||||
|
{},
|
||||||
|
{Emoticons: true},
|
||||||
|
{RepeatedSymbols: true, RepeatedSymbolsMin: 1},
|
||||||
|
{RepeatedSymbols: true, RepeatedSymbolsMin: 6},
|
||||||
|
{RepeatedSymbols: true, RepeatedSymbolsMin: 4},
|
||||||
|
} {
|
||||||
|
want := processor.Text("[#####]", level)
|
||||||
|
if options.RepeatedSymbols && options.RepeatedSymbolsMin == 4 && level != "none" {
|
||||||
|
want = processor.Text("[", level) + "5 number" + processor.Text("]", level)
|
||||||
|
}
|
||||||
|
if got := processor.Process_text("[#####]", level, options); got != want {
|
||||||
|
t.Errorf("level %s, options %+v: got %q, want %q", level, options, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTextSubstitutionTranslationsAndFieldOrder(t *testing.T) {
|
func TestTextSubstitutionTranslationsAndFieldOrder(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
directory := filepath.Join(root, "xx", "LC_MESSAGES")
|
directory := filepath.Join(root, "xx", "LC_MESSAGES")
|
||||||
|
|||||||
Reference in new issue
Block a user