56 Commits

Author SHA1 Message Date
Storm Dragon
0a2c8472c0 Fixed errors in README. Moved the audio configuration script stuff nearer the top. 2025-08-04 14:36:06 -04:00
Storm Dragon
69eade3327 Updated documentation for stand-alone pipewire or pulse configuration scripts. 2025-08-04 14:24:41 -04:00
Storm Dragon
73f67c2a04 Multiple fixes to indentation beep code, including volume for lower ranged beeps using the gstreamer driver. 2025-08-04 12:38:14 -04:00
Storm Dragon
9ef9d762f4 A few emoji updates. 2025-07-31 03:16:02 -04:00
Storm Dragon
84293db6dc Another shot at fixing multiple numpads. 2025-07-25 14:17:17 -04:00
Storm Dragon
94a1acbaca A few improvements to validation. 2025-07-24 14:05:51 -04:00
Storm Dragon
8c233e0385 Some syntax errors fixed. Syntax checking added. Release checklist created. 2025-07-24 13:52:10 -04:00
Storm Dragon
b6a9e1a692 Hopefully fixed problems with connection external numpads. 2025-07-23 00:01:46 -04:00
Storm Dragon
d41ea8388f Fixed url exclusion detection for progress bars. 2025-07-21 06:58:49 -04:00
Storm Dragon
b68a28e857 Added more emojis. 2025-07-17 11:11:35 -04:00
Storm Dragon
8c668cc0cc Final batch of pty driver fixes... For now. 2025-07-16 19:48:48 -04:00
Storm Dragon
579bf0f0f0 More work on the pty driver. 2025-07-16 19:43:07 -04:00
Storm Dragon
d1bad818cd initial improvements to pty driver. Improved clipboard handling of multibyte characters. Added emoji menu to vmenu. It places the emoji to the clipboard to be used wherever. 2025-07-16 19:35:26 -04:00
Storm Dragon
ae4c418323 A few minor progress bar beep tweaks. 2025-07-15 23:13:40 -04:00
Storm Dragon
0c116adaf2 Progress bar detection updates. 2025-07-13 11:18:51 -04:00
Storm Dragon
5a14804d11 Updates to documentation. A few tidying up changes. 2025-07-09 18:31:58 -04:00
Storm Dragon
6876995d4c New punctuation setting added. 2025-07-09 09:30:45 -04:00
Storm Dragon
01f4b64390 Replace skipped punctuation with space. There's a setting in general, on by default, that will revert to old behavior if you replace it with false. 2025-07-09 01:17:36 -04:00
Storm Dragon
5e858cfde1 Expirmental improvements to highlight tracking. 2025-07-09 01:06:54 -04:00
Storm Dragon
2ad754a372 Some fixes to pep8 stuff. 2025-07-08 18:35:12 -04:00
Storm Dragon
bb6dbc7186 Fixed character navigation in table mode. 2025-07-07 22:58:14 -04:00
Storm Dragon
c7cc9d039b Improved application detection, now works inside screen and tmux. Fixed incosistancies in prev/next word navigation. 2025-07-07 11:17:12 -04:00
Storm Dragon
d1a42835e4 Initial table mode added. Probably bugs. 2025-07-07 09:46:12 -04:00
Storm Dragon
3390c25dfe More pep8 fixes. A tiny bit of refactoring. 2025-07-07 00:42:23 -04:00
Storm Dragon
d28c18faed Found and sniped a couple more pep8 migration errors. 2025-07-05 09:29:32 -04:00
Storm Dragon
c90c726899 Fixed a bug in the remote manager. 2025-07-05 09:15:40 -04:00
Storm Dragon
bab7c1a552 Removed double keybinding from laptop layout. 2025-07-03 16:11:13 -04:00
Storm Dragon
848844aae4 Oops, forgot to delete my traceback notes. 2025-07-03 13:24:23 -04:00
Storm Dragon
4c1bddbbd3 Most of the pep8 changes finished. Be careful, things may be horribly broken. 2025-07-03 13:23:25 -04:00
Storm Dragon
21bb9c6083 Most of the pep8 changes finished. Be careful, things may be horribly broken. 2025-07-03 13:22:00 -04:00
Storm Dragon
7408951152 To make Fenrir easier to approach for new developer, start code migration to be pep8 compliant. 2025-07-01 22:23:50 -04:00
Storm Dragon
4bcf82178e Updated configure_pipewire script. A bit more code refactor. Preparing to start moving everything over to pep8 compliance. 2025-06-28 22:52:21 -04:00
Storm Dragon
beae1866bb Moved restore speech on prompt to existing temp interrupt speech command, Fenrir+kp_plus unbound now. 2025-06-28 01:49:20 -04:00
Storm Dragon
40b88efa34 Fix up a few errors that sneaked in while updating vmenu code and a couple other things. Logs should be much nicer now. 2025-06-25 10:56:08 -04:00
Storm Dragon
b1edc53362 Added missing dependency to requirements.txt. 2025-06-20 12:43:49 -04:00
Storm Dragon
dda84b9905 Final batch of code stability updates before anouther bout of extended testing. Still plenty to go, but making progress. 2025-06-20 03:34:50 -04:00
Storm Dragon
64e79f6945 Code cleanup, make sure race conditions can't happen, at least in theory. 2025-06-20 03:10:07 -04:00
Storm Dragon
f4ed8da4c3 Forgot one in last commit. 2025-06-20 03:04:25 -04:00
Storm Dragon
a5ca1d28e8 Make sure all except statements are no longer empty, should help a lot with debugging. 2025-06-20 03:03:43 -04:00
Storm Dragon
4e193f133f Fixed an error that crept into log permissions during code restructuring. 2025-06-20 02:19:07 -04:00
Storm Dragon
27dcff23bb Code optimization and bug fixes. Removed the broken, partial atspi driver implementation. 2025-06-18 15:08:36 -04:00
Storm Dragon
d81d563bb6 Add page up and page down to move through the voice browser by 10%. 2025-06-16 01:08:05 -04:00
Storm Dragon
43871cea3c Fixes to the voice driver. It should actually work completely now. 2025-06-15 19:52:18 -04:00
Storm Dragon
72bd334d65 Very experimental attempt to move the configure_fenrir script into fenrir itself using the vmenu system. Lots of testing please. 2025-06-15 14:04:14 -04:00
Storm Dragon
e76b914d6e Ignore screen 7 by default in case auto ignore screen doesn't work. 2025-06-12 18:43:12 -04:00
Storm Dragon
83cb330d34 Potential fixes to progress bar. Better handling of punctuation while reading. 2025-06-10 18:10:08 -04:00
Storm Dragon
b0ac6e1409 improved documentation for the diff generation. 2025-06-09 16:53:05 -04:00
Storm Dragon
6998706934 Testing fixes for security improvement, thread safety, and memory management. 2025-06-09 14:41:33 -04:00
Storm Dragon
62e1001679 Add keybinding for progress bar monitoring for laptop mode. Fenrir+Shift+P. 2025-06-09 13:11:51 -04:00
Storm Dragon
d935ef2e3c The fix for hopefully not reading all spaces broke review by character. Hopefully fix that. 2025-06-09 12:48:02 -04:00
Storm Dragon
e2fb28d92f Attempt to fix the bug where fenrir sometimes reads all the spaces in a message. 2025-06-09 02:33:36 -04:00
Storm Dragon
8a223282df Some modifications to progress bar detection, can revert if needed. 2025-06-09 02:19:39 -04:00
Storm Dragon
91c97dd1dd Fixed error in settings file, Time and date need %% instead of just a single %. 2025-06-08 18:04:06 -04:00
Storm Dragon
5cc719a6f3 Commit 2 of 2, code refactor and cleanup. 2025-06-08 14:26:24 -04:00
Storm Dragon
ddc1b43304 Commit 1 of 2, code refactor and cleanup. 2025-06-08 13:49:22 -04:00
Storm Dragon
6ad11effc6 Enhanced prompt detection 2025-06-08 13:31:37 -04:00
528 changed files with 26546 additions and 10618 deletions

250
README.md
View File

