From 5a14804d110dec7b1318328f8d4eda2c6326ee35 Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Wed, 9 Jul 2025 18:31:58 -0400 Subject: [PATCH] Updates to documentation. A few tidying up changes. --- README.md | 173 ++++++++++++++++++ check-dependencies.py | 13 +- config/keyboard/Readme.md | 42 +++++ docs/user.md | 47 +++++ .../vmenu-profiles/KEY/mc/search/test.py | 19 +- .../vmenu-profiles/KEY/mutt/search/test.py | 19 +- .../vmenu-profiles/KEY/nano/search/test.py | 19 +- .../vmenu-profiles/KEY/vim/search/test.py | 19 +- src/fenrirscreenreader/core/processManager.py | 2 +- .../core/settingsManager.py | 13 +- 10 files changed, 304 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index da37b5ee..48a2cd79 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ This software is licensed under the LGPL v3. - **Multiple Interface Support**: Works in Linux TTY, and terminal emulators - **Flexible Driver System**: Modular architecture with multiple drivers for speech, sound, input, and screen - **Review Mode**: Navigate and review screen content without moving the edit cursor +- **Table Navigation**: Advanced table mode with column headers, cell-by-cell navigation, and boundary feedback +- **Progress Bar Monitoring**: Automatic detection and audio feedback for progress indicators with ascending tones - **Multiple Clipboard Support**: Manage multiple clipboard entries - **Configurable Key Bindings**: Desktop and laptop keyboard layouts - **Sound Icons**: Audio feedback for various events @@ -156,6 +158,7 @@ By default Fenrir uses: - `Keypad 2` - Read current character - `Fenrir + T` - Announce time - `Fenrir + S` - Spell check current word + - `Fenrir + Keypad *` - Toggle table mode / highlight tracking ### Keyboard Layouts @@ -402,6 +405,176 @@ setting [parameters] - `time#delaySec=seconds` - Announcement interval - `time#onMinutes=00,30` - Specific minutes to announce +## Table Navigation + +Fenrir includes advanced table navigation capabilities for working with tabular data in terminal applications, CSV files, and formatted text output. + +### Entering Table Mode + +Table mode is activated through the **toggle_highlight_tracking** command, which cycles through three focus modes: + +1. **Highlight tracking mode** (default) - Follows text highlighting +2. **Cursor tracking mode** - Follows text cursor movement +3. **Table mode** - Enables table navigation + +**Key bindings:** +- **Desktop layout**: `Fenrir + Keypad *` (asterisk) +- **Laptop layout**: `Fenrir + Y` + +Press the key combination repeatedly to cycle through modes until you hear "table mode enabled". + +### Table Navigation Commands + +#### Column Navigation (Desktop Layout) +- **Next column**: `Keypad 6` - Move to next table column +- **Previous column**: `Keypad 4` - Move to previous table column +- **First column**: `Fenrir + Keypad 4` - Jump to first column of current row +- **Last column**: `Fenrir + Keypad 6` - Jump to last column of current row + +#### Column Navigation (Laptop Layout) +- **Next column**: `Fenrir + L` - Move to next table column +- **Previous column**: `Fenrir + J` - Move to previous table column +- **First column**: `Fenrir + Shift + J` - Jump to first column of current row +- **Last column**: `Fenrir + Shift + L` - Jump to last column of current row + +#### Cell Character Navigation +- **First character in cell**: `Fenrir + Keypad 1` (desktop) or `Fenrir + Ctrl + J` (laptop) +- **Last character in cell**: `Fenrir + Keypad 3` (desktop) or `Fenrir + Ctrl + L` (laptop) + +### Setting Column Headers + +For better navigation experience, you can set column headers: + +1. **Navigate to header row**: Use normal navigation to reach the row containing column headers +2. **Set headers**: Press `Fenrir + X` to mark the current line as the header row +3. **Navigation feedback**: Column headers will be announced along with cell content + +### Table Detection + +Fenrir automatically detects table structures using multiple strategies: +- **Delimited text**: CSV, pipe-separated (`|`), semicolon-separated (`;`), tab-separated +- **Aligned columns**: Space-aligned columns (2+ spaces between columns) +- **Flexible parsing**: Handles various table formats commonly found in terminal applications + +### Table Mode Features + +- **Cell-by-cell navigation**: Navigate through table cells with precise positioning +- **Column header support**: Set and announce column headers for better context +- **Boundary feedback**: Audio cues when reaching start/end of rows +- **Empty cell handling**: Blank cells are announced as "blank" +- **Independent tracking**: Table position is maintained independently of cursor movement + +### Speech Output in Table Mode + +When navigating in table mode, Fenrir announces: +- **Cell content** followed by **column header/name** +- **Boundary notifications**: "end of line", "start of line" +- **Position indicators**: "first character in cell [column name]" + +### Example Usage + +```bash +# Working with CSV data +cat data.csv +Name,Age,City +Alice,30,New York +Bob,25,Los Angeles + +# 1. Press Fenrir + Keypad * until "table mode enabled" +# 2. Navigate to "Name,Age,City" line +# 3. Press Fenrir + X to set headers +# 4. Use Keypad 4/6 to navigate between columns +# 5. Each cell will be announced with its column header +``` + +## Progress Bar Monitoring + +Fenrir provides intelligent progress bar detection and audio feedback for various progress indicators commonly found in terminal applications. + +### Enabling Progress Monitoring + +**Command**: `progress_bar_monitor` (no default key binding - assign manually) + +To enable progress monitoring: +1. Add a key binding in your keyboard layout file +2. Or use the remote control system: `echo "command progress_bar_monitor" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock` + +### Progress Detection Patterns + +Fenrir automatically detects various progress indicator formats: + +#### 1. Percentage Progress +``` +Download: 45% +Processing: 67.5% +Installing: 100% +``` + +#### 2. Fraction Progress +``` +Files: 15/100 +Progress: 3 of 10 +Step 7/15 +``` + +#### 3. Progress Bars +``` +[#### ] 40% +[====> ] 50% +[**********] 100% +``` + +#### 4. Activity Indicators +``` +Loading... +Processing... +Working... +Installing... +Downloading... +Compiling... +Building... +``` + +### Audio Feedback + +#### Progress Tones +- **Ascending tones**: 400Hz to 1200Hz frequency range +- **Percentage mapping**: 0% = 400Hz, 100% = 1200Hz +- **Smooth progression**: Frequency increases proportionally with progress + +#### Activity Indicators +- **Steady beep**: 800Hz tone every 2 seconds for ongoing activity +- **Non-intrusive**: Beeps don't interrupt speech or other audio + +### Progress Monitoring Features + +- **Automatic detection**: No manual configuration required +- **Multiple format support**: Handles various progress indicator styles +- **Prompt awareness**: Automatically pauses when command prompts are detected +- **Non-blocking**: Progress tones don't interrupt speech or other functionality +- **Configurable**: Can be enabled/disabled as needed + +### Usage Examples + +```bash +# Enable progress monitoring +echo "command progress_bar_monitor" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock + +# Common scenarios where progress monitoring is useful: +wget https://example.com/large-file.zip # Download progress +tar -xvf archive.tar.gz # Extraction progress +make -j4 # Compilation progress +pacman -S package # Package installation +rsync -av source/ destination/ # File synchronization +``` + +### Customization + +Progress monitoring can be configured through settings: +- **Default enabled**: Set `progressMonitoring=True` in sound section +- **Sound integration**: Works with all sound drivers (sox, gstreamer) +- **Remote control**: Enable/disable through remote commands + ### Scripting Examples #### Bash Script for Speech Notifications diff --git a/check-dependencies.py b/check-dependencies.py index c92c9903..8edb70f5 100755 --- a/check-dependencies.py +++ b/check-dependencies.py @@ -50,7 +50,7 @@ def check_dependency(dep: Dependency) -> bool: dependencyList = [ # Core dependencies Dependency('FenrirCore', 'core', 'core', - pythonImports=['daemonize', 'enchant']), + pythonImports=['daemonize', 'enchant', 'pyperclip', 'setproctitle']), # Screen drivers Dependency('DummyScreen', 'screen', 'dummyDriver'), @@ -58,7 +58,7 @@ dependencyList = [ pythonImports=['dbus'], devicePaths=['/dev/vcsa']), Dependency('PTY', 'screen', 'ptyDriver', - pythonImports=['pyte']), + pythonImports=['pyte', 'xdg']), # Input drivers Dependency('DummyInput', 'input', 'dummyDriver'), @@ -82,7 +82,11 @@ dependencyList = [ Dependency('Speechd', 'speech', 'speechdDriver', pythonImports=['speechd']), Dependency('GenericSpeech', 'speech', 'genericDriver', - checkCommands=['espeak-ng']) + checkCommands=['espeak-ng']), + + # Additional dependencies + Dependency('Pexpect', 'core', 'pexpectDriver', + pythonImports=['pexpect']) ] defaultModules = { @@ -90,7 +94,8 @@ defaultModules = { 'VCSA', 'Evdev', 'GenericSpeech', - 'GenericSound' + 'GenericSound', + 'Pexpect' } def check_all_dependencies(): diff --git a/config/keyboard/Readme.md b/config/keyboard/Readme.md index 7b9d0456..83cc6805 100644 --- a/config/keyboard/Readme.md +++ b/config/keyboard/Readme.md @@ -1,4 +1,46 @@ +# Fenrir Keyboard Configuration + +This directory contains keyboard layout files for Fenrir screen reader. + +## Available Layouts + +- **desktop.conf** - Desktop layout using numeric keypad (recommended) +- **laptop.conf** - Laptop layout for keyboards without numeric keypad +- **nvda-desktop.conf** - NVDA-compatible desktop layout +- **nvda-laptop.conf** - NVDA-compatible laptop layout +- **pty.conf** - PTY emulation layout for terminal use +- **pty2.conf** - Alternative PTY emulation layout + +## Key Features + +### Table Navigation +- **Toggle table mode**: `Fenrir + Keypad *` (desktop) or `Fenrir + Y` (laptop) +- **Column navigation**: `Keypad 4/6` (desktop) or `Fenrir + J/L` (laptop) +- **Row boundaries**: `Fenrir + Keypad 4/6` (desktop) or `Fenrir + Shift + J/L` (laptop) +- **Set headers**: `Fenrir + X` in table mode + +### Progress Bar Monitoring +- **Monitor progress**: `progress_bar_monitor` command (assign key binding manually) +- **Auto-detection**: Percentage, fractions, progress bars, activity indicators +- **Audio feedback**: Ascending tones (400Hz-1200Hz) for progress + +### Review Mode +- **Basic navigation**: `Keypad 7/8/9` (lines), `Keypad 4/5/6` (words), `Keypad 1/2/3` (characters) +- **Exit review**: `Fenrir + Keypad .` +- **Screen reading**: `Fenrir + Keypad 5` (current screen) + +## Configuration + +To change keyboard layout, edit `/etc/fenrir/settings/settings.conf`: + +```ini +[keyboard] +keyboardLayout=desktop # or laptop, nvda-desktop, nvda-laptop, pty, pty2 +``` + +## Available Key Constants + Keymap for Fenrir KEY_RESERVED KEY_ESC diff --git a/docs/user.md b/docs/user.md index 22af87ad..451302c7 100644 --- a/docs/user.md +++ b/docs/user.md @@ -50,6 +50,12 @@ Navigate the screen without moving the text cursor. Essential for examining cont - `Keypad 1/3` - Previous/next character - `Fenrir + Keypad dot` - Exit review mode +### Table Navigation +- `Fenrir + Keypad *` - Toggle table mode / highlight tracking +- `Keypad 4/6` - Previous/next column (in table mode) +- `Fenrir + Keypad 4/6` - First/last column (in table mode) +- `Fenrir + X` - Set column headers (in table mode) + ### Information - `Fenrir + T` - Announce time - `Fenrir + T T` - Announce date @@ -240,6 +246,47 @@ send_fenrir_command("command say Process complete") ## Advanced Features +### Table Navigation Mode + +Fenrir includes advanced table navigation capabilities for working with tabular data in terminal applications, CSV files, and formatted text output. + +#### Entering Table Mode +1. Press `Fenrir + Keypad *` (desktop) or `Fenrir + Y` (laptop) +2. Cycle through: Highlight tracking → Cursor tracking → Table mode +3. Listen for "table mode enabled" announcement + +#### Table Navigation Commands +- **Column navigation**: `Keypad 4/6` - Move between columns +- **Row boundaries**: `Fenrir + Keypad 4/6` - Jump to first/last column +- **Cell characters**: `Fenrir + Keypad 1/3` - First/last character in cell +- **Set headers**: `Fenrir + X` - Mark current line as column headers + +#### Table Features +- **Automatic detection**: Supports CSV, pipe-separated, space-aligned columns +- **Column headers**: Set and announce headers for better context +- **Boundary feedback**: Audio cues when reaching row boundaries +- **Cell-by-cell navigation**: Precise positioning within tables + +### Progress Bar Monitoring + +Fenrir automatically detects and provides audio feedback for progress indicators. + +#### Progress Detection +- **Percentage**: 45%, 67.5%, 100% +- **Fractions**: 15/100, 3 of 10, Step 7/15 +- **Progress bars**: [#### ], [====> ] +- **Activity indicators**: Loading..., Processing... + +#### Audio Feedback +- **Progress tones**: Ascending 400Hz-1200Hz frequency range +- **Activity beeps**: 800Hz tone every 2 seconds +- **Non-intrusive**: Doesn't interrupt speech or other audio + +#### Usage +- **Enable**: Use `progress_bar_monitor` command (assign key binding) +- **Automatic**: Works with downloads, compilations, installations +- **Remote control**: Enable via socket commands + ### Spell Checking - `Fenrir + S` - Spell check current word - `Fenrir + S S` - Add word to dictionary diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/test.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/test.py index 3b7ae543..4f721ce2 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/test.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/test.py @@ -20,22 +20,15 @@ class command: pass def get_description(self): - return _("presents the date") + return _("Test mc search functionality") def run(self): - date_format = self.env["runtime"]["SettingsManager"].get_setting( - "general", "date_format" - ) - - # get the time formatted - date_string = datetime.datetime.strftime( - datetime.datetime.now(), date_format - ) - - # present the time via speak and braile, there is no soundicon, - # interrupt the current speech + # Test command for mc search operations + test_message = _("MC search test: This demonstrates search functionality") + + # present the test message self.env["runtime"]["OutputManager"].present_text( - date_string, sound_icon="", interrupt=True + test_message, sound_icon="", interrupt=True ) def set_callback(self, callback): diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/test.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/test.py index 3b7ae543..37f4364e 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/test.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/test.py @@ -20,22 +20,15 @@ class command: pass def get_description(self): - return _("presents the date") + return _("Test mutt search functionality") def run(self): - date_format = self.env["runtime"]["SettingsManager"].get_setting( - "general", "date_format" - ) - - # get the time formatted - date_string = datetime.datetime.strftime( - datetime.datetime.now(), date_format - ) - - # present the time via speak and braile, there is no soundicon, - # interrupt the current speech + # Test command for mutt search operations + test_message = _("Mutt search test: This demonstrates search functionality") + + # present the test message self.env["runtime"]["OutputManager"].present_text( - date_string, sound_icon="", interrupt=True + test_message, sound_icon="", interrupt=True ) def set_callback(self, callback): diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/test.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/test.py index 3b7ae543..7bab4b1a 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/test.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/test.py @@ -20,22 +20,15 @@ class command: pass def get_description(self): - return _("presents the date") + return _("Test nano search functionality") def run(self): - date_format = self.env["runtime"]["SettingsManager"].get_setting( - "general", "date_format" - ) - - # get the time formatted - date_string = datetime.datetime.strftime( - datetime.datetime.now(), date_format - ) - - # present the time via speak and braile, there is no soundicon, - # interrupt the current speech + # Test command for nano search operations + test_message = _("Nano search test: This demonstrates search functionality") + + # present the test message self.env["runtime"]["OutputManager"].present_text( - date_string, sound_icon="", interrupt=True + test_message, sound_icon="", interrupt=True ) def set_callback(self, callback): diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/test.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/test.py index 3b7ae543..221bdd83 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/test.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/test.py @@ -20,22 +20,15 @@ class command: pass def get_description(self): - return _("presents the date") + return _("Test vim search functionality") def run(self): - date_format = self.env["runtime"]["SettingsManager"].get_setting( - "general", "date_format" - ) - - # get the time formatted - date_string = datetime.datetime.strftime( - datetime.datetime.now(), date_format - ) - - # present the time via speak and braile, there is no soundicon, - # interrupt the current speech + # Test command for vim search operations + test_message = _("Vim search test: This demonstrates search functionality") + + # present the test message self.env["runtime"]["OutputManager"].present_text( - date_string, sound_icon="", interrupt=True + test_message, sound_icon="", interrupt=True ) def set_callback(self, callback): diff --git a/src/fenrirscreenreader/core/processManager.py b/src/fenrirscreenreader/core/processManager.py index 7ea0385c..91c9325c 100644 --- a/src/fenrirscreenreader/core/processManager.py +++ b/src/fenrirscreenreader/core/processManager.py @@ -64,7 +64,7 @@ class ProcessManager: args=(event_queue, function, pargs, run_once), ) self._Processes.append(t) - else: # thread not implemented yet + else: # use thread instead of process t = Thread( target=self.custom_event_worker_thread, args=(event_queue, function, pargs, run_once), diff --git a/src/fenrirscreenreader/core/settingsManager.py b/src/fenrirscreenreader/core/settingsManager.py index 8d9ceb5a..ed5a4ea3 100644 --- a/src/fenrirscreenreader/core/settingsManager.py +++ b/src/fenrirscreenreader/core/settingsManager.py @@ -494,11 +494,14 @@ class SettingsManager: self.set_setting("general", "debug_level", 3) self.set_setting("general", "debug_mode", "PRINT") if cliArgs.emulated_pty: - self.set_setting("screen", "driver", "ptyDriver") - self.set_setting("keyboard", "driver", "ptyDriver") - # TODO needs cleanup use dict - # self.set_option_arg_dict('keyboard', 'keyboardLayout', 'pty') - self.set_setting("keyboard", "keyboardLayout", "pty") + # Set PTY driver settings + pty_settings = { + "screen": {"driver": "ptyDriver"}, + "keyboard": {"driver": "ptyDriver", "keyboardLayout": "pty"} + } + for section, settings in pty_settings.items(): + for key, value in settings.items(): + self.set_setting(section, key, value) if cliArgs.emulated_evdev: self.set_setting("screen", "driver", "ptyDriver") self.set_setting("keyboard", "driver", "evdevDriver")