@@ -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
@@ -132,6 +134,58 @@ By default Fenrir uses:
- **Input driver**: evdevDriver (Linux) or ptyDriver (other platforms)
- **Screen driver**: vcsaDriver (Linux TTY) or ptyDriver (terminal emulation)
## Audio Configuration
Both PulseAudio and PipeWire require special configuration to allow console applications running as root (like Fenrir) to route audio to your regular user session. This is normal audio system behavior, not a Fenrir issue.
### Quick Setup - Direct Script Download
For non-Fenrir users or quick setup, download and run these scripts directly:
#### PulseAudio Configuration
```bash
# Download the script
wget https://git.stormux.org/storm/fenrir/raw/branch/master/tools/configure_pulse.sh
chmod +x configure_pulse.sh
# Run twice: once as user, once as root
./configure_pulse.sh
sudo ./configure_pulse.sh
```
#### PipeWire Configuration
```bash
# Download the script
wget https://git.stormux.org/storm/fenrir/raw/branch/master/tools/configure_pipewire.sh
chmod +x configure_pipewire.sh
# Run twice: once as user, once as root
./configure_pipewire.sh
sudo ./configure_pipewire.sh
```
**Direct links:**
- [configure_pulse.sh](https://git.stormux.org/storm/fenrir/raw/branch/master/tools/configure_pulse.sh)
- [configure_pipewire.sh](https://git.stormux.org/storm/fenrir/raw/branch/master/tools/configure_pipewire.sh)
### Using Installed Scripts
If you have Fenrir installed, the scripts are available at:
**PulseAudio:**
```bash
/usr/share/fenrirscreenreader/tools/configure_pulse.sh
sudo /usr/share/fenrirscreenreader/tools/configure_pulse.sh
```
**PipeWire:**
```bash
/usr/share/fenrirscreenreader/tools/configure_pipewire.sh
sudo /usr/share/fenrirscreenreader/tools/configure_pipewire.sh
```
**Note:** These scripts work for any console application that needs root audio access, not just Fenrir.
## Getting Started
### Basic Usage
@@ -156,6 +210,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 +457,176 @@ setting <action> [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
@@ -467,31 +692,6 @@ send_fenrir_command("setting set speech#rate=0.9")
- Check Fenrir debug logs: `/var/log/fenrir.log`
- Test with simple command: `echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock`
## Configure pulseaudio
Pulseaudio by default only plays sound for the user its currently running for. As fenrir is running as root, your local user does not hear the sound and speech produced by fenrir.
for this fenrir provides a script to configure pulseaudio to stream the sound played as root to your local user. This is not a issue of fenrir but this is how pulseaudio works.
just run the configuration script twice (once as user, once as root):
/usr/share/fenrirscreenreader/tools/configure_pulse.sh
sudo /usr/share/fenrirscreenreader/tools/configure_pulse.sh
The script is also located in the tools directory in git
## Configure pipewire
Pipewire by default only plays sound for the user its currently running for. As fenrir is running as root, your local user does not hear the sound and speech produced by fenrir.
for this fenrir provides a script to configure pipewire to stream the sound played as root to your local user. This is not a issue of fenrir but this is how pipewire works.
just run the configuration script twice (once as user, once as root):
/usr/share/fenrirscreenreader/tools/configure_pipewire.sh
sudo /usr/share/fenrirscreenreader/tools/configure_pipewire.sh
The script is also located in the tools directory in git
## Command Line Options
Fenrir supports several command-line options for different use cases:

192
RELEASE_CHECKLIST.md Normal file
View File

@@ -0,0 +1,192 @@
# Fenrir Release Validation Checklist
This checklist ensures thorough validation before releasing Fenrir packages.
## 🔧 Setup Tools (One-time setup)
### Install Pre-commit Hook
```bash
# Safely install composite hook (preserves existing version management)
./tools/install_validation_hook.sh
# Test the hook
./.git/hooks/pre-commit
```
### Validation Scripts
- `tools/validate_syntax.py` - Python syntax validation
- `tools/validate_pep8.py` - PEP8 compliance checking with safe auto-fix
- `tools/validate_release.py` - Comprehensive release validation
- `tools/cleanup_cache.py` - Remove Python cache files and directories
- `tools/pre-commit-hook` - Git pre-commit validation
## 📋 Pre-Release Checklist
### 1. Code Quality Validation ✅
```bash
# Comprehensive release validation (includes syntax, imports, structure)
python3 tools/validate_release.py
# If issues found, try auto-fix
python3 tools/validate_release.py --fix
# Quick validation (skips slow dependency checks)
python3 tools/validate_release.py --quick
```
**Expected Result**: All tests pass, no syntax errors
### 2. Dependency Validation ✅
```bash
# Validate all dependencies are available
python3 check-dependencies.py
```
**Expected Result**: All required dependencies reported as available
### 3. Core Functionality Test ✅
```bash
# Test core imports (safe to run without sudo)
cd src
python3 -c "
import fenrirscreenreader.core.fenrirManager
import fenrirscreenreader.core.commandManager
import fenrirscreenreader.core.eventManager
print('Core imports successful')
"
cd ..
```
**Expected Result**: No import errors
### 4. Installation Script Validation ✅
```bash
# Validate setup.py syntax
python3 -m py_compile setup.py
# Check setup.py can be parsed
python3 setup.py --help-commands >/dev/null
```
**Expected Result**: No syntax errors, setup.py functional
### 5. Configuration Validation ✅
```bash
# Verify config files exist and are parseable
ls -la config/settings/settings.conf
ls -la config/keyboard/desktop.conf
ls -la config/punctuation/default.conf
```
**Expected Result**: All core config files present
### 6. Manual Testing (User/Package Maintainer) ⚠️
**Important**: These require user interaction as they need sudo access or specific hardware.
```bash
# Test basic functionality (ask user to run)
sudo ./src/fenrir --help
# Test in emulation mode (safer for desktop environments)
sudo ./src/fenrir -e --version
# Quick functionality test (3-5 seconds)
sudo timeout 5 ./src/fenrir -e -f || echo "Timeout reached (expected)"
```
**Expected Result**: No immediate crashes, basic help/version output works
### 7. Package-Specific Validation ✅
```bash
# Test the same compilation process used by package managers
python3 -m compileall src/fenrirscreenreader/ -q
# Verify no __pycache__ permission issues
find src/ -name "*.pyc" -delete
find src/ -name "__pycache__" -delete
```
**Expected Result**: Clean compilation, no permission errors
## 🚨 Known Issue Categories
### Critical Issues (Block Release)
- **Python syntax errors** (SyntaxError, unterminated strings)
- **Missing core dependencies** (dbus-python, evdev, etc.)
- **Import failures in core modules** (fenrirManager, commandManager)
- **Missing critical config files** (settings.conf, desktop.conf)
### Warning Issues (Address if Possible)
- **PEP8 violations** (cosmetic, don't block release)
- **Missing optional dependencies** (for specific features)
- **Command structure issues** (missing methods in command files)
- **Very long lines** (>120 characters)
## 🔍 Root Cause Analysis
### Why These Errors Weren't Caught Previously
1. **No automated syntax validation** - The codebase relied on manual testing
2. **No pre-commit hooks** - Syntax errors could be committed
3. **No CI/CD pipeline** - Package compilation happens only during release
4. **Manual PEP8 cleanup** - F-string refactoring introduced syntax errors during batch cleanup
## 📖 Usage Instructions
### For Developers
```bash
# Before committing changes
git add .
git commit # Pre-commit hook will run automatically
# Before creating tags/releases
python3 tools/validate_release.py
```
### For Package Maintainers
```bash
# Before packaging
python3 tools/validate_release.py
# If validation fails
python3 tools/validate_release.py --fix
# Quick check (if dependencies are known good)
python3 tools/validate_release.py --quick
```
### For Release Managers
```bash
# Complete validation before tagging
python3 tools/validate_release.py
# Manual verification (requires sudo)
sudo ./src/fenrir --version
# Tag release only after all validations pass
git tag -a v2.x.x -m "Release v2.x.x"
```
## 🎯 Future Improvements
### Recommended Additions
1. **GitHub Actions CI/CD** - Automated validation on every push
2. **Automated testing** - Unit tests for core functionality
3. **Integration testing** - Test driver interactions
4. **Package testing** - Validate actual package installation
### Modern Python Packaging
- Consider migrating to `pyproject.toml` (PEP 621)
- Use `build` instead of `setup.py` directly
- Add `tox.ini` for multi-environment testing
## 📞 Support
If validation fails and auto-fix doesn't resolve issues:
1. **Check the specific error messages** in validation output
2. **Review recent commits** that might have introduced issues
3. **Run individual validation steps** to isolate problems
Remember: **Working code is better than perfect code** - especially for accessibility software where reliability is critical.

View File

@@ -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():

View File

@@ -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

View File

@@ -74,7 +74,7 @@ KEY_FENRIR,KEY_0=bookmark_10
KEY_FENRIR,KEY_KPSLASH=set_window_application
2,KEY_FENRIR,KEY_KPSLASH=clear_window_application
KEY_KPPLUS=progress_bar_monitor
KEY_FENRIR,KEY_KPPLUS=silence_until_prompt
#KEY_FENRIR,KEY_KPPLUS=silence_until_prompt
KEY_FENRIR,KEY_F2=toggle_braille
KEY_FENRIR,KEY_F3=toggle_sound
KEY_FENRIR,KEY_F4=toggle_speech
@@ -114,6 +114,8 @@ KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_X=remove_marks
KEY_FENRIR,KEY_X=set_mark
KEY_FENRIR,KEY_SHIFT,KEY_X=marked_text
KEY_FENRIR,KEY_F10=toggle_vmenu_mode
KEY_FENRIR,KEY_SHIFT,KEY_F10=voice_browser_safe
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_F10=apply_tested_voice
KEY_FENRIR,KEY_SPACE=current_quick_menu_entry
KEY_FENRIR,KEY_CTRL,KEY_SPACE=current_quick_menu_value
KEY_FENRIR,KEY_RIGHT=next_quick_menu_entry

View File

@@ -75,12 +75,12 @@ KEY_FENRIR,KEY_F2=toggle_braille
KEY_FENRIR,KEY_F3=toggle_sound
KEY_FENRIR,KEY_F4=toggle_speech
KEY_FENRIR,KEY_ENTER=temp_disable_speech
KEY_FENRIR,KEY_SHIFT,KEY_ENTER=silence_until_prompt
KEY_FENRIR,KEY_SHIFT,KEY_P=progress_bar_monitor
KEY_FENRIR,KEY_SHIFT,KEY_ENTER=toggle_auto_read
KEY_FENRIR,KEY_SHIFT,KEY_CTRL,KEY_P=toggle_punctuation_level
KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_ENTER=toggle_output
KEY_FENRIR,KEY_SHIFT,KEY_E=toggle_emoticons
KEY_FENRIR,KEY_ENTER=toggle_auto_read
KEY_FENRIR,KEY_CTRL,KEY_T=toggle_auto_time
KEY_FENRIR,KEY_Y=toggle_highlight_tracking
#=toggle_barrier
@@ -112,6 +112,8 @@ KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_X=remove_marks
KEY_FENRIR,KEY_X=set_mark
KEY_FENRIR,KEY_SHIFT,KEY_X=marked_text
KEY_FENRIR,KEY_F10=toggle_vmenu_mode
KEY_FENRIR,KEY_SHIFT,KEY_F10=voice_browser_safe
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_F10=apply_tested_voice
KEY_FENRIR,KEY_SPACE=current_quick_menu_entry
KEY_FENRIR,KEY_CTRL,KEY_SPACE=current_quick_menu_value
KEY_FENRIR,KEY_RIGHT=next_quick_menu_entry

View File

@@ -95,7 +95,7 @@ fenrirMaxRate=450
driver=vcsaDriver
encoding=auto
screenUpdateDelay=0.05
ignoreScreen=
ignoreScreen=7
autodetectIgnoreScreen=True
[keyboard]
@@ -124,7 +124,9 @@ interruptOnKeyPressFilter=
doubleTapTimeout=0.2
[general]
debugLevel=0
# Debug levels: 0=DEACTIVE, 1=ERROR, 2=WARNING, 3=INFO (most verbose)
# For production use, WARNING (2) provides good balance of useful info without spam
debugLevel=2
# debugMode sets where the debug output should send to:
# debugMode=File writes to debugFile (Default:/tmp/fenrir-PID.log)
# debugMode=Print just prints on the screen
@@ -133,6 +135,9 @@ debugFile=
punctuationProfile=default
punctuationLevel=some
respectPunctuationPause=True
# Replace undefined punctuation with spaces instead of removing them
# This improves readability of text with punctuation like [X]mute, IP addresses, etc.
replaceUndefinedPunctuationWithSpace=True
newLinePause=True
numberOfClipboards=50
# used path for "export_clipboard_to_file"
@@ -143,8 +148,8 @@ emoticons=True
# define the current Fenrir key
fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT
scriptKeys=KEY_COMPOSE
timeFormat=%H:%M:%P
dateFormat=%A, %B %d, %Y
timeFormat=%%I:%%M%%P
dateFormat=%%A, %%B %%d, %%Y
autoSpellCheck=True
spellCheckLanguage=en_US
# path for your scripts "scriptKeys" functionality
@@ -218,16 +223,24 @@ quickMenu=speech#rate;speech#pitch;speech#volume
# Custom prompt patterns for silence until prompt feature
# You can add your own shell prompt patterns as regular expressions
# Each pattern should be on a separate line, format: customPatterns=pattern1,pattern2,pattern3
# Examples:
#
# Built-in patterns include:
# - Shell prompts: $, #, >, user@host$, [user@host]$, bash-5.1$
# - Package manager prompts: [Y/n], [y/N], [Yes/No], (Y/n), (y/N)
# - sudo prompts: [sudo] password for user:, Password:, user's password:
# - Confirmation prompts: Press any key, Are you sure?, Please confirm
#
# Custom pattern examples:
# For PS1='[\u@\h \W] \$ ' use: \[.*@.*\s.*\]\s*[$#>]\s*
# For "[user@hostname ~] $" use: \[.*@.*\s.*\]\s*[$#>]\s*
# For custom prompts ending with specific strings, use patterns like: .*your_prompt_ending$
# For custom package manager prompts: .*your_package_manager.*\[[YyNn]/[YyNn]\].*
customPatterns=
# Specific prompt strings to match exactly (useful for very specific custom prompts)
# Format: exactMatches=prompt1,prompt2,prompt3
# Examples:
# exactMatches=[storm@fenrir ~] $,[root@fenrir ~] #
# exactMatches=[storm@fenrir ~] $,[root@fenrir ~] #,Continue installation? [Y/n]
exactMatches=
[time]

Binary file not shown.

Binary file not shown.

View File

@@ -30,9 +30,6 @@ ContentChanged='ContentChanged.wav'
# Speech has turned On or Off
SpeechOn='SpeechOn.wav'
SpeechOff='SpeechOff.wav'
# Braille has turned On or Off
BrailleOn='BrailleOn.wav'
BrailleOff='BrailleOff.wav'
# SoundIcons has turned On or Off
SoundOn='SoundOn.wav'
SoundOff='SoundOff.wav'
@@ -44,9 +41,8 @@ PlaceEndMark='PlaceEndMark.wav'
CopyToClipboard='CopyToClipboard.wav'
# Pasted on the screen
PasteClipboardOnScreen='PasteClipboardOnScreen.wav'
# An error accoured while speech or braille output or reading the screen
# An error accoured while speech output or reading the screen
ErrorSpeech='ErrorSpeech.wav'
ErrorBraille='ErrorBraille.wav'
ErrorScreen='ErrorScreen.wav'
# If you cursor over an text that has attributs (like color)
HasAttributes='has_attribute.wav'

View File

@@ -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

View File

@@ -1,4 +1,5 @@
daemonize
dbus-python
evdev
pexpect
pyenchant

View File

@@ -37,7 +37,7 @@ for directory in directories:
if not forceSettingsFlag:
try:
files = [f for f in files if not f.endswith('settings.conf')]
except:
except Exception as e:
pass
elif 'config/scripts' in directory:
destDir = '/usr/share/fenrirscreenreader/scripts'

View File

@@ -4,19 +4,22 @@
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
import argparse
import inspect
import os
import sys
import inspect
import argparse
from daemonize import Daemonize
from fenrirscreenreader import fenrirVersion
from fenrirscreenreader.core import fenrirManager
# Get the fenrir installation path
fenrirPath = os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe()))))
if not fenrirPath in sys.path:
fenrirPath = os.path.dirname(os.path.realpath(
os.path.abspath(inspect.getfile(inspect.currentframe()))))
if fenrirPath not in sys.path:
sys.path.append(fenrirPath)
from fenrirscreenreader.core import fenrirManager
from fenrirscreenreader import fenrirVersion
def create_argument_parser():
"""Create and return the argument parser for Fenrir"""
@@ -27,7 +30,7 @@ def create_argument_parser():
argumentParser.add_argument(
'-v', '--version',
action='version',
version=f'Fenrir screen reader version {fenrirVersion.version}-{fenrirVersion.codeName}',
version=f'Fenrir screen reader version {fenrirVersion.version}-{fenrirVersion.code_name}',
help='Show version information and exit'
)
argumentParser.add_argument(
@@ -68,10 +71,10 @@ def create_argument_parser():
help='Use PTY emulation with evdev for input (single instance)'
)
argumentParser.add_argument(
'-F', '--force-all-screens',
'-F',
'--force-all-screens',
action='store_true',
help='Force Fenrir to respond on all screens, ignoring ignoreScreen setting'
)
help='Force Fenrir to respond on all screens, ignoring ignoreScreen setting')
argumentParser.add_argument(
'-i', '-I', '--ignore-screen',
metavar='SCREEN',
@@ -80,29 +83,52 @@ def create_argument_parser():
)
return argumentParser
def validate_arguments(cliArgs):
"""Validate command line arguments"""
if cliArgs.options:
for option in cliArgs.options.split(';'):
if option and ('#' not in option or '=' not in option):
return False, f"Invalid option format: {option}\nExpected format: SECTION#SETTING=VALUE"
if cliArgs.emulated_pty and cliArgs.emulated_evdev:
return False, "Cannot use both --emulated-pty and --emulated-evdev simultaneously"
return True, None
def run_fenrir():
"""Main function that runs Fenrir"""
fenrirApp = fenrirManager.fenrirManager(cliArgs)
fenrirApp.proceed()
del fenrirApp
fenrirApp = None
try:
fenrirApp = fenrirManager.FenrirManager(cliArgs)
fenrirApp.proceed()
except Exception as e:
print(f"Error starting Fenrir: {e}", file=sys.stderr)
if fenrirApp and hasattr(fenrirApp, 'cleanup_on_error'):
try:
fenrirApp.cleanup_on_error()
except Exception as cleanup_error:
print(
f"Error during cleanup: {cleanup_error}", file=sys.stderr)
sys.exit(1)
finally:
if fenrirApp:
del fenrirApp
# Clean up PID file if it exists
pidFile = "/run/fenrir.pid"
if os.path.exists(pidFile):
try:
os.remove(pidFile)
except Exception:
pass
def main():
global cliArgs
argumentParser = create_argument_parser()
cliArgs = argumentParser.parse_args()
# Validate arguments
isValid, errorMsg = validate_arguments(cliArgs)
if not isValid:
@@ -123,5 +149,6 @@ def main():
)
daemonProcess.start()
if __name__ == "__main__":
main()

View File

@@ -2,20 +2,27 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return 'No description found'
def get_description(self):
return "No description found"
def run(self):
pass
def setCallback(self, callback):
def set_callback(self, callback):
pass

View File

@@ -2,25 +2,38 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
# this command is just to initialize stuff.
# like init index lists in memoryManager
# like init index lists in MemoryManager
# it is not useful to execute it
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
# clipboard
self.env['runtime']['memoryManager'].addIndexList('clipboardHistory', self.env['runtime']['settingsManager'].getSettingAsInt('general', 'numberOfClipboards'))
self.env["runtime"]["MemoryManager"].add_index_list(
"clipboardHistory",
self.env["runtime"]["SettingsManager"].get_setting_as_int(
"general", "numberOfClipboards"
),
)
def shutdown(self):
pass
def getDescription(self):
return 'No description found'
def get_description(self):
return "No description found"
def run(self):
pass
def setCallback(self, callback):
def set_callback(self, callback):
pass

View File

@@ -2,53 +2,92 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import word_utils
import string
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import word_utils
initialized = False
try:
import enchant
initialized = True
except:
except Exception as e:
pass
class command():
class command:
def __init__(self):
self.language = ''
self.language = ""
self.spellChecker = None
def initialize(self, environment):
self.env = environment
self.updateSpellLanguage()
self.update_spell_language()
def shutdown(self):
pass
def getDescription(self):
return _('adds the current word to the exceptions dictionary')
def updateSpellLanguage(self):
self.spellChecker = enchant.Dict(self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage'))
self.language = self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage')
pass
def get_description(self):
return _("adds the current word to the exceptions dictionary")
def update_spell_language(self):
self.spellChecker = enchant.Dict(
self.env["runtime"]["SettingsManager"].get_setting(
"general", "spellCheckLanguage"
)
)
self.language = self.env["runtime"]["SettingsManager"].get_setting(
"general", "spellCheckLanguage"
)
def run(self):
if not initialized:
return
if self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') != self.language:
return
if (
self.env["runtime"]["SettingsManager"].get_setting(
"general", "spellCheckLanguage"
)
!= self.language
):
try:
self.updateSpellLanguage()
self.update_spell_language()
except Exception as e:
return
cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor()
return
cursor_pos = self.env["runtime"][
"CursorManager"
].get_review_or_text_cursor()
# get the word
newContent = self.env['screen']['newContentText'].split('\n')[cursorPos['y']]
x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord(cursorPos['x'], 0, newContent)
currWord = currWord.strip(string.whitespace + r'!"#$%&\()*+,-./:;<=Â?@[\\]^_{|}~')
new_content = self.env["screen"]["new_content_text"].split("\n")[
cursor_pos["y"]
]
x, y, curr_word, end_of_screen, line_break = (
word_utils.get_current_word(cursor_pos["x"], 0, new_content)
)
curr_word = curr_word.strip(
string.whitespace + r'!"#$%&\()*+,-./:;<=Â?@[\\]^_{|}~'
)
if currWord != '':
if self.spellChecker.is_added(currWord):
self.env['runtime']['outputManager'].presentText(_('{0} is already in dictionary').format(currWord,), soundIcon='Cancel', interrupt=True)
if curr_word != "":
if self.spellChecker.is_added(curr_word):
self.env["runtime"]["OutputManager"].present_text(
_("{0} is already in dictionary").format(
curr_word,
),
sound_icon="Cancel",
interrupt=True,
)
else:
self.spellChecker.add(currWord)
self.env['runtime']['outputManager'].presentText(_('{0} added to dictionary').format(currWord,), soundIcon='Accept', interrupt=True)
self.spellChecker.add(curr_word)
self.env["runtime"]["OutputManager"].present_text(
_("{0} added to dictionary").format(
curr_word,
),
sound_icon="Accept",
interrupt=True,
)
def setCallback(self, callback):
def set_callback(self, callback):
pass

View File

@@ -0,0 +1,108 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
import math
from fenrirscreenreader.core.i18n import _
class adjustment_command:
"""Base class for speech and sound adjustment commands"""
def __init__(self, section, setting, direction, step=0.1):
self.section = section # 'speech' or 'sound'
self.setting = setting # 'rate', 'pitch', 'volume'
self.direction = direction # 'inc' or 'dec'
self.step = step
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def get_description(self):
action = "Increase" if self.direction == "inc" else "Decrease"
if self.section == "speech":
return _(f"{action} the speech {self.setting}")
else:
return _(f"{action} the {self.section} {self.setting}")
def run(self):
if self.section == "sound" and self.setting == "volume":
# Sound volume uses different method
self._adjust_sound_volume()
else:
# Speech rate, pitch, volume use standard method
self._adjust_speech_setting()
def _adjust_speech_setting(self):
"""Adjust speech settings (rate, pitch, volume)"""
value = self.env["runtime"]["SettingsManager"].get_setting_as_float(
self.section, self.setting
)
# Apply adjustment with rounding
if self.direction == "inc":
value = round((math.ceil(10 * value) / 10) + self.step, 2)
if value > 1.0:
value = 1.0
else: # dec
value = round((math.ceil(10 * value) / 10) - self.step, 2)
if value < 0.0:
value = 0.0
# Set the new value
self.env["runtime"]["SettingsManager"].set_setting(
self.section, self.setting, str(value)
)
# Present feedback
percentage = int(value * 100)
if self.section == "speech":
feedback = _("{0} percent speech {1}").format(
percentage, self.setting
)
else:
feedback = _("{0} percent {1} {2}").format(
percentage, self.section, self.setting
)
self.env["runtime"]["OutputManager"].present_text(
feedback, sound_icon="", interrupt=True
)
def _adjust_sound_volume(self):
"""Adjust sound volume using same logic as speech"""
value = self.env["runtime"]["SettingsManager"].get_setting_as_float(
self.section, self.setting
)
# Sound volume uses same math as speech settings
if self.direction == "inc":
value = round((math.ceil(10 * value) / 10) + self.step, 2)
if value > 1.0:
value = 1.0
else: # dec
value = round((math.ceil(10 * value) / 10) - self.step, 2)
if value < 0.0:
value = 0.0
# Set the new value
self.env["runtime"]["SettingsManager"].set_setting(
self.section, self.setting, str(value)
)
# Present feedback with appropriate sound icon
percentage = int(value * 100)
sound_icon = "SoundOn" if self.direction == "inc" else "SoundOff"
feedback = _("{0} percent sound volume").format(percentage)
self.env["runtime"]["OutputManager"].present_text(
feedback, sound_icon=sound_icon, interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,26 +2,36 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader import fenrirVersion
from fenrirscreenreader.core.i18n import _
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Present the version of Fenrir currrrently in use.')
def get_description(self):
return _("Present the version of Fenrir currently in use.")
def run(self):
try:
self.env['runtime']['outputManager'].presentText(f'Fenrir screen reader version {fenrirVersion.version}-{fenrirVersion.codeName}', interrupt=True)
except exception as e:
self.env['runtime']['outputManager'].presentText(_('Version information is unavailable.'), interrupt=True)
def setCallback(self, callback):
self.env["runtime"]["OutputManager"].present_text(
f"Fenrir screen reader version "
f"{fenrirVersion.version}-{fenrirVersion.code_name}",
interrupt=True,
)
except Exception as e:
self.env["runtime"]["OutputManager"].present_text(
_("Version information is unavailable."), interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -0,0 +1,94 @@
#!/usr/bin/env python3
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def get_description(self):
return "Apply the last tested voice from safe voice browser"
def run(self):
try:
# Check if we have a tested voice
if (
"commandBuffer" not in self.env
or "lastTestedModule" not in self.env["commandBuffer"]
or "lastTestedVoice" not in self.env["commandBuffer"]
):
self.env["runtime"]["OutputManager"].present_text(
"No voice has been tested yet", interrupt=True
)
self.env["runtime"]["OutputManager"].present_text(
"Use voice browser first", interrupt=True
)
return
module = self.env["commandBuffer"]["lastTestedModule"]
voice = self.env["commandBuffer"]["lastTestedVoice"]
self.env["runtime"]["OutputManager"].present_text(
f"Applying {voice} from {module}", interrupt=True
)
# Apply to runtime settings only (temporary until saved)
SettingsManager = self.env["runtime"]["SettingsManager"]
# Store old values for safety
old_driver = SettingsManager.get_setting("speech", "driver")
old_module = SettingsManager.get_setting("speech", "module")
old_voice = SettingsManager.get_setting("speech", "voice")
try:
# Apply new settings to runtime only (use set_setting to update
# settingArgDict)
SettingsManager.set_setting(
"speech", "driver", "speechdDriver"
)
SettingsManager.set_setting("speech", "module", module)
SettingsManager.set_setting("speech", "voice", voice)
# Apply to speech driver instance directly
if "SpeechDriver" in self.env["runtime"]:
SpeechDriver = self.env["runtime"]["SpeechDriver"]
# Set the module and voice on the driver instance
SpeechDriver.set_module(module)
SpeechDriver.set_voice(voice)
self.env["runtime"]["OutputManager"].present_text(
"Voice applied successfully!", interrupt=True
)
self.env["runtime"]["OutputManager"].present_text(
"Use save settings to make permanent", interrupt=True
)
self.env["runtime"]["OutputManager"].play_sound("Accept")
except Exception as e:
# Revert on failure
SettingsManager.set_setting("speech", "driver", old_driver)
SettingsManager.set_setting("speech", "module", old_module)
SettingsManager.set_setting("speech", "voice", old_voice)
self.env["runtime"]["OutputManager"].present_text(
f"Failed to apply voice, reverted: {str(e)}",
interrupt=True,
)
self.env["runtime"]["OutputManager"].play_sound("Error")
except Exception as e:
self.env["runtime"]["OutputManager"].present_text(
f"Apply voice error: {str(e)}", interrupt=True
)
self.env["runtime"]["OutputManager"].play_sound("Error")
def set_callback(self, callback):
pass

View File

@@ -2,29 +2,45 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import screen_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Reads attributes of current cursor position')
def get_description(self):
return _("Reads attributes of current cursor position")
def run(self):
cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor()
cursor_pos = self.env["runtime"][
"CursorManager"
].get_review_or_text_cursor()
try:
attributes = self.env['runtime']['attributeManager'].getAttributeByXY( cursorPos['x'], cursorPos['y'])
attributes = self.env["runtime"][
"AttributeManager"
].get_attribute_by_xy(cursor_pos["x"], cursor_pos["y"])
except Exception as e:
print(e)
attributeFormatString = self.env['runtime']['settingsManager'].getSetting('general', 'attributeFormatString')
attributeFormatString = self.env['runtime']['attributeManager'].formatAttributes(attributes, attributeFormatString)
self.env['runtime']['outputManager'].presentText(attributeFormatString, soundIcon='', interrupt=True)
def setCallback(self, callback):
print(e)
attribute_format_string = self.env["runtime"][
"SettingsManager"
].get_setting("general", "attribute_format_string")
attribute_format_string = self.env["runtime"][
"AttributeManager"
].format_attributes(attributes, attribute_format_string)
self.env["runtime"]["OutputManager"].present_text(
attribute_format_string, sound_icon="", interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '1'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(1, "read")

View File

@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '10'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(10, "read")

View File

@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '2'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(2, "read")

View File

@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '3'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(3, "read")

View File

@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '4'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(4, "read")

View File

@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '5'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(5, "read")

View File

@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '6'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(6, "read")

View File

@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '7'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(7, "read")

View File

@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '8'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(8, "read")

View File

@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '9'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(9, "read")

View File

@@ -0,0 +1,211 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import line_utils
from fenrirscreenreader.utils import mark_utils
class bookmark_command:
"""Base class for bookmark operations - read, set, clear"""
def __init__(self, bookmark_id, action="read"):
self.ID = str(bookmark_id)
self.action = action
def initialize(self, environment):
self.env = environment
# Always initialize bookmark structure - all commands need this
if self.ID not in self.env["commandBuffer"]["bookMarks"]:
self.env["commandBuffer"]["bookMarks"][self.ID] = {}
def shutdown(self):
pass
def get_description(self):
if self.action == "read":
return _("read Bookmark {0}").format(self.ID)
elif self.action == "set":
return _("set Bookmark {0}").format(self.ID)
elif self.action == "clear":
return _("remove Bookmark {0}").format(self.ID)
return f"{self.action} Bookmark {self.ID}"
def run(self):
if self.action == "read":
self._read_bookmark()
elif self.action == "set":
self._set_bookmark()
elif self.action == "clear":
self._clear_bookmark()
def _read_bookmark(self):
curr_app = self.env["runtime"][
"ApplicationManager"
].get_current_application()
if not self.env["commandBuffer"]["bookMarks"][self.ID]:
self.env["runtime"]["OutputManager"].present_text(
"Bookmark {0} not set".format(self.ID), interrupt=True
)
return
if curr_app not in self.env["commandBuffer"]["bookMarks"][self.ID]:
self.env["runtime"]["OutputManager"].present_text(
"Bookmark for application {0} not set".format(curr_app),
interrupt=True,
)
return
if not self.env["commandBuffer"]["bookMarks"][self.ID][curr_app].get(
"1"
):
self.env["runtime"]["OutputManager"].present_text(
"Bookmark for application {0} not set".format(curr_app),
interrupt=True,
)
return
# Get bookmarked text
marked = ""
start_mark = self.env["commandBuffer"]["bookMarks"][self.ID][curr_app][
"1"
].copy()
if self.env["commandBuffer"]["bookMarks"][self.ID][curr_app]["2"]:
end_mark = self.env["commandBuffer"]["bookMarks"][self.ID][
curr_app
]["2"].copy()
marked = mark_utils.get_text_between_marks(
start_mark, end_mark, self.env["screen"]["new_content_text"]
)
else:
x, y, marked = line_utils.get_current_line(
start_mark["x"],
start_mark["y"],
self.env["screen"]["new_content_text"],
)
if marked.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), sound_icon="EmptyLine", interrupt=True
)
else:
self.env["runtime"]["OutputManager"].present_text(
marked, interrupt=True
)
def _set_bookmark(self):
if not self.env["commandBuffer"]["Marks"]["1"]:
self.env["runtime"]["OutputManager"].present_text(
_("No mark found"), interrupt=True
)
return
curr_app = self.env["runtime"][
"ApplicationManager"
].get_current_application()
self.env["commandBuffer"]["bookMarks"][self.ID][curr_app] = {}
bookmarks = self.env["commandBuffer"]["bookMarks"][self.ID][curr_app]
bookmarks["1"] = self.env["commandBuffer"]["Marks"]["1"].copy()
if self.env["commandBuffer"]["Marks"]["2"]:
bookmarks["2"] = self.env["commandBuffer"]["Marks"]["2"].copy()
else:
bookmarks["2"] = None
self.env["runtime"]["OutputManager"].present_text(
_("Bookmark {0} set for application {1}").format(
self.ID, curr_app
),
interrupt=True,
)
# Clear marks after setting bookmark
self.env["commandBuffer"]["Marks"]["1"] = None
self.env["commandBuffer"]["Marks"]["2"] = None
def _clear_bookmark(self):
curr_app = self.env["runtime"][
"ApplicationManager"
].get_current_application()
bookmarks = self.env["commandBuffer"]["bookMarks"]
if self.ID in bookmarks and curr_app in bookmarks[self.ID]:
del self.env["commandBuffer"]["bookMarks"][self.ID][curr_app]
self.env["runtime"]["OutputManager"].present_text(
_("Bookmark {0} removed for application {1}").format(
self.ID, curr_app
),
interrupt=True,
)
else:
self.env["runtime"]["OutputManager"].present_text(
_("Bookmark {0} not set for application {1}").format(
self.ID, curr_app
),
interrupt=True,
)
def set_callback(self, callback):
pass
# Factory function to create bookmark command instances
def create_bookmark_commands():
"""Create all bookmark command instances"""
commands = {}
# Create read bookmark commands (bookmark_1 through bookmark_10)
for i in range(1, 11):
commands[f"bookmark_{i}"] = lambda i=i: bookmark_command(i, "read")
# Create set bookmark commands (set_bookmark_1 through set_bookmark_10)
for i in range(1, 11):
commands[f"set_bookmark_{i}"] = lambda i=i: bookmark_command(i, "set")
# Create clear bookmark commands (clear_bookmark_1 through
# clear_bookmark_10)
for i in range(1, 11):
commands[f"clear_bookmark_{i}"] = lambda i=i: bookmark_command(
i, "clear"
)
return commands
# For backwards compatibility, provide individual command classes
# This allows the existing command loading system to work unchanged
def _make_command_class(bookmark_id, action):
"""Create a command class for a specific bookmark and action"""
class command(bookmark_command):
def __init__(self):
super().__init__(bookmark_id, action)
return command
# Generate individual command classes for each bookmark operation
# These will be used by the existing command loading system
# Read bookmarks (bookmark_1.py style)
for i in range(1, 11):
globals()[f"bookmark_{i}_command"] = _make_command_class(i, "read")
# Set bookmarks (set_bookmark_1.py style)
for i in range(1, 11):
globals()[f"set_bookmark_{i}_command"] = _make_command_class(i, "set")
# Clear bookmarks (clear_bookmark_1.py style)
for i in range(1, 11):
globals()[f"clear_bookmark_{i}_command"] = _make_command_class(i, "clear")

View File

@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '1'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(1, "clear")

View File

@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '10'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(10, "clear")

View File

@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '2'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(2, "clear")

View File

@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '3'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(3, "clear")

View File

@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '4'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(4, "clear")

View File

@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '5'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(5, "clear")

View File

@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '6'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(6, "clear")

View File

@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '7'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(7, "clear")

View File

@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '8'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(8, "clear")

View File

@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '9'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(9, "clear")

View File

@@ -2,23 +2,33 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('clears the currently selected clipboard')
pass
def get_description(self):
return _("clears the currently selected clipboard")
def run(self):
self.env['runtime']['memoryManager'].clearCurrentIndexList('clipboardHistory')
self.env['runtime']['outputManager'].presentText(_('clipboard cleared'), interrupt=True)
return
def setCallback(self, callback):
self.env["runtime"]["MemoryManager"].clear_current_index_list(
"clipboardHistory"
)
self.env["runtime"]["OutputManager"].present_text(
_("clipboard cleared"), interrupt=True
)
return
def set_callback(self, callback):
pass

View File

@@ -2,26 +2,40 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Turn off window mode for application')
def run(self):
if self.env['runtime']['cursorManager'].clearWindowForApplication():
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
self.env['runtime']['outputManager'].presentText(_('Window Mode off for application {0}').format(currApp,), interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(_("Not in window Mode"), interrupt=True)
def setCallback(self, callback):
pass
def get_description(self):
return _("Turn off window mode for application")
def run(self):
if self.env["runtime"]["CursorManager"].clear_window_for_application():
curr_app = self.env["runtime"][
"ApplicationManager"
].get_current_application()
self.env["runtime"]["OutputManager"].present_text(
_("Window Mode off for application {0}").format(
curr_app,
),
interrupt=True,
)
else:
self.env["runtime"]["OutputManager"].present_text(
_("Not in window Mode"), interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,27 +2,35 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import mark_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('copies last presented text to the clipboard')
def run(self):
lastEcho = self.env['runtime']['outputManager'].getLastEcho()
if lastEcho.rstrip() != "":
lastEcho = lastEcho.rstrip()
self.env['runtime']['memoryManager'].addValueToFirstIndex('clipboardHistory', lastEcho)
self.env['runtime']['outputManager'].presentText(lastEcho, soundIcon='CopyToClipboard', interrupt=True)
def setCallback(self, callback):
def shutdown(self):
pass
def get_description(self):
return _("copies last presented text to the clipboard")
def run(self):
last_echo = self.env["runtime"]["OutputManager"].get_last_echo()
if last_echo.rstrip() != "":
last_echo = last_echo.rstrip()
self.env["runtime"]["MemoryManager"].add_value_to_first_index(
"clipboardHistory", last_echo
)
self.env["runtime"]["OutputManager"].present_text(
last_echo, sound_icon="CopyToClipboard", interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,73 +2,81 @@
# -*- coding: utf-8 -*-
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import mark_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('copies marked text to the currently selected clipboard')
def getTextFromScreen(self, startMark, endMark):
screenContent = self.env['screen']['newContentText']
screenLines = screenContent.split('\n')
startY = min(startMark['y'], len(screenLines) - 1)
endY = min(endMark['y'], len(screenLines) - 1)
pass
def get_description(self):
return _("copies marked text to the currently selected clipboard")
def get_text_from_screen(self, start_mark, end_mark):
screen_content = self.env["screen"]["new_content_text"]
screen_lines = screen_content.split("\n")
start_y = min(start_mark["y"], len(screen_lines) - 1)
end_y = min(end_mark["y"], len(screen_lines) - 1)
# If marks are on the same line
if startY == endY:
line = screenLines[startY]
startX = min(startMark['x'], len(line))
endX = min(endMark['x'], len(line)) + 1
return line[startX:endX]
if start_y == end_y:
line = screen_lines[start_y]
start_x = min(start_mark["x"], len(line))
end_x = min(end_mark["x"], len(line)) + 1
return line[start_x:end_x]
# Handle multi-line selection
result = []
# First line (from start mark to end of line)
firstLine = screenLines[startY]
startX = min(startMark['x'], len(firstLine))
result.append(firstLine[startX:].rstrip())
first_line = screen_lines[start_y]
start_x = min(start_mark["x"], len(first_line))
result.append(first_line[start_x:].rstrip())
# Middle lines (complete lines)
for lineNum in range(startY + 1, endY):
result.append(screenLines[lineNum].rstrip())
for lineNum in range(start_y + 1, end_y):
result.append(screen_lines[lineNum].rstrip())
# Last line (from start to end mark)
if endY > startY:
lastLine = screenLines[endY]
endX = min(endMark['x'], len(lastLine)) + 1
result.append(lastLine[:endX].rstrip())
return '\n'.join(result)
if end_y > start_y:
last_line = screen_lines[end_y]
end_x = min(end_mark["x"], len(last_line)) + 1
result.append(last_line[:end_x].rstrip())
return "\n".join(result)
def run(self):
if not self.env['commandBuffer']['Marks']['1']:
self.env['runtime']['outputManager'].presentText(_("One or two marks are needed"), interrupt=True)
if not self.env["commandBuffer"]["Marks"]["1"]:
self.env["runtime"]["OutputManager"].present_text(
_("One or two marks are needed"), interrupt=True
)
return
if not self.env['commandBuffer']['Marks']['2']:
self.env['runtime']['cursorManager'].setMark()
if not self.env["commandBuffer"]["Marks"]["2"]:
self.env["runtime"]["CursorManager"].set_mark()
# use the last first and the last setted mark as range
startMark = self.env['commandBuffer']['Marks']['1'].copy()
endMark = self.env['commandBuffer']['Marks']['2'].copy()
# Replace mark_utils.getTextBetweenMarks with our new method
marked = self.getTextFromScreen(startMark, endMark)
self.env['runtime']['memoryManager'].addValueToFirstIndex('clipboardHistory', marked)
start_mark = self.env["commandBuffer"]["Marks"]["1"].copy()
end_mark = self.env["commandBuffer"]["Marks"]["2"].copy()
# Replace mark_utils.get_text_between_marks with our new method
marked = self.get_text_from_screen(start_mark, end_mark)
self.env["runtime"]["MemoryManager"].add_value_to_first_index(
"clipboardHistory", marked
)
# reset marks
self.env['runtime']['cursorManager'].clearMarks()
self.env['runtime']['outputManager'].presentText(marked, soundIcon='CopyToClipboard', interrupt=True)
def setCallback(self, callback):
self.env["runtime"]["CursorManager"].clear_marks()
self.env["runtime"]["OutputManager"].present_text(
marked, sound_icon="CopyToClipboard", interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,26 +2,39 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('speaks the contents of the currently selected clipboard')
pass
def get_description(self):
return _("speaks the contents of the currently selected clipboard")
def run(self):
if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'):
self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True)
return
clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory')
self.env['runtime']['outputManager'].presentText(clipboard , interrupt=True)
def setCallback(self, callback):
if self.env["runtime"]["MemoryManager"].is_index_list_empty(
"clipboardHistory"
):
self.env["runtime"]["OutputManager"].present_text(
_("clipboard empty"), interrupt=True
)
return
clipboard = self.env["runtime"][
"MemoryManager"
].get_index_list_element("clipboardHistory")
self.env["runtime"]["OutputManager"].present_text(
clipboard, interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,25 +2,34 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('reads the contents of the current screen')
pass
def get_description(self):
return _("reads the contents of the current screen")
def run(self):
if self.env['screen']['newContentText'].isspace():
self.env['runtime']['outputManager'].presentText(_("screen is empty"), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(self.env['screen']['newContentText'],interrupt=True)
def setCallback(self, callback):
if self.env["screen"]["new_content_text"].isspace():
self.env["runtime"]["OutputManager"].present_text(
_("screen is empty"), sound_icon="EmptyLine", interrupt=True
)
else:
self.env["runtime"]["OutputManager"].present_text(
self.env["screen"]["new_content_text"], interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,31 +2,43 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import mark_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('reads from the cursor to the bottom of the screen')
pass
def get_description(self):
return _("reads from the cursor to the bottom of the screen")
def run(self):
# Prefer review cursor over text cursor
cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor()
cursor_pos = self.env["runtime"][
"CursorManager"
].get_review_or_text_cursor()
textAfterCursor = mark_utils.getTextAfterMark(cursorPos, self.env['screen']['newContentText'])
text_after_cursor = mark_utils.get_text_after_mark(
cursor_pos, self.env["screen"]["new_content_text"]
)
if textAfterCursor.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True)
if text_after_cursor.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), sound_icon="EmptyLine", interrupt=True
)
else:
self.env['runtime']['outputManager'].presentText(textAfterCursor, interrupt=True)
self.env["runtime"]["OutputManager"].present_text(
text_after_cursor, interrupt=True
)
def setCallback(self, callback):
def set_callback(self, callback):
pass

View File

@@ -2,35 +2,44 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import mark_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Reads from the top of the screen to the cursor position')
pass
def get_description(self):
return _("Reads from the top of the screen to the cursor position")
def run(self):
# Prefer review cursor over text cursor
if self.env['screen']['newCursorReview']:
cursorPos = self.env['screen']['newCursorReview'].copy()
if self.env["screen"]["newCursorReview"]:
cursor_pos = self.env["screen"]["newCursorReview"].copy()
else:
cursorPos = self.env['screen']['newCursor'].copy()
cursor_pos = self.env["screen"]["new_cursor"].copy()
textBeforeCursor = mark_utils.getTextBeforeMark(cursorPos, self.env['screen']['newContentText'])
text_before_cursor = mark_utils.get_text_before_mark(
cursor_pos, self.env["screen"]["new_content_text"]
)
if textBeforeCursor.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True)
if text_before_cursor.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), sound_icon="EmptyLine", interrupt=True
)
else:
self.env['runtime']['outputManager'].presentText(textBeforeCursor, interrupt=True)
def setCallback(self, callback):
self.env["runtime"]["OutputManager"].present_text(
text_before_cursor, interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,25 +2,34 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('get current quick menu entry')
def run(self):
menu = ''
value = ''
menu = self.env['runtime']['quickMenuManager'].getCurrentEntry()
if menu != '':
value = self.env['runtime']['quickMenuManager'].getCurrentValue()
self.env['runtime']['outputManager'].presentText(menu + ' ' + value, interrupt=True)
def setCallback(self, callback):
pass
def get_description(self):
return _("get current quick menu entry")
def run(self):
menu = ""
value = ""
menu = self.env["runtime"]["QuickMenuManager"].get_current_entry()
if menu != "":
value = self.env["runtime"]["QuickMenuManager"].get_current_value()
self.env["runtime"]["OutputManager"].present_text(
menu + " " + value, interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,21 +2,30 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('get current quick menu value')
def run(self):
value = self.env['runtime']['quickMenuManager'].getCurrentValue()
self.env['runtime']['outputManager'].presentText(value, interrupt=True)
def setCallback(self, callback):
pass
def get_description(self):
return _("get current quick menu value")
def run(self):
value = self.env["runtime"]["QuickMenuManager"].get_current_value()
self.env["runtime"]["OutputManager"].present_text(
value, interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,24 +2,36 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Column number for cursor')
def get_description(self):
return _("Column number for cursor")
def run(self):
cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor()
self.env['runtime']['outputManager'].presentText(str(cursorPos['x'] + 1) , interrupt=True)
self.env['runtime']['outputManager'].announceActiveCursor()
self.env['runtime']['outputManager'].presentText(' column number' , interrupt=False)
def setCallback(self, callback):
cursor_pos = self.env["runtime"][
"CursorManager"
].get_review_or_text_cursor()
self.env["runtime"]["OutputManager"].present_text(
str(cursor_pos["x"] + 1), interrupt=True
)
self.env["runtime"]["OutputManager"].announce_active_cursor()
self.env["runtime"]["OutputManager"].present_text(
" column number", interrupt=False
)
def set_callback(self, callback):
pass

View File

@@ -2,24 +2,36 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Line number for cursor')
def get_description(self):
return _("Line number for cursor")
def run(self):
cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor()
self.env['runtime']['outputManager'].presentText(str(cursorPos['y'] + 1), interrupt=True)
self.env['runtime']['outputManager'].announceActiveCursor()
self.env['runtime']['outputManager'].presentText(' line number' , interrupt=False)
def setCallback(self, callback):
cursor_pos = self.env["runtime"][
"CursorManager"
].get_review_or_text_cursor()
self.env["runtime"]["OutputManager"].present_text(
str(cursor_pos["y"] + 1), interrupt=True
)
self.env["runtime"]["OutputManager"].announce_active_cursor()
self.env["runtime"]["OutputManager"].present_text(
" line number", interrupt=False
)
def set_callback(self, callback):
pass

View File

@@ -2,25 +2,39 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('displays the position of the review cursor')
pass
def get_description(self):
return _("displays the position of the review cursor")
def run(self):
# Prefer review cursor over text cursor
cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor()
cursor_pos = self.env["runtime"][
"CursorManager"
].get_review_or_text_cursor()
self.env['runtime']['outputManager'].presentText(_("line {0}, column {1}, Terminal {2}").format(cursorPos['y']+1, cursorPos['x']+1, self.env['screen']['newTTY']), interrupt=True)
def setCallback(self, callback):
self.env["runtime"]["OutputManager"].present_text(
_("line {0}, column {1}, Terminal {2}").format(
cursor_pos["y"] + 1,
cursor_pos["x"] + 1,
self.env["screen"]["newTTY"],
),
interrupt=True,
)
def set_callback(self, callback):
pass

View File

@@ -2,32 +2,48 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import line_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read line to cursor pos, use review cursor if you are in review mode, otherwhise use text cursor')
def run(self):
cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor()
x, y, currLine = \
line_utils.getCurrentLine(cursorPos['x'], cursorPos['y'], self.env['screen']['newContentText'])
if currLine.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(currLine[:cursorPos['x']], interrupt=True)
self.env['runtime']['outputManager'].announceActiveCursor()
def setCallback(self, callback):
def shutdown(self):
pass
def get_description(self):
return _(
"read line to cursor pos, use review cursor if you are in review mode, "
"otherwhise use text cursor"
)
def run(self):
cursor_pos = self.env["runtime"][
"CursorManager"
].get_review_or_text_cursor()
x, y, curr_line = line_utils.get_current_line(
cursor_pos["x"],
cursor_pos["y"],
self.env["screen"]["new_content_text"],
)
if curr_line.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), sound_icon="EmptyLine", interrupt=True
)
else:
self.env["runtime"]["OutputManager"].present_text(
curr_line[: cursor_pos["x"]], interrupt=True
)
self.env["runtime"]["OutputManager"].announce_active_cursor()
def set_callback(self, callback):
pass

View File

@@ -2,32 +2,48 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import line_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read to end of line, use review cursor if you are in review mode, otherwhise use text cursor')
def run(self):
cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor()
x, y, currLine = \
line_utils.getCurrentLine(cursorPos['x'], cursorPos['y'], self.env['screen']['newContentText'])
if currLine.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(currLine[cursorPos['x']:], interrupt=True)
self.env['runtime']['outputManager'].announceActiveCursor()
def setCallback(self, callback):
def shutdown(self):
pass
def get_description(self):
return _(
"read to end of line, use review cursor if you are in review mode, "
"otherwhise use text cursor"
)
def run(self):
cursor_pos = self.env["runtime"][
"CursorManager"
].get_review_or_text_cursor()
x, y, curr_line = line_utils.get_current_line(
cursor_pos["x"],
cursor_pos["y"],
self.env["screen"]["new_content_text"],
)
if curr_line.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), sound_icon="EmptyLine", interrupt=True
)
else:
self.env["runtime"]["OutputManager"].present_text(
curr_line[cursor_pos["x"] :], interrupt=True
)
self.env["runtime"]["OutputManager"].announce_active_cursor()
def set_callback(self, callback):
pass

View File

@@ -2,60 +2,75 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import os
class command():
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('cycles between available keyboard layouts')
def getAvailableLayouts(self):
pass
def get_description(self):
return _("cycles between available keyboard layouts")
def get_available_layouts(self):
"""Get list of available keyboard layout files"""
layouts = []
# Check standard locations for keyboard layouts
settingsRoot = '/etc/fenrirscreenreader/'
if not os.path.exists(settingsRoot):
settings_root = "/etc/fenrirscreenreader/"
if not os.path.exists(settings_root):
# Fallback to source directory
import fenrirscreenreader
fenrirPath = os.path.dirname(fenrirscreenreader.__file__)
settingsRoot = fenrirPath + '/../../config/'
keyboardPath = settingsRoot + 'keyboard/'
if os.path.exists(keyboardPath):
for file in os.listdir(keyboardPath):
if file.endswith('.conf') and not file.startswith('__') and not file.lower().startswith('pty'):
layout_name = file.replace('.conf', '')
fenrir_path = os.path.dirname(fenrirscreenreader.__file__)
settings_root = fenrir_path + "/../../config/"
keyboard_path = settings_root + "keyboard/"
if os.path.exists(keyboard_path):
for file in os.listdir(keyboard_path):
if (
file.endswith(".conf")
and not file.startswith("__")
and not file.lower().startswith("pty")
):
layout_name = file.replace(".conf", "")
if layout_name not in layouts:
layouts.append(layout_name)
# Ensure we have at least basic layouts
if not layouts:
layouts = ['desktop', 'laptop']
layouts = ["desktop", "laptop"]
else:
layouts.sort()
return layouts
def run(self):
current_layout = self.env['runtime']['settingsManager'].getSetting('keyboard', 'keyboardLayout')
current_layout = self.env["runtime"]["SettingsManager"].get_setting(
"keyboard", "keyboardLayout"
)
# Extract layout name from full path if needed
if '/' in current_layout:
current_layout = os.path.basename(current_layout).replace('.conf', '')
if "/" in current_layout:
current_layout = os.path.basename(current_layout).replace(
".conf", ""
)
# Get available layouts
available_layouts = self.getAvailableLayouts()
available_layouts = self.get_available_layouts()
# Find next layout in cycle
try:
current_index = available_layouts.index(current_layout)
@@ -63,28 +78,28 @@ class command():
except ValueError:
# If current layout not found, start from beginning
next_index = 0
next_layout = available_layouts[next_index]
# Update setting and reload shortcuts
self.env['runtime']['settingsManager'].setSetting('keyboard', 'keyboardLayout', next_layout)
self.env["runtime"]["SettingsManager"].set_setting(
"keyboard", "keyboardLayout", next_layout
)
# Reload shortcuts with new layout
try:
self.env['runtime']['inputManager'].reloadShortcuts()
self.env['runtime']['outputManager'].presentText(
_('Switched to {} keyboard layout').format(next_layout),
interrupt=True
self.env["runtime"]["InputManager"].reload_shortcuts()
self.env["runtime"]["OutputManager"].present_text(
_("Switched to {} keyboard layout").format(next_layout),
interrupt=True,
)
except Exception as e:
self.env['runtime']['debug'].writeDebugOut(
"Error reloading shortcuts: " + str(e),
debug.debugLevel.ERROR
self.env["runtime"]["DebugManager"].write_debug_out(
"Error reloading shortcuts: " + str(e), debug.DebugLevel.ERROR
)
self.env['runtime']['outputManager'].presentText(
_('Error switching keyboard layout'),
interrupt=True
self.env["runtime"]["OutputManager"].present_text(
_("Error switching keyboard layout"), interrupt=True
)
def setCallback(self, callback):
pass
def set_callback(self, callback):
pass

View File

@@ -2,29 +2,41 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import datetime
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('presents the date')
pass
def get_description(self):
return _("presents the date")
def run(self):
dateFormat = self.env['runtime']['settingsManager'].getSetting('general', 'dateFormat')
date_format = self.env["runtime"]["SettingsManager"].get_setting(
"general", "date_format"
)
# get the time formatted
dateString = datetime.datetime.strftime(datetime.datetime.now(), dateFormat)
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
self.env['runtime']['outputManager'].presentText(dateString , soundIcon='', interrupt=True)
# present the time via speak and braile, there is no soundicon,
# interrupt the current speech
self.env["runtime"]["OutputManager"].present_text(
date_string, sound_icon="", interrupt=True
)
def setCallback(self, callback):
def set_callback(self, callback):
pass

View File

@@ -2,38 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
initialized = False
try:
import alsaaudio
initialized = True
except:
pass
import importlib.util
import os
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
class command():
_base_path = os.path.join(os.path.dirname(__file__), "adjustment_base.py")
_spec = importlib.util.spec_from_file_location("adjustment_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
adjustment_command = _module.adjustment_command
class command(adjustment_command):
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _("Decrease system volume")
def run(self):
if not initialized:
self.env['runtime']['outputManager'].presentText(_('alsaaudio is not installed'), interrupt=True)
return
mixer = alsaaudio.Mixer()
value = mixer.getvolume()[0]
value = value - 5
if value < 5:
value = 5
mixer.setvolume(value)
self.env['runtime']['outputManager'].presentText(_("{0} percent system volume").format(value), interrupt=True)
def setCallback(self, callback):
pass
super().__init__("alsa", "volume", "dec")

View File

@@ -2,32 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import math
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "adjustment_base.py")
_spec = importlib.util.spec_from_file_location("adjustment_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
adjustment_command = _module.adjustment_command
class command(adjustment_command):
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('decrease sound volume')
def run(self):
value = self.env['runtime']['settingsManager'].getSettingAsFloat('sound', 'volume')
value = round((math.ceil(10 * value) / 10) - 0.1, 2)
if value < 0.1:
value = 0.1
self.env['runtime']['settingsManager'].setSetting('sound', 'volume', str(value))
self.env['runtime']['outputManager'].presentText(_("{0} percent sound volume").format(int(value * 100)), soundIcon='SoundOff', interrupt=True)
def setCallback(self, callback):
pass
super().__init__("sound", "volume", "dec")

View File

@@ -2,28 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import math
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "adjustment_base.py")
_spec = importlib.util.spec_from_file_location("adjustment_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
adjustment_command = _module.adjustment_command
class command(adjustment_command):
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Decreases the pitch of the speech')
def run(self):
value = self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'pitch')
value = round((math.ceil(10 * value) / 10) - 0.1, 2)
if value < 0.0:
value = 0.0
self.env['runtime']['settingsManager'].setSetting('speech', 'pitch', str(value))
self.env['runtime']['outputManager'].presentText(_('{0} percent speech pitch').format(int(value * 100)), soundIcon='', interrupt=True)
def setCallback(self, callback):
pass
super().__init__("speech", "pitch", "dec")

View File

@@ -2,29 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import math
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "adjustment_base.py")
_spec = importlib.util.spec_from_file_location("adjustment_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
adjustment_command = _module.adjustment_command
class command(adjustment_command):
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Decreases the rate of the speech')
def run(self):
value = self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'rate')
value = round((math.ceil(10 * value) / 10) - 0.1, 2)
if value < 0.0:
value = 0.0
self.env['runtime']['settingsManager'].setSetting('speech', 'rate', str(value))
self.env['runtime']['outputManager'].presentText(_("{0} percent speech rate").format(int(value * 100)), soundIcon='', interrupt=True)
def setCallback(self, callback):
pass
super().__init__("speech", "rate", "dec")

View File

@@ -2,30 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import math
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "adjustment_base.py")
_spec = importlib.util.spec_from_file_location("adjustment_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
adjustment_command = _module.adjustment_command
class command(adjustment_command):
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Decreases the volume of the speech')
def run(self):
value = self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'volume')
value = round((math.ceil(10 * value) / 10) - 0.1, 2)
if value < 0.1:
value = 0.1
self.env['runtime']['settingsManager'].setSetting('speech', 'volume', str(value))
self.env['runtime']['outputManager'].presentText(_("{0} percent speech volume").format(int(value * 100)), soundIcon='', interrupt=True)
def setCallback(self, callback):
pass
super().__init__("speech", "volume", "dec")

View File

@@ -2,27 +2,36 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('exits review mode')
def run(self):
if not self.env['runtime']['cursorManager'].isReviewMode():
self.env['runtime']['outputManager'].presentText(_("Not in Review Mode"), interrupt=True)
return
self.env['runtime']['cursorManager'].clearReviewCursor()
self.env['runtime']['outputManager'].presentText(_("Exiting Review Mode"), interrupt=True)
def setCallback(self, callback):
def shutdown(self):
pass
def get_description(self):
return _("exits review mode")
def run(self):
if not self.env["runtime"]["CursorManager"].is_review_mode():
self.env["runtime"]["OutputManager"].present_text(
_("Not in Review Mode"), interrupt=True
)
return
self.env["runtime"]["CursorManager"].clear_review_cursor()
self.env["runtime"]["OutputManager"].present_text(
_("Exiting Review Mode"), interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,38 +2,66 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import os
class command():
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment, scriptPath=''):
def initialize(self, environment, script_path=""):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('export the current fenrir clipboard to a file')
def run(self):
clipboardFilePath = self.env['runtime']['settingsManager'].getSetting('general', 'clipboardExportPath')
clipboardFilePath = clipboardFilePath.replace('$user',self.env['general']['currUser'])
clipboardFilePath = clipboardFilePath.replace('$USER',self.env['general']['currUser'])
clipboardFilePath = clipboardFilePath.replace('$User',self.env['general']['currUser'])
clipboardFile = open(clipboardFilePath,'w')
def get_description(self):
return _("export the current fenrir clipboard to a file")
def run(self):
clipboard_file_path = self.env["runtime"][
"SettingsManager"
].get_setting("general", "clipboardExportPath")
clipboard_file_path = clipboard_file_path.replace(
"$user", self.env["general"]["curr_user"]
)
clipboard_file_path = clipboard_file_path.replace(
"$USER", self.env["general"]["curr_user"]
)
clipboard_file_path = clipboard_file_path.replace(
"$User", self.env["general"]["curr_user"]
)
clipboard_file = open(clipboard_file_path, "w")
try:
if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'):
self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True)
return
clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory')
clipboardFile.write(clipboard)
clipboardFile.close()
os.chmod(clipboardFilePath, 0o666)
self.env['runtime']['outputManager'].presentText(_('clipboard exported to file'), interrupt=True)
if self.env["runtime"]["MemoryManager"].is_index_list_empty(
"clipboardHistory"
):
self.env["runtime"]["OutputManager"].present_text(
_("clipboard empty"), interrupt=True
)
return
clipboard = self.env["runtime"][
"MemoryManager"
].get_index_list_element("clipboardHistory")
clipboard_file.write(clipboard)
clipboard_file.close()
os.chmod(clipboard_file_path, 0o644)
self.env["runtime"]["OutputManager"].present_text(
_("clipboard exported to file"), interrupt=True
)
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('export_clipboard_to_file:run: Filepath:'+ clipboardFile +' trace:' + str(e),debug.debugLevel.ERROR)
def setCallback(self, callback):
self.env["runtime"]["DebugManager"].write_debug_out(
"export_clipboard_to_file:run: Filepath:"
+ clipboard_file
+ " trace:"
+ str(e),
debug.DebugLevel.ERROR,
)
def set_callback(self, callback):
pass

View File

@@ -2,70 +2,96 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import os
import importlib
import _thread
import importlib
import os
import pyperclip
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment, scriptPath=''):
def initialize(self, environment, script_path=""):
self.env = environment
self.scriptPath = scriptPath
self.script_path = script_path
def shutdown(self):
pass
def getDescription(self):
return _('Export current fenrir clipboard to X or GUI clipboard')
def run(self):
_thread.start_new_thread(self._threadRun , ())
def _threadRun(self):
def get_description(self):
return _("Export current fenrir clipboard to X or GUI clipboard")
def run(self):
_thread.start_new_thread(self._thread_run, ())
def _thread_run(self):
try:
# Check if clipboard is empty
if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'):
self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True)
if self.env["runtime"]["MemoryManager"].is_index_list_empty(
"clipboardHistory"
):
self.env["runtime"]["OutputManager"].present_text(
_("clipboard empty"), interrupt=True
)
return
# Get current clipboard content
clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory')
clipboard = self.env["runtime"][
"MemoryManager"
].get_index_list_element("clipboardHistory")
# Remember original display environment variable if it exists
originalDisplay = os.environ.get('DISPLAY', '')
original_display = os.environ.get("DISPLAY", "")
success = False
# Try different display options
for i in range(10):
display = f":{i}"
try:
# Set display environment variable
os.environ['DISPLAY'] = display
os.environ["DISPLAY"] = display
# Attempt to set clipboard content
importlib.reload(pyperclip) # Weird workaround for some distros
# Weird workaround for some distros
importlib.reload(pyperclip)
pyperclip.copy(clipboard)
# If we get here without exception, we found a working display
# If we get here without exception, we found a working
# display
success = True
break
except Exception:
# Failed for this display, try next one
continue
# Restore original display setting
if originalDisplay:
os.environ['DISPLAY'] = originalDisplay
if original_display:
os.environ["DISPLAY"] = original_display
else:
os.environ.pop('DISPLAY', None)
os.environ.pop("DISPLAY", None)
# Notify the user of the result
if success:
self.env['runtime']['outputManager'].presentText(_('exported to the X session.'), interrupt=True)
self.env["runtime"]["OutputManager"].present_text(
_("exported to the X session."), interrupt=True
)
else:
self.env['runtime']['outputManager'].presentText(_('failed to export to X clipboard. No available display found.'), interrupt=True)
self.env["runtime"]["OutputManager"].present_text(
_(
"failed to export to X clipboard. No available display "
"found."
),
interrupt=True,
)
except Exception as e:
self.env['runtime']['outputManager'].presentText(str(e), soundIcon='', interrupt=False)
def setCallback(self, callback):
self.env["runtime"]["OutputManager"].present_text(
str(e), sound_icon="", interrupt=False
)
def set_callback(self, callback):
pass

View File

@@ -2,27 +2,42 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('selects the first clipboard')
def run(self):
if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'):
self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True)
return
self.env['runtime']['memoryManager'].setFirstIndex('clipboardHistory')
clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory')
self.env['runtime']['outputManager'].presentText(clipboard, interrupt=True)
def setCallback(self, callback):
pass
def get_description(self):
return _("selects the first clipboard")
def run(self):
if self.env["runtime"]["MemoryManager"].is_index_list_empty(
"clipboardHistory"
):
self.env["runtime"]["OutputManager"].present_text(
_("clipboard empty"), interrupt=True
)
return
self.env["runtime"]["MemoryManager"].set_first_index(
"clipboardHistory"
)
clipboard = self.env["runtime"][
"MemoryManager"
].get_index_list_element("clipboardHistory")
self.env["runtime"]["OutputManager"].present_text(
clipboard, interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,23 +2,30 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('sends the following keypress to the terminal or application')
def run(self):
self.env['input']['keyForeward'] = 3
self.env['runtime']['outputManager'].presentText(_('Forward next keypress'), interrupt=True)
def setCallback(self, callback):
def shutdown(self):
pass
def get_description(self):
return _("sends the following keypress to the terminal or application")
def run(self):
self.env["input"]["keyForeward"] = 3
self.env["runtime"]["OutputManager"].present_text(
_("Forward next keypress"), interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,38 +2,58 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
import os
class command():
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import mark_utils
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('imports text from clipboard file to the clipboard')
def run(self):
clipboardFilePath = self.env['runtime']['settingsManager'].getSetting('general', 'clipboardExportPath')
clipboardFilePath = clipboardFilePath.replace('$user',self.env['general']['currUser'])
clipboardFilePath = clipboardFilePath.replace('$USER',self.env['general']['currUser'])
clipboardFilePath = clipboardFilePath.replace('$User',self.env['general']['currUser'])
if not os.path.exists(clipboardFilePath):
self.env['runtime']['outputManager'].presentText(_('File does not exist'), soundIcon='', interrupt=True)
return
clipboardFile = open(clipboardFilePath,'r')
imported = clipboardFile.read()
clipboardFile.close()
self.env['runtime']['memoryManager'].addValueToFirstIndex('clipboardHistory', imported)
self.env['runtime']['outputManager'].presentText('Import to Clipboard', soundIcon='CopyToClipboard', interrupt=True)
self.env['runtime']['outputManager'].presentText(imported, soundIcon='', interrupt=False)
def setCallback(self, callback):
pass
def get_description(self):
return _("imports text from clipboard file to the clipboard")
def run(self):
clipboard_file_path = self.env["runtime"][
"SettingsManager"
].get_setting("general", "clipboardExportPath")
clipboard_file_path = clipboard_file_path.replace(
"$user", self.env["general"]["curr_user"]
)
clipboard_file_path = clipboard_file_path.replace(
"$USER", self.env["general"]["curr_user"]
)
clipboard_file_path = clipboard_file_path.replace(
"$User", self.env["general"]["curr_user"]
)
if not os.path.exists(clipboard_file_path):
self.env["runtime"]["OutputManager"].present_text(
_("File does not exist"), sound_icon="", interrupt=True
)
return
clipboard_file = open(clipboard_file_path, "r")
imported = clipboard_file.read()
clipboard_file.close()
self.env["runtime"]["MemoryManager"].add_value_to_first_index(
"clipboardHistory", imported
)
self.env["runtime"]["OutputManager"].present_text(
"Import to Clipboard", sound_icon="CopyToClipboard", interrupt=True
)
self.env["runtime"]["OutputManager"].present_text(
imported, sound_icon="", interrupt=False
)
def set_callback(self, callback):
pass

View File

@@ -2,63 +2,86 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib
import _thread
import pyperclip
import importlib
import os
class command():
import pyperclip
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment, scriptPath=''):
def initialize(self, environment, script_path=""):
self.env = environment
self.scriptPath = scriptPath
self.script_path = script_path
def shutdown(self):
pass
def getDescription(self):
def get_description(self):
return _("imports the graphical clipboard to Fenrir's clipboard")
def run(self):
_thread.start_new_thread(self._threadRun , ())
def _threadRun(self):
def run(self):
_thread.start_new_thread(self._thread_run, ())
def _thread_run(self):
try:
# Remember original display environment variable if it exists
originalDisplay = os.environ.get('DISPLAY', '')
clipboardContent = None
original_display = os.environ.get("DISPLAY", "")
clipboard_content = None
# Try different display options
for i in range(10):
display = f":{i}"
try:
# Set display environment variable
os.environ['DISPLAY'] = display
os.environ["DISPLAY"] = display
# Attempt to get clipboard content
importlib.reload(pyperclip) # Weird workaround for some distros
clipboardContent = pyperclip.paste()
# If we get here without exception, we found a working display
if clipboardContent:
# Weird workaround for some distros
importlib.reload(pyperclip)
clipboard_content = pyperclip.paste()
# If we get here without exception, we found a working
# display
if clipboard_content:
break
except Exception:
# Failed for this display, try next one
continue
# Restore original display setting
if originalDisplay:
os.environ['DISPLAY'] = originalDisplay
if original_display:
os.environ["DISPLAY"] = original_display
else:
os.environ.pop('DISPLAY', None)
os.environ.pop("DISPLAY", None)
# Process the clipboard content if we found any
if clipboardContent and isinstance(clipboardContent, str):
self.env['runtime']['memoryManager'].addValueToFirstIndex('clipboardHistory', clipboardContent)
self.env['runtime']['outputManager'].presentText('Import to Clipboard', soundIcon='CopyToClipboard', interrupt=True)
self.env['runtime']['outputManager'].presentText(clipboardContent, soundIcon='', interrupt=False)
if clipboard_content and isinstance(clipboard_content, str):
self.env["runtime"]["MemoryManager"].add_value_to_first_index(
"clipboardHistory", clipboard_content
)
self.env["runtime"]["OutputManager"].present_text(
"Import to Clipboard",
sound_icon="CopyToClipboard",
interrupt=True,
)
self.env["runtime"]["OutputManager"].present_text(
clipboard_content, sound_icon="", interrupt=False
)
else:
self.env['runtime']['outputManager'].presentText('No text found in clipboard or no accessible display', interrupt=True)
self.env["runtime"]["OutputManager"].present_text(
"No text found in clipboard or no accessible display",
interrupt=True,
)
except Exception as e:
self.env['runtime']['outputManager'].presentText(str(e), soundIcon='', interrupt=False)
def setCallback(self, callback):
self.env["runtime"]["OutputManager"].present_text(
str(e), sound_icon="", interrupt=False
)
def set_callback(self, callback):
pass

View File

@@ -2,38 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
initialized = False
try:
import alsaaudio
initialized = True
except:
pass
import importlib.util
import os
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
class command():
_base_path = os.path.join(os.path.dirname(__file__), "adjustment_base.py")
_spec = importlib.util.spec_from_file_location("adjustment_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
adjustment_command = _module.adjustment_command
class command(adjustment_command):
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _("Increase system volume")
def run(self):
if not initialized:
self.env['runtime']['outputManager'].presentText(_('alsaaudio is not installed'), interrupt=True)
return
mixer = alsaaudio.Mixer()
value = mixer.getvolume()[0]
value = value + 5
if value > 100:
value = 100
mixer.setvolume(value)
self.env['runtime']['outputManager'].presentText(_("{0} percent system volume").format(value), interrupt=True)
def setCallback(self, callback):
pass
super().__init__("alsa", "volume", "inc")

View File

@@ -2,31 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import math
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "adjustment_base.py")
_spec = importlib.util.spec_from_file_location("adjustment_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
adjustment_command = _module.adjustment_command
class command(adjustment_command):
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('adjusts the volume for in coming sounds')
def run(self):
value = self.env['runtime']['settingsManager'].getSettingAsFloat('sound', 'volume')
value = round((math.ceil(10 * value) / 10) + 0.1, 2)
if value > 1.0:
value = 1.0
self.env['runtime']['settingsManager'].setSetting('sound', 'volume', str(value))
self.env['runtime']['outputManager'].presentText(_("{0} percent sound volume").format(int(value * 100)), soundIcon='SoundOn', interrupt=True)
def setCallback(self, callback):
pass
super().__init__("sound", "volume", "inc")

View File

@@ -2,29 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import math
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "adjustment_base.py")
_spec = importlib.util.spec_from_file_location("adjustment_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
adjustment_command = _module.adjustment_command
class command(adjustment_command):
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Increases the pitch of the speech')
def run(self):
value = self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'pitch')
value = round((math.ceil(10 * value) / 10) + 0.1, 2)
if value > 1.0:
value = 1.0
self.env['runtime']['settingsManager'].setSetting('speech', 'pitch', str(value))
self.env['runtime']['outputManager'].presentText(_("{0} percent speech pitch").format(int(value * 100)), soundIcon='', interrupt=True)
def setCallback(self, callback):
pass
super().__init__("speech", "pitch", "inc")

View File

@@ -2,29 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import math
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "adjustment_base.py")
_spec = importlib.util.spec_from_file_location("adjustment_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
adjustment_command = _module.adjustment_command
class command(adjustment_command):
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Increase the speech rate')
def run(self):
value = self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'rate')
value = round((math.ceil(10 * value) / 10) + 0.1, 2)
if value > 1.0:
value = 1.0
self.env['runtime']['settingsManager'].setSetting('speech', 'rate', str(value))
self.env['runtime']['outputManager'].presentText(_("{0} percent speech rate").format(int(value * 100)), soundIcon='', interrupt=True)
def setCallback(self, callback):
pass
super().__init__("speech", "rate", "inc")

View File

@@ -2,29 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import math
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "adjustment_base.py")
_spec = importlib.util.spec_from_file_location("adjustment_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
adjustment_command = _module.adjustment_command
class command(adjustment_command):
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Increase the speech volume')
def run(self):
value = self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'volume')
value = round((math.ceil(10 * value) / 10) + 0.1, 2)
if value > 1.0:
value = 1.0
self.env['runtime']['settingsManager'].setSetting('speech', 'volume', str(value))
self.env['runtime']['outputManager'].presentText(_("{0} percent speech volume").format(int(value * 100)), soundIcon='', interrupt=True)
def setCallback(self, callback):
pass
super().__init__("speech", "volume", "inc")

View File

@@ -2,35 +2,49 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import line_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Presents the indentation level for the current line')
pass
def get_description(self):
return _("Presents the indentation level for the current line")
def run(self):
# Prefer review cursor over text cursor
if self.env['screen']['newCursorReview']:
cursorPos = self.env['screen']['newCursorReview'].copy()
if self.env["screen"]["newCursorReview"]:
cursor_pos = self.env["screen"]["newCursorReview"].copy()
else:
cursorPos = self.env['screen']['newCursor'].copy()
x, y, currLine = \
line_utils.getCurrentLine(cursorPos['x'], cursorPos['y'], self.env['screen']['newContentText'])
if currLine.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(_("indent {0}").format(len(currLine) - len(currLine.lstrip())), interrupt=True)
cursor_pos = self.env["screen"]["new_cursor"].copy()
x, y, curr_line = line_utils.get_current_line(
cursor_pos["x"],
cursor_pos["y"],
self.env["screen"]["new_content_text"],
)
def setCallback(self, callback):
if curr_line.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), sound_icon="EmptyLine", interrupt=True
)
else:
self.env["runtime"]["OutputManager"].present_text(
_("indent {0}").format(
len(curr_line) - len(curr_line.lstrip())
),
interrupt=True,
)
def set_callback(self, callback):
pass

View File

@@ -2,27 +2,40 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('selects the last clipboard')
def run(self):
if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'):
self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True)
return
self.env['runtime']['memoryManager'].setLastIndex('clipboardHistory')
clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory')
self.env['runtime']['outputManager'].presentText(clipboard, interrupt=True)
def setCallback(self, callback):
pass
def get_description(self):
return _("selects the last clipboard")
def run(self):
if self.env["runtime"]["MemoryManager"].is_index_list_empty(
"clipboardHistory"
):
self.env["runtime"]["OutputManager"].present_text(
_("clipboard empty"), interrupt=True
)
return
self.env["runtime"]["MemoryManager"].set_last_index("clipboardHistory")
clipboard = self.env["runtime"][
"MemoryManager"
].get_index_list_element("clipboardHistory")
self.env["runtime"]["OutputManager"].present_text(
clipboard, interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,37 +2,54 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import mark_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Presents the currently selected text that will be copied to the clipboard')
pass
def get_description(self):
return _(
"Presents the currently selected text that will be copied to the "
"clipboard"
)
def run(self):
if not (self.env['commandBuffer']['Marks']['1'] and \
self.env['commandBuffer']['Marks']['2']):
self.env['runtime']['outputManager'].presentText(_("please set begin and endmark"), interrupt=True)
if not (
self.env["commandBuffer"]["Marks"]["1"]
and self.env["commandBuffer"]["Marks"]["2"]
):
self.env["runtime"]["OutputManager"].present_text(
_("please set begin and endmark"), interrupt=True
)
return
# use the last first and the last setted mark as range
startMark = self.env['commandBuffer']['Marks']['1'].copy()
endMark = self.env['commandBuffer']['Marks']['2'].copy()
start_mark = self.env["commandBuffer"]["Marks"]["1"].copy()
end_mark = self.env["commandBuffer"]["Marks"]["2"].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
marked = mark_utils.get_text_between_marks(
start_mark, end_mark, self.env["screen"]["new_content_text"]
)
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True)
self.env["runtime"]["OutputManager"].present_text(
_("blank"), sound_icon="EmptyLine", interrupt=True
)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
self.env["runtime"]["OutputManager"].present_text(
marked, interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,35 +2,56 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('selects the next clipboard')
def run(self):
if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'):
self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True)
return
self.env['runtime']['memoryManager'].getNextIndex('clipboardHistory')
isFirst = self.env['runtime']['memoryManager'].isFirstIndex('clipboardHistory')
isLast = self.env['runtime']['memoryManager'].isLastIndex('clipboardHistory')
clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory')
if isFirst:
self.env['runtime']['outputManager'].presentText(_('First clipboard '), interrupt=True)
if isLast:
self.env['runtime']['outputManager'].presentText(_('Last clipboard '), interrupt=True)
speechInterrupt = not(isLast or isFirst)
self.env['runtime']['outputManager'].presentText(clipboard, interrupt = speechInterrupt)
def setCallback(self, callback):
pass
def get_description(self):
return _("selects the next clipboard")
def run(self):
if self.env["runtime"]["MemoryManager"].is_index_list_empty(
"clipboardHistory"
):
self.env["runtime"]["OutputManager"].present_text(
_("clipboard empty"), interrupt=True
)
return
self.env["runtime"]["MemoryManager"].get_next_index("clipboardHistory")
is_first = self.env["runtime"]["MemoryManager"].is_first_index(
"clipboardHistory"
)
is_last = self.env["runtime"]["MemoryManager"].is_last_index(
"clipboardHistory"
)
clipboard = self.env["runtime"][
"MemoryManager"
].get_index_list_element("clipboardHistory")
if is_first:
self.env["runtime"]["OutputManager"].present_text(
_("First clipboard "), interrupt=True
)
if is_last:
self.env["runtime"]["OutputManager"].present_text(
_("Last clipboard "), interrupt=True
)
speech_interrupt = not (is_last or is_first)
self.env["runtime"]["OutputManager"].present_text(
clipboard, interrupt=speech_interrupt
)
def set_callback(self, callback):
pass

View File

@@ -2,28 +2,41 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('get next quick menu entry')
def run(self):
menu = ''
value = ''
if self.env['runtime']['quickMenuManager'].nextEntry():
menu = self.env['runtime']['quickMenuManager'].getCurrentEntry()
if menu != '':
value = self.env['runtime']['quickMenuManager'].getCurrentValue()
self.env['runtime']['outputManager'].presentText(menu + ' ' + value, interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(_('Quick menu not available'), interrupt=True)
def setCallback(self, callback):
pass
def get_description(self):
return _("get next quick menu entry")
def run(self):
menu = ""
value = ""
if self.env["runtime"]["QuickMenuManager"].next_entry():
menu = self.env["runtime"]["QuickMenuManager"].get_current_entry()
if menu != "":
value = self.env["runtime"][
"QuickMenuManager"
].get_current_value()
self.env["runtime"]["OutputManager"].present_text(
menu + " " + value, interrupt=True
)
else:
self.env["runtime"]["OutputManager"].present_text(
_("Quick menu not available"), interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,22 +2,31 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('get next quick menu value')
def run(self):
if self.env['runtime']['quickMenuManager'].nextValue():
value = self.env['runtime']['quickMenuManager'].getCurrentValue()
self.env['runtime']['outputManager'].presentText(value, interrupt=True)
def setCallback(self, callback):
pass
def get_description(self):
return _("get next quick menu value")
def run(self):
if self.env["runtime"]["QuickMenuManager"].next_value():
value = self.env["runtime"]["QuickMenuManager"].get_current_value()
self.env["runtime"]["OutputManager"].present_text(
value, interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,29 +2,49 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import time
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
self.env['runtime']['memoryManager'].addIndexList('clipboardHistory', self.env['runtime']['settingsManager'].getSettingAsInt('general', 'numberOfClipboards'))
self.env["runtime"]["MemoryManager"].add_index_list(
"clipboardHistory",
self.env["runtime"]["SettingsManager"].get_setting_as_int(
"general", "numberOfClipboards"
),
)
def shutdown(self):
pass
def getDescription(self):
return _('pastes the text from the currently selected clipboard')
def run(self):
if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'):
self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True)
return
self.env['runtime']['outputManager'].presentText('paste clipboard', soundIcon='PasteClipboardOnScreen', interrupt=True)
clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory')
self.env['runtime']['screenManager'].injectTextToScreen(clipboard)
def setCallback(self, callback):
pass
def get_description(self):
return _("pastes the text from the currently selected clipboard")
def run(self):
if self.env["runtime"]["MemoryManager"].is_index_list_empty(
"clipboardHistory"
):
self.env["runtime"]["OutputManager"].present_text(
_("clipboard empty"), interrupt=True
)
return
self.env["runtime"]["OutputManager"].present_text(
"paste clipboard",
sound_icon="PasteClipboardOnScreen",
interrupt=True,
)
clipboard = self.env["runtime"][
"MemoryManager"
].get_index_list_element("clipboardHistory")
self.env["runtime"]["ScreenManager"].inject_text_to_screen(clipboard)
def set_callback(self, callback):
pass

View File

@@ -2,29 +2,38 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import line_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('present first line')
def run(self):
x, y, firstLine = \
line_utils.getCurrentLine(0, 0, self.env['screen']['newContentText'])
if firstLine.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(firstLine, interrupt=True)
def setCallback(self, callback):
pass
def get_description(self):
return _("present first line")
def run(self):
x, y, first_line = line_utils.get_current_line(
0, 0, self.env["screen"]["new_content_text"]
)
if first_line.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), sound_icon="EmptyLine", interrupt=True
)
else:
self.env["runtime"]["OutputManager"].present_text(
first_line, interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,29 +2,40 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import line_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('current line')
def run(self):
x, y, lastLine = \
line_utils.getCurrentLine(0, self.env['screen']['lines'] -1, self.env['screen']['newContentText'])
if lastLine.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(lastLine, interrupt=True)
def setCallback(self, callback):
def shutdown(self):
pass
def get_description(self):
return _("current line")
def run(self):
x, y, last_line = line_utils.get_current_line(
0,
self.env["screen"]["lines"] - 1,
self.env["screen"]["new_content_text"],
)
if last_line.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), sound_icon="EmptyLine", interrupt=True
)
else:
self.env["runtime"]["OutputManager"].present_text(
last_line, interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,34 +2,55 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('selects the previous clipboard')
pass
def get_description(self):
return _("selects the previous clipboard")
def run(self):
if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'):
self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True)
return
self.env['runtime']['memoryManager'].setPrefIndex('clipboardHistory')
isFirst = self.env['runtime']['memoryManager'].isFirstIndex('clipboardHistory')
isLast = self.env['runtime']['memoryManager'].isLastIndex('clipboardHistory')
clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory')
if isFirst:
self.env['runtime']['outputManager'].presentText(_('First clipboard '), interrupt=True)
if isLast:
self.env['runtime']['outputManager'].presentText(_('Last clipboard '), interrupt=True)
speechInterrupt = not(isLast or isFirst)
self.env['runtime']['outputManager'].presentText(clipboard, interrupt = speechInterrupt)
def setCallback(self, callback):
if self.env["runtime"]["MemoryManager"].is_index_list_empty(
"clipboardHistory"
):
self.env["runtime"]["OutputManager"].present_text(
_("clipboard empty"), interrupt=True
)
return
self.env["runtime"]["MemoryManager"].set_pref_index("clipboardHistory")
is_first = self.env["runtime"]["MemoryManager"].is_first_index(
"clipboardHistory"
)
is_last = self.env["runtime"]["MemoryManager"].is_last_index(
"clipboardHistory"
)
clipboard = self.env["runtime"][
"MemoryManager"
].get_index_list_element("clipboardHistory")
if is_first:
self.env["runtime"]["OutputManager"].present_text(
_("First clipboard "), interrupt=True
)
if is_last:
self.env["runtime"]["OutputManager"].present_text(
_("Last clipboard "), interrupt=True
)
speech_interrupt = not (is_last or is_first)
self.env["runtime"]["OutputManager"].present_text(
clipboard, interrupt=speech_interrupt
)
def set_callback(self, callback):
pass

View File

@@ -2,28 +2,41 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('get previous quick menu entry')
def run(self):
menu = ''
value = ''
if self.env['runtime']['quickMenuManager'].prevEntry():
menu = self.env['runtime']['quickMenuManager'].getCurrentEntry()
if menu != '':
value = self.env['runtime']['quickMenuManager'].getCurrentValue()
self.env['runtime']['outputManager'].presentText(menu + ' ' + value, interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(_('Quick menu not available'), interrupt=True)
def setCallback(self, callback):
pass
def get_description(self):
return _("get previous quick menu entry")
def run(self):
menu = ""
value = ""
if self.env["runtime"]["QuickMenuManager"].prev_entry():
menu = self.env["runtime"]["QuickMenuManager"].get_current_entry()
if menu != "":
value = self.env["runtime"][
"QuickMenuManager"
].get_current_value()
self.env["runtime"]["OutputManager"].present_text(
menu + " " + value, interrupt=True
)
else:
self.env["runtime"]["OutputManager"].present_text(
_("Quick menu not available"), interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,22 +2,31 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('get previous quick menu value')
def run(self):
if self.env['runtime']['quickMenuManager'].prevValue():
value = self.env['runtime']['quickMenuManager'].getCurrentValue()
self.env['runtime']['outputManager'].presentText(value, interrupt=True)
def setCallback(self, callback):
pass
def get_description(self):
return _("get previous quick menu value")
def run(self):
if self.env["runtime"]["QuickMenuManager"].prev_value():
value = self.env["runtime"]["QuickMenuManager"].get_current_value()
self.env["runtime"]["OutputManager"].present_text(
value, interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,120 +2,254 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import re
import time
import threading
import time
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
# Use commandBuffer like other commands
if 'progressMonitoring' not in self.env['commandBuffer']:
# Check if progress monitoring should be enabled by default from settings
if "progressMonitoring" not in self.env["commandBuffer"]:
# Check if progress monitoring should be enabled by default from
# settings
try:
defaultEnabled = self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'progressMonitoring')
except:
default_enabled = self.env["runtime"][
"SettingsManager"
].get_setting_as_bool("sound", "progressMonitoring")
except Exception as e:
# If setting doesn't exist, default to False
defaultEnabled = False
self.env['commandBuffer']['progressMonitoring'] = defaultEnabled
self.env['commandBuffer']['lastProgressTime'] = 0
self.env['commandBuffer']['lastProgressValue'] = -1
default_enabled = False
self.env["commandBuffer"]["progressMonitoring"] = default_enabled
self.env["commandBuffer"]["lastProgressTime"] = 0
self.env["commandBuffer"]["lastProgressValue"] = -1
def shutdown(self):
self.stopProgressMonitoring()
def getDescription(self):
return _('Toggle progress bar monitoring with ascending tones')
self.stop_progress_monitoring()
def get_description(self):
return _("Toggle progress bar monitoring with ascending tones")
def run(self):
# Check if commandBuffer exists
if 'progressMonitoring' not in self.env['commandBuffer']:
self.env['commandBuffer']['progressMonitoring'] = False
self.env['commandBuffer']['lastProgressTime'] = 0
self.env['commandBuffer']['lastProgressValue'] = -1
if self.env['commandBuffer']['progressMonitoring']:
self.stopProgressMonitoring()
self.env['runtime']['outputManager'].presentText(_("Progress monitoring disabled"), interrupt=True)
if "progressMonitoring" not in self.env["commandBuffer"]:
self.env["commandBuffer"]["progressMonitoring"] = False
self.env["commandBuffer"]["lastProgressTime"] = 0
self.env["commandBuffer"]["lastProgressValue"] = -1
if self.env["commandBuffer"]["progressMonitoring"]:
self.stop_progress_monitoring()
self.env["runtime"]["OutputManager"].present_text(
_("Progress monitoring disabled"), interrupt=True
)
else:
self.startProgressMonitoring()
self.env['runtime']['outputManager'].presentText(_("Progress monitoring enabled"), interrupt=True)
def startProgressMonitoring(self):
self.env['commandBuffer']['progressMonitoring'] = True
self.env['commandBuffer']['lastProgressTime'] = time.time()
self.env['commandBuffer']['lastProgressValue'] = -1
self.start_progress_monitoring()
self.env["runtime"]["OutputManager"].present_text(
_("Progress monitoring enabled"), interrupt=True
)
def start_progress_monitoring(self):
self.env["commandBuffer"]["progressMonitoring"] = True
self.env["commandBuffer"]["lastProgressTime"] = time.time()
self.env["commandBuffer"]["lastProgressValue"] = -1
# Don't control speech - let user decide with silence_until_prompt
def stopProgressMonitoring(self):
self.env['commandBuffer']['progressMonitoring'] = False
def stop_progress_monitoring(self):
self.env["commandBuffer"]["progressMonitoring"] = False
# Don't control speech - progress monitor is beep-only
def detectProgress(self, text):
if not self.env['runtime']['progressMonitoring']:
def detect_progress(self, text):
if not self.env["commandBuffer"]["progressMonitoring"]:
return
currentTime = time.time()
# Skip progress detection if current screen looks like a prompt
if self.is_current_line_prompt():
return
current_time = time.time()
# Pattern 1: Percentage (50%, 25.5%, etc.)
percentMatch = re.search(r'(\d+(?:\.\d+)?)\s*%', text)
if percentMatch:
percentage = float(percentMatch.group(1))
if percentage != self.env['runtime']['lastProgressValue']:
self.playProgressTone(percentage)
self.env['runtime']['lastProgressValue'] = percentage
self.env['runtime']['lastProgressTime'] = currentTime
percent_match = re.search(r"(\d+(?:\.\d+)?)\s*%", text)
if percent_match:
percentage = float(percent_match.group(1))
if percentage != self.env["commandBuffer"]["lastProgressValue"]:
self.play_progress_tone(percentage)
self.env["commandBuffer"]["lastProgressValue"] = percentage
self.env["commandBuffer"]["lastProgressTime"] = current_time
return
# Pattern 2: Fraction (15/100, 3 of 10, etc.)
fractionMatch = re.search(r'(\d+)\s*(?:of|/)\s*(\d+)', text)
if fractionMatch:
current = int(fractionMatch.group(1))
total = int(fractionMatch.group(2))
fraction_match = re.search(r"(\d+)\s*(?:of|/)\s*(\d+)", text)
if fraction_match:
current = int(fraction_match.group(1))
total = int(fraction_match.group(2))
if total > 0:
percentage = (current / total) * 100
if percentage != self.env['runtime']['lastProgressValue']:
self.playProgressTone(percentage)
self.env['runtime']['lastProgressValue'] = percentage
self.env['runtime']['lastProgressTime'] = currentTime
if (
percentage
!= self.env["commandBuffer"]["lastProgressValue"]
):
self.play_progress_tone(percentage)
self.env["commandBuffer"]["lastProgressValue"] = percentage
self.env["commandBuffer"][
"lastProgressTime"
] = current_time
return
# Pattern 3: Progress bars ([#### ], [====> ], etc.)
barMatch = re.search(r'\[([#=\-\*]+)([^\]]*)\]', text)
if barMatch:
filled = len(barMatch.group(1))
total = filled + len(barMatch.group(2))
if total > 0:
# Improved pattern to avoid matching IRC channels like [#channel]
bar_match = re.search(r"\[([#=\-\*]+)([\s\.]*)\]", text)
if bar_match:
filled = len(bar_match.group(1))
unfilled = len(bar_match.group(2))
total = filled + unfilled
# Require at least 2 progress chars total and unfilled portion must
# be spaces/dots
if total >= 2 and (
not bar_match.group(2)
or re.match(r"^[\s\.]*$", bar_match.group(2))
):
percentage = (filled / total) * 100
if percentage != self.env['runtime']['lastProgressValue']:
self.playProgressTone(percentage)
self.env['runtime']['lastProgressValue'] = percentage
self.env['runtime']['lastProgressTime'] = currentTime
if (
percentage
!= self.env["commandBuffer"]["lastProgressValue"]
):
self.play_progress_tone(percentage)
self.env["commandBuffer"]["lastProgressValue"] = percentage
self.env["commandBuffer"][
"lastProgressTime"
] = current_time
return
# Pattern 4: Generic activity indicators (Loading..., Working..., etc.)
activityPattern = re.search(r'(loading|processing|working|installing|downloading|compiling|building).*\.{2,}', text, re.IGNORECASE)
if activityPattern:
activity_pattern = re.search(
(
r"(loading|processing|working|installing|downloading|"
r"compiling|building).*\.{2,}"
),
text,
re.IGNORECASE,
)
if activity_pattern:
# Play a steady beep every 2 seconds for ongoing activity
if currentTime - self.env['runtime']['lastProgressTime'] >= 2.0:
self.playActivityBeep()
self.env['runtime']['lastProgressTime'] = currentTime
def playProgressTone(self, percentage):
if (
current_time - self.env["commandBuffer"]["lastProgressTime"]
>= 2.0
):
self.play_activity_beep()
self.env["commandBuffer"]["lastProgressTime"] = current_time
def play_progress_tone(self, percentage):
# Map 0-100% to 400-1200Hz frequency range
frequency = 400 + (percentage * 8)
frequency = max(400, min(1200, frequency)) # Clamp to safe range
self.env['runtime']['outputManager'].playFrequence(frequency, 0.15, interrupt=False)
def playActivityBeep(self):
self.env["runtime"]["OutputManager"].play_frequence(
frequency, 0.15, interrupt=False
)
def play_activity_beep(self):
# Single tone for generic activity
self.env['runtime']['outputManager'].playFrequence(800, 0.1, interrupt=False)
def setCallback(self, callback):
pass
self.env["runtime"]["OutputManager"].play_frequence(
800, 0.1, interrupt=False
)
def is_current_line_prompt(self):
"""Check if the current line looks like a standalone prompt (not command with progress)"""
import re
try:
# Get the current screen content
if not self.env["screen"]["new_content_text"]:
return False
lines = self.env["screen"]["new_content_text"].split("\n")
if not lines:
return False
# Check the last line (most common) and current cursor line for
# prompt patterns
lines_to_check = []
# Add last line (most common for prompts)
if lines:
lines_to_check.append(lines[-1])
# Add current cursor line if different from last line
if (
self.env["screen"]["new_cursor"]["y"] < len(lines)
and self.env["screen"]["new_cursor"]["y"] != len(lines) - 1
):
lines_to_check.append(
lines[self.env["screen"]["new_cursor"]["y"]]
)
# Standalone prompt patterns (no commands mixed in)
standalone_prompt_patterns = [
r"^\s*\$\s*$", # Just $ (with whitespace)
r"^\s*#\s*$", # Just # (with whitespace)
r"^\s*>\s*$", # Just > (with whitespace)
r"^\[.*\]\s*[\\\$#>]\s*$", # [path]$ without commands
r"^[a-zA-Z0-9._-]+[\\\$#>]\s*$", # bash-5.1$ without commands
# Interactive prompt patterns (these ARE standalone)
r".*\?\s*\[[YyNn]/[YyNn]\]\s*$", # ? [Y/n] or ? [y/N] style
r".*\?\s*\[[Yy]es/[Nn]o\]\s*$", # ? [Yes/No] style
# "continue? [Y/n]" style
r".*continue\?\s*\[[YyNn]/[YyNn]\].*$",
r"^::.*\?\s*\[[YyNn]/[YyNn]\].*$", # pacman style prompts
# Authentication prompts (these ARE standalone)
r"^\[[Ss]udo\]\s*[Pp]assword\s*for\s+.*:\s*$", # [sudo] password
r"^[Pp]assword\s*:\s*$", # Password:
r".*[Pp]assword\s*:\s*$", # general password prompts
# Continuation prompts (these ARE standalone)
r"^[Pp]ress\s+any\s+key\s+to\s+continue.*$", # Press any key
r"^[Aa]re\s+you\s+sure\?\s*.*$", # Are you sure?
]
for line in lines_to_check:
line = line.strip()
if not line:
continue
# Check if this line contains both a prompt AND other content (like commands)
# If so, don't treat it as a standalone prompt
has_prompt_marker = bool(
re.search(r".*@.*[\\\$#>]", line)
or re.search(r"^\[.*\]\s*[\\\$#>]", line)
)
if has_prompt_marker:
# If line has prompt marker but also has significant content after it,
# it's a command line, not a standalone prompt
prompt_end = max(
line.rfind("$"),
line.rfind("#"),
line.rfind(">"),
line.rfind("\\"),
)
if (
prompt_end >= 0 and prompt_end < len(line) - 5
): # More than just whitespace after prompt
continue # This is a command line, not a standalone prompt
for pattern in standalone_prompt_patterns:
try:
if re.search(pattern, line):
return True
except re.error:
continue
return False
except Exception as e:
# If anything fails, assume it's not a prompt to be safe
return False
def set_callback(self, callback):
pass

View File

@@ -2,23 +2,27 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('exits Fenrir')
def run(self):
self.env['runtime']['eventManager'].stopMainEventLoop()
def setCallback(self, callback):
def shutdown(self):
pass
def get_description(self):
return _("exits Fenrir")
def run(self):
self.env["runtime"]["EventManager"].stop_main_event_loop()
def set_callback(self, callback):
pass

View File

@@ -2,23 +2,30 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Removes marks from selected text')
def run(self):
self.env['runtime']['cursorManager'].clearMarks()
self.env['runtime']['outputManager'].presentText(_('Remove marks'), interrupt=True)
def setCallback(self, callback):
def shutdown(self):
pass
def get_description(self):
return _("Removes marks from selected text")
def run(self):
self.env["runtime"]["CursorManager"].clear_marks()
self.env["runtime"]["OutputManager"].present_text(
_("Remove marks"), interrupt=True
)
def set_callback(self, callback):
pass

View File

@@ -2,54 +2,96 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import word_utils
import string
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import word_utils
initialized = False
try:
import enchant
initialized = True
except:
except Exception as e:
pass
class command():
class command:
def __init__(self):
self.language = ''
self.language = ""
self.spellChecker = None
def initialize(self, environment):
self.env = environment
self.updateSpellLanguage()
self.update_spell_language()
def shutdown(self):
pass
def getDescription(self):
return _('removes the current word from the exceptions dictionary')
def updateSpellLanguage(self):
self.spellChecker = enchant.Dict(self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage'))
self.language = self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage')
def get_description(self):
return _("removes the current word from the exceptions dictionary")
def update_spell_language(self):
self.spellChecker = enchant.Dict(
self.env["runtime"]["SettingsManager"].get_setting(
"general", "spellCheckLanguage"
)
)
self.language = self.env["runtime"]["SettingsManager"].get_setting(
"general", "spellCheckLanguage"
)
def run(self):
if not initialized:
self.env['runtime']['outputManager'].presentText(_('pyenchant is not installed'), interrupt=True)
return
if self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') != self.language:
self.env["runtime"]["OutputManager"].present_text(
_("pyenchant is not installed"), interrupt=True
)
return
if (
self.env["runtime"]["SettingsManager"].get_setting(
"general", "spellCheckLanguage"
)
!= self.language
):
try:
self.updateSpellLanguage()
except:
return
self.update_spell_language()
except Exception as e:
return
cursor_pos = self.env["runtime"][
"CursorManager"
].get_review_or_text_cursor()
cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor()
# get the word
newContent = self.env['screen']['newContentText'].split('\n')[cursorPos['y']]
x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord(cursorPos['x'], 0, newContent)
currWord = currWord.strip(string.whitespace + r'!"#$%&()*+,-./:;<=Â?@[\\]^_{|}~')
if not currWord.isspace():
if self.spellChecker.is_removed(currWord):
self.env['runtime']['outputManager'].presentText(_('{0} is not in the dictionary').format(currWord,), soundIcon='Cancel', interrupt=True)
new_content = self.env["screen"]["new_content_text"].split("\n")[
cursor_pos["y"]
]
x, y, curr_word, end_of_screen, line_break = (
word_utils.get_current_word(cursor_pos["x"], 0, new_content)
)
curr_word = curr_word.strip(
string.whitespace + r'!"#$%&()*+,-./:;<=Â?@[\\]^_{|}~'
)
if not curr_word.isspace():
if self.spellChecker.is_removed(curr_word):
self.env["runtime"]["OutputManager"].present_text(
_("{0} is not in the dictionary").format(
curr_word,
),
sound_icon="Cancel",
interrupt=True,
)
else:
self.spellChecker.remove(currWord)
self.env['runtime']['outputManager'].presentText(_('{0} removed').format(currWord,), soundIcon='Accept', interrupt=True)
def setCallback(self, callback):
self.spellChecker.remove(curr_word)
self.env["runtime"]["OutputManager"].present_text(
_("{0} removed").format(
curr_word,
),
sound_icon="Accept",
interrupt=True,
)
def set_callback(self, callback):
pass

View File

@@ -2,23 +2,33 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Move review to the bottom of the screen')
pass
def get_description(self):
return _("Move review to the bottom of the screen")
def run(self):
self.env['screen']['newCursorReview'] = { 'x': 0, 'y':self.env['screen']['lines'] -1}
self.env['runtime']['outputManager'].presentText(_("Bottom"), interrupt=True, flush=False)
self.env["screen"]["newCursorReview"] = {
"x": 0,
"y": self.env["screen"]["lines"] - 1,
}
self.env["runtime"]["OutputManager"].present_text(
_("Bottom"), interrupt=True, flush=False
)
def setCallback(self, callback):
def set_callback(self, callback):
pass

View File

@@ -2,35 +2,82 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import char_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('presents the current character.')
def run(self):
self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor()
self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currChar = \
char_utils.getCurrentChar(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText'])
self.env['runtime']['outputManager'].presentText(currChar ,interrupt=True, ignorePunctuation=True, announceCapital=True, flush=False)
# is has attribute it enabled?
if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'hasAttributes'):
cursorPos = self.env['screen']['newCursorReview']
if not self.env['runtime']['attributeManager'].hasAttributes(cursorPos):
return
self.env['runtime']['outputManager'].presentText('has attribute', soundIcon='HasAttributes', interrupt=False)
def setCallback(self, callback):
def shutdown(self):
pass
def get_description(self):
return _("presents the current character.")
def run(self):
self.env["runtime"][
"CursorManager"
].enter_review_mode_curr_text_cursor()
# In table mode, sync to cell start if cursor is outside current cell
if self.env["runtime"]["TableManager"].is_table_mode():
table_info = self.env["runtime"]["TableManager"].get_current_table_cell_info()
if table_info:
cursor_pos = self.env["screen"]["newCursorReview"]
line_text = self.env["runtime"]["ScreenManager"].get_line_text(
cursor_pos["y"]
)
if line_text:
column_start = self.env["runtime"]["TableManager"].get_column_start_position(
line_text, table_info["column_index"]
)
cell_content = table_info["cell_content"]
cell_end = column_start + len(cell_content)
# If cursor is outside the current cell, move to cell start
if (
cursor_pos["x"] < column_start or
cursor_pos["x"] >= cell_end
):
self.env["screen"]["newCursorReview"]["x"] = column_start
(
self.env["screen"]["newCursorReview"]["x"],
self.env["screen"]["newCursorReview"]["y"],
curr_char,
) = char_utils.get_current_char(
self.env["screen"]["newCursorReview"]["x"],
self.env["screen"]["newCursorReview"]["y"],
self.env["screen"]["new_content_text"],
)
char_utils.present_char_for_review(
self.env,
curr_char,
interrupt=True,
announce_capital=True,
flush=False,
)
# is has attribute it enabled?
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
"general", "hasattributes"
):
cursor_pos = self.env["screen"]["newCursorReview"]
if not self.env["runtime"]["AttributeManager"].has_attributes(
cursor_pos
):
return
self.env["runtime"]["OutputManager"].present_text(
"has attribute", sound_icon="HasAttributes", interrupt=False
)
def set_callback(self, callback):
pass

View File

@@ -2,32 +2,49 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import char_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('set review and phonetically presents the current character')
def run(self):
self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor()
self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currChar = \
char_utils.getCurrentChar(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText'])
if currChar.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), interrupt=True, flush=False)
else:
currChar = char_utils.getPhonetic(currChar)
self.env['runtime']['outputManager'].presentText(currChar ,interrupt=True, announceCapital=True, flush=False)
def setCallback(self, callback):
def shutdown(self):
pass
def get_description(self):
return _("set review and phonetically presents the current character")
def run(self):
self.env["runtime"][
"CursorManager"
].enter_review_mode_curr_text_cursor()
(
self.env["screen"]["newCursorReview"]["x"],
self.env["screen"]["newCursorReview"]["y"],
curr_char,
) = char_utils.get_current_char(
self.env["screen"]["newCursorReview"]["x"],
self.env["screen"]["newCursorReview"]["y"],
self.env["screen"]["new_content_text"],
)
if curr_char.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), interrupt=True, flush=False
)
else:
curr_char = char_utils.get_phonetic(curr_char)
self.env["runtime"]["OutputManager"].present_text(
curr_char, interrupt=True, announce_capital=True, flush=False
)
def set_callback(self, callback):
pass

View File

@@ -2,31 +2,48 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import line_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('current line')
def run(self):
self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor()
self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currLine = \
line_utils.getCurrentLine(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText'])
if currLine.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True, flush=False)
else:
self.env['runtime']['outputManager'].presentText(currLine, interrupt=True, flush=False)
def setCallback(self, callback):
def shutdown(self):
pass
def get_description(self):
return _("current line")
def run(self):
self.env["runtime"][
"CursorManager"
].enter_review_mode_curr_text_cursor()
(
self.env["screen"]["newCursorReview"]["x"],
self.env["screen"]["newCursorReview"]["y"],
curr_line,
) = line_utils.get_current_line(
self.env["screen"]["newCursorReview"]["x"],
self.env["screen"]["newCursorReview"]["y"],
self.env["screen"]["new_content_text"],
)
if curr_line.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), sound_icon="EmptyLine", interrupt=True, flush=False
)
else:
self.env["runtime"]["OutputManager"].present_text(
curr_line, interrupt=True, flush=False
)
def set_callback(self, callback):
pass

View File

@@ -2,36 +2,99 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import word_utils
from fenrirscreenreader.core import debug
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('current word.')
pass
def get_description(self):
return _("current word.")
def run(self):
self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor()
self.env["runtime"][
"CursorManager"
].enter_review_mode_curr_text_cursor()
self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currWord, endOfScreen, lineBreak = \
word_utils.getCurrentWord(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText'])
if currWord.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), interrupt=True, flush=False)
(
self.env["screen"]["newCursorReview"]["x"],
self.env["screen"]["newCursorReview"]["y"],
curr_word,
end_of_screen,
line_break,
) = word_utils.get_current_word(
self.env["screen"]["newCursorReview"]["x"],
self.env["screen"]["newCursorReview"]["y"],
self.env["screen"]["new_content_text"],
)
# Check if we're in table mode and provide table-aware output
is_table_mode = self.env["runtime"]["TableManager"].is_table_mode()
self.env["runtime"]["DebugManager"].write_debug_out(
f"review_curr_word: is_table_mode={is_table_mode}",
debug.DebugLevel.INFO
)
if is_table_mode:
# Get current cell info using internal column tracking
table_info = (
self.env["runtime"]["TableManager"].get_current_table_cell_info()
)
if table_info:
# Announce with table context - cell content first, then header
output_text = (
f"{table_info['cell_content']} {table_info['column_header']}"
)
self.env["runtime"]["OutputManager"].present_text(
output_text, interrupt=True, flush=False
)
return # Exit early for table mode
else:
# Fallback to regular word announcement
if curr_word.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), interrupt=True, flush=False
)
else:
self.env["runtime"]["OutputManager"].present_text(
curr_word, interrupt=True, flush=False
)
else:
self.env['runtime']['outputManager'].presentText(currWord, interrupt=True, flush=False)
if endOfScreen:
if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'):
self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen')
if lineBreak:
if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'lineBreak'):
self.env['runtime']['outputManager'].presentText(_('line break'), interrupt=False, soundIcon='EndOfLine')
def setCallback(self, callback):
# Regular word announcement
if curr_word.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), interrupt=True, flush=False
)
else:
self.env["runtime"]["OutputManager"].present_text(
curr_word, interrupt=True, flush=False
)
if end_of_screen:
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
"review", "end_of_screen"
):
self.env["runtime"]["OutputManager"].present_text(
_("end of screen"),
interrupt=True,
sound_icon="EndOfScreen",
)
if line_break:
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
"review", "line_break"
):
self.env["runtime"]["OutputManager"].present_text(
_("line break"), interrupt=False, sound_icon="EndOfLine"
)
def set_callback(self, callback):
pass

View File

@@ -2,40 +2,73 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import word_utils
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import char_utils
from fenrirscreenreader.utils import word_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Phonetically spells the current word')
def run(self):
self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor()
self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currWord, endOfScreen, lineBreak = \
word_utils.getCurrentWord(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText'])
if currWord.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), interrupt=True, flush=False)
else:
firstSequence = True
for c in currWord:
currChar = char_utils.getPhonetic(c)
self.env['runtime']['outputManager'].presentText(currChar, interrupt=firstSequence, announceCapital=True, flush=False)
firstSequence = False
if endOfScreen:
if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'):
self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen')
if lineBreak:
if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'lineBreak'):
self.env['runtime']['outputManager'].presentText(_('line break'), interrupt=False, soundIcon='EndOfLine')
def setCallback(self, callback):
pass
def get_description(self):
return _("Phonetically spells the current word")
def run(self):
self.env["runtime"][
"CursorManager"
].enter_review_mode_curr_text_cursor()
(
self.env["screen"]["newCursorReview"]["x"],
self.env["screen"]["newCursorReview"]["y"],
curr_word,
end_of_screen,
line_break,
) = word_utils.get_current_word(
self.env["screen"]["newCursorReview"]["x"],
self.env["screen"]["newCursorReview"]["y"],
self.env["screen"]["new_content_text"],
)
if curr_word.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), interrupt=True, flush=False
)
else:
first_sequence = True
for c in curr_word:
curr_char = char_utils.get_phonetic(c)
self.env["runtime"]["OutputManager"].present_text(
curr_char,
interrupt=first_sequence,
announce_capital=True,
flush=False,
)
first_sequence = False
if end_of_screen:
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
"review", "end_of_screen"
):
self.env["runtime"]["OutputManager"].present_text(
_("end of screen"),
interrupt=True,
sound_icon="EndOfScreen",
)
if line_break:
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
"review", "line_break"
):
self.env["runtime"]["OutputManager"].present_text(
_("line break"), interrupt=False, sound_icon="EndOfLine"
)
def set_callback(self, callback):
pass

View File

@@ -2,28 +2,55 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import char_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Move review to the character below the current position')
pass
def get_description(self):
return _("Move review to the character below the current position")
def run(self):
cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor()
self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], downChar, endOfScreen = \
char_utils.getDownChar(self.env['screen']['newCursorReview']['x'],self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText'])
self.env['runtime']['outputManager'].presentText(downChar ,interrupt=True, ignorePunctuation=True, announceCapital=True, flush=False)
if endOfScreen:
if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'):
self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen')
def setCallback(self, callback):
cursor_pos = self.env["runtime"][
"CursorManager"
].get_review_or_text_cursor()
(
self.env["screen"]["newCursorReview"]["x"],
self.env["screen"]["newCursorReview"]["y"],
downChar,
end_of_screen,
) = char_utils.get_down_char(
self.env["screen"]["newCursorReview"]["x"],
self.env["screen"]["newCursorReview"]["y"],
self.env["screen"]["new_content_text"],
)
self.env["runtime"]["OutputManager"].present_text(
downChar,
interrupt=True,
ignore_punctuation=True,
announce_capital=True,
flush=False,
)
if end_of_screen:
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
"review", "end_of_screen"
):
self.env["runtime"]["OutputManager"].present_text(
_("end of screen"),
interrupt=True,
sound_icon="EndOfScreen",
)
def set_callback(self, callback):
pass

Some files were not shown because too many files have changed in this diff Show More