11 Commits

Author SHA1 Message Date
2462a081bf Add a documentation string for the module cli. 2025-01-28 15:30:09 -05:00
1f489a1ae9 Tweaks. 2025-01-28 15:23:04 -05:00
8ce9a8ffeb Move the command line into the main package directory.
The recommendation is that you put you cli script into the package
itself and add in an entry to that module as an entrypoint.
2025-01-28 15:22:07 -05:00
d8395c12e2 Add some things into the file. 2025-01-28 15:21:30 -05:00
3e1c8a2829 Drop the setup.py file if we can. 2025-01-28 15:20:53 -05:00
75199dfe0e Version bump. 2025-01-28 07:49:54 -05:00
160c40e931 Modified lock file. 2025-01-28 04:07:37 -05:00
47c626b420 Add more dynamically computed fields.
That said, let's use the old file for some of the computed fields for
the time being.
2025-01-28 04:06:00 -05:00
f509d89d90 Drop the warning about the dependencies being overwritten.
The pyproject.toml file is the place where things are being migrated
too so it was a bit reduntant.
2025-01-28 04:04:59 -05:00
39a918f74b My testing work with uv.
This seems to be building.
2025-01-24 12:20:41 -05:00
71d92e9702 Merged changes from master. 2025-01-08 20:28:16 -05:00
410 changed files with 14901 additions and 23298 deletions

1
.gitignore vendored
View File

@ -6,4 +6,3 @@ dist/
build/ build/
*.kate-swp *.kate-swp
.directory .directory
CLAUDE.md

1
.python-version Normal file
View File

@ -0,0 +1 @@
3.13

28
CREDITS
View File

@ -1,30 +1,18 @@
# Fenrir Screen Reader Credits # Fenrir screen reader
## Current Maintainer ## Developers
* **Storm Dragon** - Project leader and maintainer * Storm Dragon: Project leader
* Jeremiah: Coder.
## Current Contributors
* **Jeremiah** - Developer
## Previous Developers ## Previous Developers
* **Chrys** - Original creator and main developer * Chrys: coder.
## Special Thanks ## Special thanks to:
* **F123 Consulting** - Suggestions, funding, and extensive testing * F123 Consulting for suggestions, some funding, and endless testing.
* **Stormux Community** - Continuation of the project and ongoing support * Stormux for continuation of the project.
* **All contributors** - Bug reports, feature requests, and community support
## Community
* IRC: irc.stormux.org #stormux
* Email list: stormux+subscribe@groups.io
* Wiki: https://git.stormux.org/storm/fenrir/wiki

690
README.md
View File

@ -1,99 +1,69 @@
# Fenrir # Fenrir
A modern, modular, flexible and fast console screen reader. A modern, modular, flexible and fast console screenreader.
It should run on any operating system. If you want to help, or write drivers to make it work on other systems, just let me know. It should run on any operating system. If you want to help, or write drivers to make it work on other systems, just let me know.
This software is licensed under the LGPL v3. This software is licensed under the LGPL v3.
**Current maintainer:** Storm Dragon
**Previous developer:** Chrys
## Key Features
- **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
- **Spell Checking**: Built-in spell checker with word management
- **Language Support**: Multiple speech synthesis languages and voices
- **Bookmark System**: Quick access to specific screen areas
- **Auto-announcement**: Automatic reading of incoming text and time announcements
- **Tutorial Mode**: Built-in help system for learning keyboard shortcuts
## OS Requirements ## OS Requirements
- Linux (ptyDriver, vcsaDriver, evdevDriver) - Primary platform with full support - Linux (ptyDriver, vcsaDriver, evdevDriver)
- macOS (ptyDriver) - Limited support - macOS (ptyDriver)
- BSD (ptyDriver) - Limited support - BSD (ptyDriver)
- Windows (ptyDriver) - Limited support - Windows (ptyDriver)
## Core Requirements ## Core Requirements
- Python 3 >= 3.9 (recommended 3.13+) - python3 >= 3.3
- Screen, input, speech, sound driver dependencies (see "Features, Drivers, Extras" section) - screen, input, speech, sound drivers dependencies see "Features, Drivers, Extras".
- For full functionality on Linux: evdev, speech-dispatcher, sox
## Features, Drivers, Extras, Dependencies ## Features, Drivers, Extras, Dependencies
### Input Drivers: ### Input Drivers:
1. **evdevDriver** - Linux evdev input driver (recommended for Linux) 1. "evdevDriver" input driver for linux evdev
- python-evdev >=0.6.3 (This is commonly referred to as python3-evdev by your distribution) - python-evdev >=0.6.3 (This is commonly referred to as python3-evdev by your distribution)
- python-pyudev - python-pyudev
- loaded uinput kernel module - loaded uinput kernel module
- ReadWrite permission: - ReadWrite permission
- /dev/input - /dev/input
- /dev/uinput - /dev/uinput
2. **ptyDriver** - Terminal emulation input driver (cross-platform) 2. "ptyDriver" terminal emulation input driver
- python-pyte - python-pyte
3. **atspiDriver** - AT-SPI input driver for desktop environments
- python-pyatspi2
### Remote Drivers:
1. **unixDriver** - Unix socket remote control (default)
- socat (for command-line interaction)
2. **tcpDriver** - TCP socket remote control (localhost only)
- netcat or telnet (for command-line interaction)
### Screen Drivers: ### Screen Drivers:
1. **vcsaDriver** - Linux VCSA devices driver (recommended for Linux TTY) 1. "vcsaDriver" screen driver for linux VCSA devices
- python-dbus - python-dbus
- Read permission to the following files and services: - Read permission to the following files and services:
- /sys/devices/virtual/tty/tty0/active - /sys/devices/virtual/tty/tty0/active
- /dev/tty[1-64] - /dev/tty[1-64]
- /dev/vcsa[1-64] - /dev/vcsa[1-64]
- read logind DBUS - read logind DBUS
2. **ptyDriver** - Terminal emulation driver (cross-platform) 2. "ptyDriver" terminal emulation driver
- python-pyte - python-pyte
### Speech Drivers: ### Speech Drivers:
1. **speechdDriver** - Speech-dispatcher driver (recommended) 1. "genericDriver" (default) speech driver for sound as subprocess:
- Speech-dispatcher - espeak or espeak-ng
- python-speechd 2. "speechdDriver" speech driver for Speech-dispatcher:
2. **genericDriver** - Generic subprocess speech driver - Speech-dispatcher
- espeak or espeak-ng (or any TTS command) - python-speechd
3. **debugDriver** - Debug speech driver for testing 3. "emacspeakDriver" speech driver for emacspeak
- No dependencies - emacspeak
### Sound Drivers: ### Sound Drivers:
1. **genericDriver** (default) - Generic subprocess sound driver 1. "genericDriver" (default) sound driver for sound as subprocess:
- Sox with opus support (recommended) - Sox
2. **gstreamerDriver** - GStreamer sound driver 2. "gstreamerDriver" sound driver for gstreamer
- gstreamer >=1.0 - gstreamer >=1.0
- GLib - GLib
3. **debugDriver** - Debug sound driver for testing
- No dependencies
## Extras: ## Extras:
@ -121,524 +91,16 @@ If there is a package for your distrobution of choice, please let us know so we
- You can also just run it from Git without installing: - You can also just run it from Git without installing:
Requires root privileges Requires root privileges
cd src/ cd src/fenrir/
sudo ./fenrir sudo ./fenrir
Settings are located in: Settings "settings.conf" is located in the "config" directory or after installation in /etc/fenrir/settings.
- **After installation**: `/etc/fenrir/settings/settings.conf` Take care to use drivers from the config matching your installed drivers.
- **Development**: `config/settings/settings.conf` By default it uses:
- sound driver: genericDriver (via sox, could configured in settings.conf)
- speech driver: genericDriver (via espeak or espeak-ng, could configured in settings.conf)
- input driver: evdevDriver
By default Fenrir uses:
- **Sound driver**: genericDriver (via sox)
- **Speech driver**: speechdDriver (via speech-dispatcher)
- **Input driver**: evdevDriver (Linux) or ptyDriver (other platforms)
- **Screen driver**: vcsaDriver (Linux TTY) or ptyDriver (terminal emulation)
## Getting Started
### Basic Usage
1. **Start Fenrir**:
```bash
sudo systemctl start fenrir # If installed as service
# OR
sudo fenrir # Run directly
```
2. **Basic Navigation**:
- **Fenrir Key**: By default `Insert`, `Keypad Insert`, or `Meta/Super` key
- **Tutorial Mode**: `Fenrir + H` to learn all commands interactively
- **Quit Fenrir**: `Fenrir + Q`
3. **Essential Commands**:
- `Ctrl` - Stop speech (shut up)
- `Fenrir + Keypad 5` - Read current screen
- `Keypad 8` - Read current line
- `Keypad 5` - Read current word
- `Keypad 2` - Read current character
- `Fenrir + T` - Announce time
- `Fenrir + S` - Spell check current word
- `Fenrir + Keypad *` - Toggle table mode / highlight tracking
### Keyboard Layouts
Fenrir supports two main keyboard layouts:
- **Desktop Layout**: Uses numeric keypad for navigation (recommended for desktop users)
- **Laptop Layout**: Alternative bindings for keyboards without numeric keypad
Configure in `/etc/fenrir/settings/settings.conf`:
```ini
[keyboard]
keyboardLayout=desktop # or 'laptop'
```
### First Time Setup
1. **Enable Fenrir at boot**:
```bash
sudo systemctl enable fenrir
```
2. **Configure audio** (if needed):
- For PulseAudio: Run configure_pulse.sh script (see below)
- For PipeWire: Run configure_pipewire.sh script (see below)
3. **Test speech**:
```bash
# Test speech-dispatcher directly
sudo spd-say "Hello World"
```
## Remote Control
Fenrir includes a powerful remote control system that allows external applications and scripts to control Fenrir through Unix sockets or TCP connections. This is particularly useful for automation, integration with other applications, or providing alternative control methods.
### Configuration
Enable remote control in `/etc/fenrir/settings/settings.conf`:
```ini
[remote]
enable=True
driver=unixDriver # or tcpDriver
port=22447 # for TCP driver
socketFile= # custom socket path (optional)
enableSettingsRemote=True # allow settings changes
enableCommandRemote=True # allow command execution
```
### Remote Drivers
1. **unixDriver** (recommended): Uses Unix domain sockets
- Socket location: `/tmp/fenrirscreenreader-deamon.sock` (TTY mode) or `/tmp/fenrirscreenreader-<pid>.sock`
- More secure, local-only access
- Works with `socat`
2. **tcpDriver**: Uses TCP sockets on localhost
- Default port: 22447
- Works with `netcat`, `telnet`, or any TCP client
- Local connections only (127.0.0.1)
### Using socat with Unix Sockets
The `socat` command provides the easiest way to send commands to Fenrir:
#### Basic Speech Control
```bash
# Interrupt current speech
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Speak custom text
echo "command say Hello, this is a test message" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Temporarily disable speech (until next keystroke)
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
```
#### Settings Control
```bash
# Enable highlight tracking mode
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Change speech parameters
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#pitch=0.6" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#volume=0.9" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Change punctuation level (none/some/most/all)
echo "setting set general#punctuationLevel=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set general#punctuationLevel=none" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Voice and TTS engine control
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#module=espeak-ng" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Disable sound temporarily
echo "setting set sound#enabled=False" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set sound#volume=0.5" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Keyboard and input settings
echo "setting set keyboard#charEchoMode=1" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set keyboard#wordEcho=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Screen control (ignore specific TTYs)
echo "setting set screen#ignoreScreen=1,2,3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Multiple settings at once
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuationLevel=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Reset all settings to defaults
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Save current settings
echo "setting save" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting saveas /tmp/my-fenrir-settings.conf" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
```
#### Clipboard Operations
```bash
# Place text into clipboard
echo "command clipboard This text will be copied to clipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Export clipboard to file
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
```
#### Window Management
```bash
# Define a window area (x1 y1 x2 y2)
echo "command window 0 0 80 24" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Reset window to full screen
echo "command resetwindow" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
```
#### VMenu Control
```bash
# Set virtual menu context
echo "command vmenu nano/file" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Reset virtual menu
echo "command resetvmenu" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
```
#### Application Control
```bash
# Quit Fenrir
echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
```
### Using TCP Driver
If using the TCP driver, replace socat commands with netcat:
```bash
# Using netcat
echo "command say Hello from TCP" | nc localhost 22447
# Using telnet
echo "command interrupt" | telnet localhost 22447
```
### Remote Command Reference
#### Command Format
```
command <action> [parameters]
setting <action> [parameters]
```
#### Available Commands
**Speech Commands:**
- `command say <text>` - Speak the specified text
- `command interrupt` - Stop current speech
- `command tempdisablespeech` - Disable speech until next key press
**Clipboard Commands:**
- `command clipboard <text>` - Add text to clipboard
- `command exportclipboard` - Export clipboard to file
**Window Commands:**
- `command window <x1> <y1> <x2> <y2>` - Define window area
- `command resetwindow` - Reset to full screen
**VMenu Commands:**
- `command vmenu <menu_path>` - Set vmenu context
- `command resetvmenu` - Reset vmenu
**Application Commands:**
- `command quitapplication` - Quit Fenrir
#### Available Settings
**Settings Commands:**
- `setting set <section>#<key>=<value>` - Set configuration value
- `setting reset` - Reset all settings to defaults
- `setting save [path]` - Save current settings
- `setting saveas <path>` - Save settings to specific file
**Common Settings:**
*Speech Settings:*
- `speech#enabled=True/False` - Enable/disable speech
- `speech#rate=0.1-1.0` - Speech rate (speed)
- `speech#pitch=0.1-1.0` - Speech pitch (tone)
- `speech#volume=0.1-1.0` - Speech volume
- `speech#voice=voice_name` - Voice selection (e.g., "en-us+f3")
- `speech#module=module_name` - TTS module (e.g., "espeak-ng")
- `speech#driver=driver_name` - Speech driver (speechdDriver/genericDriver)
- `speech#autoReadIncoming=True/False` - Auto-read new text
*Sound Settings:*
- `sound#enabled=True/False` - Enable/disable sound
- `sound#volume=0.1-1.0` - Sound volume
- `sound#driver=driver_name` - Sound driver (genericDriver/gstreamerDriver)
- `sound#theme=theme_name` - Sound theme
*General Settings:*
- `general#punctuationLevel=none/some/most/all` - Punctuation verbosity
- `general#debugLevel=0-3` - Debug level
- `general#emoticons=True/False` - Enable emoticon replacement
- `general#autoSpellCheck=True/False` - Automatic spell checking
*Focus Settings:*
- `focus#cursor=True/False` - Follow text cursor
- `focus#highlight=True/False` - Follow text highlighting
*Keyboard Settings:*
- `keyboard#charEchoMode=0-2` - Character echo (0=none, 1=always, 2=capslock only)
- `keyboard#wordEcho=True/False` - Echo complete words
- `keyboard#charDeleteEcho=True/False` - Echo deleted characters
- `keyboard#interruptOnKeyPress=True/False` - Interrupt speech on key press
*Screen Settings:*
- `screen#ignoreScreen=1,2,3` - TTY screens to ignore
- `screen#autodetectIgnoreScreen=True/False` - Auto-detect screens to ignore
- `screen#screenUpdateDelay=float` - Screen update delay
*Time Settings:*
- `time#enabled=True/False` - Enable time announcements
- `time#presentTime=True/False` - Announce time
- `time#presentDate=True/False` - Announce date changes
- `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
```bash
#!/bin/bash
# notify_fenrir.sh - Send notifications to Fenrir
SOCKET="/tmp/fenrirscreenreader-deamon.sock"
fenrir_say() {
echo "command say $1" | socat - UNIX-CLIENT:$SOCKET
}
fenrir_interrupt() {
echo "command interrupt" | socat - UNIX-CLIENT:$SOCKET
}
# Usage examples
fenrir_say "Build completed successfully"
fenrir_interrupt
```
#### Python Integration
```python
#!/usr/bin/env python3
import socket
import os
def send_fenrir_command(command):
"""Send command to Fenrir via Unix socket"""
socket_path = "/tmp/fenrirscreenreader-deamon.sock"
if os.path.exists(socket_path):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
sock.connect(socket_path)
sock.send(command.encode('utf-8'))
finally:
sock.close()
# Examples
send_fenrir_command("command say Processing complete")
send_fenrir_command("setting set speech#rate=0.9")
```
### Security Considerations
- Unix sockets are accessible only to the user running Fenrir
- TCP driver binds only to localhost (127.0.0.1)
- Socket file permissions are set to write-only (0o222)
- Commands are processed with Fenrir's privileges
- Settings changes can be disabled via `enableSettingsRemote=False`
- Command execution can be disabled via `enableCommandRemote=False`
### Troubleshooting
**Socket not found:**
- Verify Fenrir is running: `ps aux | grep fenrir`
- Check socket location: `/tmp/fenrirscreenreader-*`
- Ensure remote driver is enabled in settings
**Commands not working:**
- Verify `enableCommandRemote=True` in settings
- Check Fenrir debug logs: `/var/log/fenrir.log`
- Test with simple command: `echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock`
## Configure pulseaudio ## Configure pulseaudio
@ -665,64 +127,12 @@ just run the configuration script twice (once as user, once as root):
The script is also located in the tools directory in git The script is also located in the tools directory in git
## Command Line Options ## localization
copy fenrir.mo translations file from fenrir/locale/your_language/LC_MESSAGES/fenrir.mo to /usr/share/locale/your_language/LC_MESSAGES/fenrir.mo
Fenrir supports several command-line options for different use cases:
```
fenrir [OPTIONS]
```
### Options:
- `-h, --help` - Show help message and exit
- `-v, --version` - Show version information and exit
- `-f, --foreground` - Run in foreground (don't daemonize)
- `-s, --setting SETTING-FILE` - Path to custom settings file
- `-o, --options SECTION#SETTING=VALUE;..` - Override settings file options
- `-d, --debug` - Enable debug mode
- `-p, --print` - Print debug messages to screen
- `-e, --emulated-pty` - Use PTY emulation with escape sequences for input (enables desktop/X/Wayland usage)
- `-E, --emulated-evdev` - Use PTY emulation with evdev for input (single instance)
- `-F, --force-all-screens` - Force Fenrir to respond on all screens, ignoring ignoreScreen setting
- `-i, -I, --ignore-screen SCREEN` - Ignore specific screen(s). Can be used multiple times. Combines with existing ignore settings.
### Examples:
```bash
# Run in foreground with debug output
sudo fenrir -f -d
# Use PTY emulation for desktop use
sudo fenrir -e
# Override settings via command line
sudo fenrir -o "speech#rate=0.8;sound#volume=0.5"
# Force Fenrir to work on all screens (ignore ignoreScreen setting)
sudo fenrir -F
# Ignore specific screens
sudo fenrir --ignore-screen 1
sudo fenrir -i 1 -i 2 # Ignore screens 1 and 2
```
## Localization
Translation files are located in the `locale/` directory. To install translations:
```bash
# Copy translation file to system location
sudo cp locale/your_language/LC_MESSAGES/fenrir.mo /usr/share/locale/your_language/LC_MESSAGES/fenrir.mo
```
Available languages:
- German (de)
- Spanish (es)
- Polish (pl)
- Portuguese (pt)
- Russian (ru)
## Documentation and Support ## Documentation and Support
- **Email list**: [stormux+subscribe@groups.io](mailto:stormux+subscribe@groups.io?subject=subscribe) with the subject subscribe - Email list: [stormux+subscribe@groups.io](mailto:stormux+subscribe@groups.io?subject=subscribe) with the subject subscribe.
- **Fenrir Wiki**: [https://git.stormux.org/storm/fenrir/wiki](https://git.stormux.org/storm/fenrir/wiki) - [Fenrir Wiki](https://git.stormux.org/storm/fenrir/wiki)
- **IRC**: irc.stormux.org #stormux - IRC: irc.stormux.org #stormux
- **Issues**: Report bugs and feature requests on the project repository

View File

@ -50,7 +50,7 @@ def check_dependency(dep: Dependency) -> bool:
dependencyList = [ dependencyList = [
# Core dependencies # Core dependencies
Dependency('FenrirCore', 'core', 'core', Dependency('FenrirCore', 'core', 'core',
pythonImports=['daemonize', 'enchant', 'pyperclip', 'setproctitle']), pythonImports=['daemonize', 'enchant']),
# Screen drivers # Screen drivers
Dependency('DummyScreen', 'screen', 'dummyDriver'), Dependency('DummyScreen', 'screen', 'dummyDriver'),
@ -58,7 +58,7 @@ dependencyList = [
pythonImports=['dbus'], pythonImports=['dbus'],
devicePaths=['/dev/vcsa']), devicePaths=['/dev/vcsa']),
Dependency('PTY', 'screen', 'ptyDriver', Dependency('PTY', 'screen', 'ptyDriver',
pythonImports=['pyte', 'xdg']), pythonImports=['pyte']),
# Input drivers # Input drivers
Dependency('DummyInput', 'input', 'dummyDriver'), Dependency('DummyInput', 'input', 'dummyDriver'),
@ -82,11 +82,7 @@ dependencyList = [
Dependency('Speechd', 'speech', 'speechdDriver', Dependency('Speechd', 'speech', 'speechdDriver',
pythonImports=['speechd']), pythonImports=['speechd']),
Dependency('GenericSpeech', 'speech', 'genericDriver', Dependency('GenericSpeech', 'speech', 'genericDriver',
checkCommands=['espeak-ng']), checkCommands=['espeak-ng'])
# Additional dependencies
Dependency('Pexpect', 'core', 'pexpectDriver',
pythonImports=['pexpect'])
] ]
defaultModules = { defaultModules = {
@ -94,8 +90,7 @@ defaultModules = {
'VCSA', 'VCSA',
'Evdev', 'Evdev',
'GenericSpeech', 'GenericSpeech',
'GenericSound', 'GenericSound'
'Pexpect'
} }
def check_all_dependencies(): def check_all_dependencies():

View File

@ -1,46 +1,4 @@
# 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 Keymap for Fenrir
KEY_RESERVED KEY_RESERVED
KEY_ESC KEY_ESC

View File

@ -73,8 +73,7 @@ KEY_FENRIR,KEY_SHIFT,KEY_0=set_bookmark_10
KEY_FENRIR,KEY_0=bookmark_10 KEY_FENRIR,KEY_0=bookmark_10
KEY_FENRIR,KEY_KPSLASH=set_window_application KEY_FENRIR,KEY_KPSLASH=set_window_application
2,KEY_FENRIR,KEY_KPSLASH=clear_window_application 2,KEY_FENRIR,KEY_KPSLASH=clear_window_application
KEY_KPPLUS=progress_bar_monitor KEY_KPPLUS=last_incoming
#KEY_FENRIR,KEY_KPPLUS=silence_until_prompt
KEY_FENRIR,KEY_F2=toggle_braille KEY_FENRIR,KEY_F2=toggle_braille
KEY_FENRIR,KEY_F3=toggle_sound KEY_FENRIR,KEY_F3=toggle_sound
KEY_FENRIR,KEY_F4=toggle_speech KEY_FENRIR,KEY_F4=toggle_speech
@ -114,8 +113,6 @@ KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_X=remove_marks
KEY_FENRIR,KEY_X=set_mark KEY_FENRIR,KEY_X=set_mark
KEY_FENRIR,KEY_SHIFT,KEY_X=marked_text KEY_FENRIR,KEY_SHIFT,KEY_X=marked_text
KEY_FENRIR,KEY_F10=toggle_vmenu_mode 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_SPACE=current_quick_menu_entry
KEY_FENRIR,KEY_CTRL,KEY_SPACE=current_quick_menu_value KEY_FENRIR,KEY_CTRL,KEY_SPACE=current_quick_menu_value
KEY_FENRIR,KEY_RIGHT=next_quick_menu_entry KEY_FENRIR,KEY_RIGHT=next_quick_menu_entry
@ -129,4 +126,3 @@ KEY_FENRIR,KEY_F8=export_clipboard_to_x
KEY_FENRIR,KEY_CTRL,KEY_UP=inc_alsa_volume KEY_FENRIR,KEY_CTRL,KEY_UP=inc_alsa_volume
KEY_FENRIR,KEY_CTRL,KEY_DOWN=dec_alsa_volume KEY_FENRIR,KEY_CTRL,KEY_DOWN=dec_alsa_volume
KEY_FENRIR,KEY_SHIFT,KEY_V=announce_fenrir_version KEY_FENRIR,KEY_SHIFT,KEY_V=announce_fenrir_version
KEY_F4=cycle_keyboard_layout

View File

@ -75,12 +75,11 @@ KEY_FENRIR,KEY_F2=toggle_braille
KEY_FENRIR,KEY_F3=toggle_sound KEY_FENRIR,KEY_F3=toggle_sound
KEY_FENRIR,KEY_F4=toggle_speech KEY_FENRIR,KEY_F4=toggle_speech
KEY_FENRIR,KEY_ENTER=temp_disable_speech KEY_FENRIR,KEY_ENTER=temp_disable_speech
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_SHIFT,KEY_CTRL,KEY_P=toggle_punctuation_level
KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_ENTER=toggle_output KEY_FENRIR,KEY_SHIFT,KEY_ENTER=toggle_output
KEY_FENRIR,KEY_SHIFT,KEY_E=toggle_emoticons 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_CTRL,KEY_T=toggle_auto_time
KEY_FENRIR,KEY_Y=toggle_highlight_tracking KEY_FENRIR,KEY_Y=toggle_highlight_tracking
#=toggle_barrier #=toggle_barrier
@ -112,8 +111,6 @@ KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_X=remove_marks
KEY_FENRIR,KEY_X=set_mark KEY_FENRIR,KEY_X=set_mark
KEY_FENRIR,KEY_SHIFT,KEY_X=marked_text KEY_FENRIR,KEY_SHIFT,KEY_X=marked_text
KEY_FENRIR,KEY_F10=toggle_vmenu_mode 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_SPACE=current_quick_menu_entry
KEY_FENRIR,KEY_CTRL,KEY_SPACE=current_quick_menu_value KEY_FENRIR,KEY_CTRL,KEY_SPACE=current_quick_menu_value
KEY_FENRIR,KEY_RIGHT=next_quick_menu_entry KEY_FENRIR,KEY_RIGHT=next_quick_menu_entry
@ -129,4 +126,3 @@ KEY_FENRIR,KEY_F8=export_clipboard_to_x
KEY_FENRIR,KEY_CTRL,KEY_UP=inc_alsa_volume KEY_FENRIR,KEY_CTRL,KEY_UP=inc_alsa_volume
KEY_FENRIR,KEY_CTRL,KEY_DOWN=dec_alsa_volume KEY_FENRIR,KEY_CTRL,KEY_DOWN=dec_alsa_volume
KEY_FENRIR,KEY_SHIFT,KEY_V=announce_fenrir_version KEY_FENRIR,KEY_SHIFT,KEY_V=announce_fenrir_version
KEY_F4=cycle_keyboard_layout

View File

@ -72,8 +72,7 @@ KEY_FENRIR,KEY_SHIFT,KEY_0=set_bookmark_10
KEY_FENRIR,KEY_0=bookmark_10 KEY_FENRIR,KEY_0=bookmark_10
KEY_FENRIR,KEY_KPSLASH=set_window_application KEY_FENRIR,KEY_KPSLASH=set_window_application
2,KEY_FENRIR,KEY_KPSLASH=clear_window_application 2,KEY_FENRIR,KEY_KPSLASH=clear_window_application
KEY_KPPLUS=progress_bar_monitor KEY_KPPLUS=last_incoming
KEY_FENRIR,KEY_KPPLUS=silence_until_prompt
#=toggle_braille #=toggle_braille
KEY_FENRIR,KEY_F3=toggle_sound KEY_FENRIR,KEY_F3=toggle_sound
KEY_FENRIR,KEY_F4=toggle_speech KEY_FENRIR,KEY_F4=toggle_speech
@ -127,4 +126,3 @@ KEY_FENRIR,KEY_CTRL,KEY_C=save_settings
KEY_FENRIR,KEY_F8=export_clipboard_to_x KEY_FENRIR,KEY_F8=export_clipboard_to_x
KEY_FENRIR,KEY_ALT,KEY_UP=inc_alsa_volume KEY_FENRIR,KEY_ALT,KEY_UP=inc_alsa_volume
KEY_FENRIR,KEY_ALT,KEY_DOWN=dec_alsa_volume KEY_FENRIR,KEY_ALT,KEY_DOWN=dec_alsa_volume
KEY_F4=cycle_keyboard_layout

View File

@ -126,4 +126,3 @@ KEY_FENRIR,KEY_CTRL,KEY_C=save_settings
KEY_FENRIR,KEY_F8=export_clipboard_to_x KEY_FENRIR,KEY_F8=export_clipboard_to_x
KEY_FENRIR,KEY_ALT,KEY_UP=inc_alsa_volume KEY_FENRIR,KEY_ALT,KEY_UP=inc_alsa_volume
KEY_FENRIR,KEY_ALT,KEY_DOWN=dec_alsa_volume KEY_FENRIR,KEY_ALT,KEY_DOWN=dec_alsa_volume
KEY_F4=cycle_keyboard_layout

View File

@ -85,5 +85,3 @@ alt+f12 - quit fenrir
^[[1;3F=temp_disable_speech ^[[1;3F=temp_disable_speech
# control+end - toggle auto read # control+end - toggle auto read
^[[1;5F=toggle_auto_read ^[[1;5F=toggle_auto_read
# F12 - cycle keyboard layout
^[[24~=cycle_keyboard_layout

View File

@ -0,0 +1,218 @@
# Fenrir comment: copy of speakup DefaultKeyAssignments converted to fenrir syntax
# Fenrir comment: https://android.googlesource.com/kernel/msm/+/android-7.1.0_r0.2/drivers/staging/speakup/DefaultKeyAssignments
# Fenrir comment: The insert or shift key named below is the fenrir key
# This file is intended to give you an overview of the default keys used
# by speakup for it's review functions. You may change them to be
# anything you want but that will take some familiarity with key
# mapping.
# We have remapped the insert or zero key on the keypad to act as a
# shift key. Well, actually as an altgr key. So in the following list
# InsKeyPad-period means hold down the insert key like a shift key and
# hit the keypad period.
# KeyPad-8 Say current Line
KEY_KP8=review_curr_line
# InsKeyPad-8 say from top of screen to reading cursor.
KEY_FENRIR,KEY_KP8=curr_screen_before_cursor
# KeyPad-7 Say Previous Line (UP one line)
KEY_KP7=review_prev_line
# KeyPad-9 Say Next Line (down one line)
KEY_KP9=review_next_line
# KeyPad-5 Say Current Word
KEY_KP5=review_curr_word
# InsKeyPad-5 Spell Current Word
KEY_FENRIR,KEY_KP5=review_curr_word_phonetic
# KeyPad-4 Say Previous Word (left one word)
KEY_KP4=review_prev_word
# InsKeyPad-4 say from left edge of line to reading cursor.
KEY_FENRIR,KEY_KP4=cursor_read_line_to_cursor
# KeyPad-6 Say Next Word (right one word)
KEY_KP6=review_next_word
# InsKeyPad-6 Say from reading cursor to right edge of line.
KEY_FENRIR,KEY_KP6=cursor_read_to_end_of_line
# KeyPad-2 Say Current Letter
KEY_KP2=review_curr_char
# InsKeyPad-2 say current letter phonetically
KEY_FENRIR,KEY_KP2=review_curr_char_phonetic
# KeyPad-1 Say Previous Character (left one letter)
KEY_KP1=review_prev_char
# KeyPad-3 Say Next Character (right one letter)
KEY_KP3=review_next_char
# KeyPad-plus Say Entire Screen
KEY_KPPLUS=curr_screen
# InsKeyPad-plus Say from reading cursor line to bottom of screen.
KEY_FENRIR,KEY_KPPLUS=curr_screen_after_cursor
# KeyPad-Minus Park reading cursor (toggle)
# TODO
# InsKeyPad-minus Say character hex and decimal value.
# TODO
# KeyPad-period Say Position (current line, position and console)
KEY_KPDOT=cursor_position
# InsKeyPad-period say colour attributes of current position.
KEY_FENRIR,KEY_KPDOT=attribute_cursor
# InsKeyPad-9 Move reading cursor to top of screen (insert pgup)
KEY_FENRIR,KEY_KP9=review_bottom
# InsKeyPad-3 Move reading cursor to bottom of screen (insert pgdn)
KEY_FENRIR,KEY_KP3=review_top
# InsKeyPad-7 Move reading cursor to left edge of screen (insert home)
KEY_FENRIR,KEY_KP7=review_screen_first_char
# InsKeyPad-1 Move reading cursor to right edge of screen (insert end)
KEY_FENRIR,KEY_KP1=review_screen_last_char
# ControlKeyPad-1 Move reading cursor to last character on current line.
KEY_CTRL,KEY_KP1=review_line_end
# KeyPad-Enter Shut Up (until another key is hit) and sync reading cursor
KEY_KPENTER=temp_disable_speech
# InsKeyPad-Enter Shut Up (until toggled back on).
KEY_FENRIR,KEY_KPENTER=toggle_speech
# InsKeyPad-star n<x|y> go to line (y) or column (x). Where 'n' is any
# allowed value for the row or column for your current screen.
# TODO
# KeyPad-/ Mark and Cut screen region.
KEY_KPSLASH=copy_marked_to_clipboard
# InsKeyPad-/ Paste screen region into any console.
KEY_FENRIR,KEY_KPSLASH=paste_clipboard
# Hitting any key while speakup is outputting speech will quiet the
# synth until it has caught up with what is being printed on the
# console.
# following by other fenrir commands
KEY_FENRIR,KEY_H=toggle_tutorial_mode
KEY_CTRL=shut_up
KEY_FENRIR,KEY_KP4=review_line_begin
#=review_line_end
#=review_line_first_char
#=review_line_last_char
KEY_FENRIR,KEY_ALT,KEY_1=present_first_line
KEY_FENRIR,KEY_ALT,KEY_2=present_last_line
KEY_FENRIR,KEY_SHIFT,KEY_KP4=review_prev_word_phonetic
KEY_FENRIR,KEY_SHIFT,KEY_KP6=review_next_word_phonetic
KEY_FENRIR,KEY_SHIFT,KEY_KP1=review_prev_char_phonetic
KEY_FENRIR,KEY_SHIFT,KEY_KP3=review_next_char_phonetic
KEY_FENRIR,KEY_CTRL,KEY_KP8=review_up
KEY_FENRIR,KEY_CTRL,KEY_KP2=review_down
#=exit_review
KEY_FENRIR,KEY_I=indent_curr_line
KEY_KPPLUS=curr_screen
#=cursor_column
#=cursor_lineno
#=braille_flush
#=braille_return_to_cursor
#=braille_pan_left
#=braille_pan_right
KEY_FENRIR,KEY_CTRL,KEY_1=clear_bookmark_1
KEY_FENRIR,KEY_SHIFT,KEY_1=set_bookmark_1
KEY_FENRIR,KEY_1=bookmark_1
KEY_FENRIR,KEY_CTRL,KEY_2=clear_bookmark_2
KEY_FENRIR,KEY_SHIFT,KEY_2=set_bookmark_2
KEY_FENRIR,KEY_2=bookmark_2
KEY_FENRIR,KEY_CTRL,KEY_3=clear_bookmark_3
KEY_FENRIR,KEY_SHIFT,KEY_3=set_bookmark_3
KEY_FENRIR,KEY_3=bookmark_3
KEY_FENRIR,KEY_CTRL,KEY_4=clear_bookmark_4
KEY_FENRIR,KEY_SHIFT,KEY_4=set_bookmark_4
KEY_FENRIR,KEY_4=bookmark_4
KEY_FENRIR,KEY_CTRL,KEY_5=clear_bookmark_5
KEY_FENRIR,KEY_SHIFT,KEY_5=set_bookmark_5
KEY_FENRIR,KEY_5=bookmark_5
KEY_FENRIR,KEY_CTRL,KEY_6=clear_bookmark_6
KEY_FENRIR,KEY_SHIFT,KEY_6=set_bookmark_6
KEY_FENRIR,KEY_6=bookmark_6
KEY_FENRIR,KEY_CTRL,KEY_7=clear_bookmark_7
KEY_FENRIR,KEY_SHIFT,KEY_7=set_bookmark_7
KEY_FENRIR,KEY_7=bookmark_7
KEY_FENRIR,KEY_CTRL,KEY_8=clear_bookmark_8
KEY_FENRIR,KEY_SHIFT,KEY_8=set_bookmark_8
KEY_FENRIR,KEY_8=bookmark_8
KEY_FENRIR,KEY_CTRL,KEY_9=clear_bookmark_9
KEY_FENRIR,KEY_SHIFT,KEY_9=set_bookmark_9
KEY_FENRIR,KEY_9=bookmark_9
KEY_FENRIR,KEY_CTRL,KEY_0=clear_bookmark_10
KEY_FENRIR,KEY_SHIFT,KEY_0=set_bookmark_10
KEY_FENRIR,KEY_0=bookmark_10
KEY_FENRIR,KEY_KPSLASH=set_window_application
2,KEY_FENRIR,KEY_KPSLASH=clear_window_application
#=last_incoming
KEY_FENRIR,KEY_F2=toggle_braille
KEY_FENRIR,KEY_F3=toggle_sound
KEY_FENRIR,KEY_F9=toggle_punctuation_level
KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check
KEY_FENRIR,KEY_BACKSLASH=toggle_output
KEY_FENRIR,KEY_CTRL,KEY_E=toggle_emoticons
key_FENRIR,KEY_KPENTER=toggle_auto_read
KEY_FENRIR,KEY_CTRL,KEY_T=toggle_auto_time
KEY_FENRIR,KEY_KPASTERISK=toggle_highlight_tracking
KEY_FENRIR,KEY_KPMINUS=toggle_barrier
KEY_FENRIR,KEY_Q=quit_fenrir
KEY_FENRIR,KEY_T=time
2,KEY_FENRIR,KEY_T=date
KEY_KPSLASH=toggle_auto_indent
#=toggle_has_attribute
KEY_FENRIR,KEY_S=spell_check
2,KEY_FENRIR,KEY_S=add_word_to_spell_check
KEY_FENRIR,KEY_SHIFT,KEY_S=remove_word_from_spell_check
KEY_FENRIR,KEY_BACKSPACE=forward_keypress
KEY_FENRIR,KEY_ALT,KEY_UP=inc_sound_volume
KEY_FENRIR,KEY_ALT,KEY_DOWN=dec_sound_volume
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_C=clear_clipboard
KEY_FENRIR,KEY_HOME=first_clipboard
KEY_FENRIR,KEY_END=last_clipboard
KEY_FENRIR,KEY_PAGEUP=prev_clipboard
KEY_FENRIR,KEY_PAGEDOWN=next_clipboard
KEY_FENRIR,KEY_SHIFT,KEY_C=curr_clipboard
KEY_FENRIR,KEY_CTRL,KEY_C=copy_last_echo_to_clipboard
KEY_FENRIR,KEY_F5=import_clipboard_from_file
KEY_FENRIR,KEY_F6=export_clipboard_to_file
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_SPACE=current_quick_menu_entry
KEY_FENRIR,KEY_CTRL,KEY_SPACE=current_quick_menu_value
KEY_FENRIR,KEY_RIGHT=next_quick_menu_entry
KEY_FENRIR,KEY_UP=next_quick_menu_value
KEY_FENRIR,KEY_LEFT=prev_quick_menu_entry
KEY_FENRIR,KEY_DOWN=prev_quick_menu_value
KEY_FENRIR,KEY_CTRL,KEY_S=save_settings
# linux specific
KEY_FENRIR,KEY_F7=import_clipboard_from_x
KEY_FENRIR,KEY_F8=export_clipboard_to_x
KEY_FENRIR,KEY_CTRL,KEY_UP=inc_alsa_volume
KEY_FENRIR,KEY_CTRL,KEY_DOWN=dec_alsa_volume

View File

@ -5,7 +5,7 @@
[levelDict] [levelDict]
none:===: none:===:
some:===:-$~+*-/\@# some:===:-$~+*-/\@#
most:===:.,:-_$~+*-/\@!#%^&*()[]}{<>; most:===:.,:-$~+*-/\@!#%^&*()[]}{<>;
all:===:!"#$%& \'()*+,-./:;<=>?@[\\]^_`{|}~ all:===:!"#$%& \'()*+,-./:;<=>?@[\\]^_`{|}~
[punctDict] [punctDict]

View File

@ -5,7 +5,7 @@
[levelDict] [levelDict]
none:===: none:===:
some:===:-$~+*-/\@ some:===:-$~+*-/\@
most:===:.,:-$~+*-_/\@!#%^&*()[]}{<>; most:===:.,:-$~+*-/\@!#%^&*()[]}{<>;
all:===:!"#$%& \'()*+,-./:;<=>?@[\\]^_`{|}~ all:===:!"#$%& \'()*+,-./:;<=>?@[\\]^_`{|}~
[punctDict] [punctDict]

View File

@ -4,7 +4,7 @@
# the entrys are seperated with :===: in words colon tripple equal colon ( to not collide with substitutions) # the entrys are seperated with :===: in words colon tripple equal colon ( to not collide with substitutions)
[levelDict] [levelDict]
none:===: none:===:
some:===:-$~+*-/\@_ some:===:-$~+*-/\@
most:===:.,:-$~+*-/\@!#%^&*()[]}{<>; most:===:.,:-$~+*-/\@!#%^&*()[]}{<>;
all:===:!"#$%& \'()*+,-./:;<=>?@[\\]^_`{|}~ all:===:!"#$%& \'()*+,-./:;<=>?@[\\]^_`{|}~

View File

@ -15,7 +15,7 @@ theme=default
# Sound volume controls how loud the sounds for your selected soundpack are. # Sound volume controls how loud the sounds for your selected soundpack are.
# 0 is quietest, 1.0 is loudest. # 0 is quietest, 1.0 is loudest.
volume=0.7 volume=1.0
# shell commands for generic sound driver # shell commands for generic sound driver
# the folowing variable are substituted # the folowing variable are substituted
@ -28,9 +28,6 @@ genericPlayFileCommand=play -q -v fenrirVolume fenrirSoundFile
#the following command is used to generate a frequency beep #the following command is used to generate a frequency beep
genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence
# Enable progress bar monitoring with ascending tones by default
progressMonitoring=True
[speech] [speech]
# Turn speech on or off: # Turn speech on or off:
enabled=True enabled=True
@ -95,8 +92,8 @@ fenrirMaxRate=450
driver=vcsaDriver driver=vcsaDriver
encoding=auto encoding=auto
screenUpdateDelay=0.05 screenUpdateDelay=0.05
ignoreScreen=7 suspendingScreen=
autodetectIgnoreScreen=True autodetectSuspendingScreen=True
[keyboard] [keyboard]
driver=evdevDriver driver=evdevDriver
@ -124,9 +121,7 @@ interruptOnKeyPressFilter=
doubleTapTimeout=0.2 doubleTapTimeout=0.2
[general] [general]
# Debug levels: 0=DEACTIVE, 1=ERROR, 2=WARNING, 3=INFO (most verbose) debugLevel=0
# 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 sets where the debug output should send to:
# debugMode=File writes to debugFile (Default:/tmp/fenrir-PID.log) # debugMode=File writes to debugFile (Default:/tmp/fenrir-PID.log)
# debugMode=Print just prints on the screen # debugMode=Print just prints on the screen
@ -135,11 +130,8 @@ debugFile=
punctuationProfile=default punctuationProfile=default
punctuationLevel=some punctuationLevel=some
respectPunctuationPause=True 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 newLinePause=True
numberOfClipboards=50 numberOfClipboards=10
# used path for "export_clipboard_to_file" # used path for "export_clipboard_to_file"
# $user is replaced by username # $user is replaced by username
#clipboardExportPath=/home/$user/fenrirClipboard #clipboardExportPath=/home/$user/fenrirClipboard
@ -148,8 +140,8 @@ emoticons=True
# define the current Fenrir key # define the current Fenrir key
fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT
scriptKeys=KEY_COMPOSE scriptKeys=KEY_COMPOSE
timeFormat=%%I:%%M%%P timeFormat=%H:%M:%P
dateFormat=%%A, %%B %%d, %%Y dateFormat=%A, %B %d, %Y
autoSpellCheck=True autoSpellCheck=True
spellCheckLanguage=en_US spellCheckLanguage=en_US
# path for your scripts "scriptKeys" functionality # path for your scripts "scriptKeys" functionality
@ -171,7 +163,7 @@ autoPresentIndent=False
# 1 = sound only # 1 = sound only
# 2 = speak only # 2 = speak only
autoPresentIndentMode=1 autoPresentIndentMode=1
# play a sound when attributes change # play a sound when attributes are changeing
hasAttributes=True hasAttributes=True
# shell for PTY emulatiun (empty = default shell) # shell for PTY emulatiun (empty = default shell)
shell= shell=
@ -198,7 +190,7 @@ enableSettingsRemote=True
enableCommandRemote=True enableCommandRemote=True
[barrier] [barrier]
enabled=False enabled=True
leftBarriers=│└┌─ leftBarriers=│└┌─
rightBarriers=│┘┐─ rightBarriers=│┘┐─
@ -219,32 +211,8 @@ list=
vmenuPath= vmenuPath=
quickMenu=speech#rate;speech#pitch;speech#volume quickMenu=speech#rate;speech#pitch;speech#volume
[prompt]
# 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
#
# 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 ~] #,Continue installation? [Y/n]
exactMatches=
[time] [time]
# automatic time announcement # automatic time anouncement
enabled=False enabled=False
# present time # present time
presentTime=True presentTime=True

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

@ -1,389 +1,4 @@
# Fenrir Development Guide 1. Basic
2. Commands
3. Useful API
This document provides information for developers who want to contribute to Fenrir or understand its architecture.
## Project Structure
Fenrir follows a modular, driver-based architecture:
```
src/fenrirscreenreader/
├── core/ # Core system modules
│ ├── fenrirManager.py # Main application manager
│ ├── screenManager.py # Screen handling
│ ├── inputManager.py # Input handling
│ ├── outputManager.py # Speech/sound output
│ ├── commandManager.py # Command system
│ └── settingsManager.py # Configuration management
├── commands/ # Command implementations
│ ├── commands/ # User-invoked commands
│ ├── onCursorChange/ # Cursor movement hooks
│ ├── onScreenUpdate/ # Screen update hooks
│ ├── onKeyInput/ # Key input hooks
│ └── help/ # Tutorial system
├── drivers/ # Driver implementations
│ ├── inputDriver/ # Input drivers (evdev, pty, atspi)
│ ├── screenDriver/ # Screen drivers (vcsa, pty)
│ ├── speechDriver/ # Speech drivers (speechd, generic)
│ └── soundDriver/ # Sound drivers (generic, gstreamer)
└── utils/ # Utility modules
```
## Core Architecture
### Driver System
Fenrir uses a pluggable driver architecture:
1. **Input Drivers**: Capture keyboard input
- evdevDriver: Linux evdev (recommended)
- ptyDriver: Terminal emulation
- atspiDriver: AT-SPI for desktop
2. **Screen Drivers**: Read screen content
- vcsaDriver: Linux VCSA devices
- ptyDriver: Terminal emulation
3. **Speech Drivers**: Text-to-speech output
- speechdDriver: Speech-dispatcher
- genericDriver: Command-line TTS
4. **Sound Drivers**: Audio output
- genericDriver: Sox-based
- gstreamerDriver: GStreamer
5. **Remote Drivers**: Remote control interfaces
- unixDriver: Unix socket control
- tcpDriver: TCP socket control
### Command System
Commands are Python modules that implement specific functionality:
```python
class command():
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Command description')
def run(self):
# Command implementation
pass
```
### Event Hooks
Fenrir supports various event hooks:
- **onCursorChange**: Triggered when cursor moves
- **onScreenUpdate**: Triggered on screen content changes
- **onKeyInput**: Triggered on key presses
- **onByteInput**: Triggered on byte-level input
- **onScreenChanged**: Triggered when switching screens
## Development Setup
### Requirements
- Python 3.6+
- python3-evdev
- python3-pyudev
- speech-dispatcher
- sox
### Getting Started
```bash
# Clone repository
git clone https://git.stormux.org/storm/fenrir.git
cd fenrir
# Install dependencies
sudo pip3 install -r requirements.txt
# Run from source
cd src/
sudo ./fenrir -f -d
```
### Testing
```bash
# Run in debug mode
sudo ./fenrir -f -d -p
# Debug output goes to:
# - Console (with -p flag)
# - /var/log/fenrir.log
```
## Creating Commands
### Basic Command
Create a file in `src/fenrirscreenreader/commands/commands/`:
```python
from fenrirscreenreader.core import debug
class command():
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('My custom command')
def run(self):
# Get current text
text = self.env['screen']['newContentText']
# Speak something
self.env['runtime']['outputManager'].presentText('Hello World')
# Play sound
self.env['runtime']['outputManager'].playSoundIcon('Accept')
```
### Key Bindings
Add key bindings in keyboard layout files:
`config/keyboard/desktop.conf` or `config/keyboard/laptop.conf`
```ini
[KEY_CTRL]#[KEY_ALT]#[KEY_H]=my_command
```
### Event Hooks
Create event handlers in appropriate directories:
```python
# onCursorChange/my_hook.py
class command():
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('My cursor change handler')
def run(self):
if self.env['runtime']['cursorManager'].isCursorHorizontalMove():
# Handle horizontal cursor movement
pass
```
## Creating Drivers
### Driver Template
```python
class driver():
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
# Driver-specific methods...
```
### Input Driver
Implement these methods:
- `getInputEvent()`: Return input events
- `writeEventBuffer()`: Handle output events
- `grabDevices()`: Take exclusive control
- `releaseDevices()`: Release control
### Screen Driver
Implement these methods:
- `getCurrScreen()`: Get current screen content
- `getSessionInformation()`: Get session info
### Speech Driver
Implement these methods:
- `speak()`: Speak text
- `cancel()`: Stop speech
- `setCallback()`: Set callback functions
### Remote Driver
Implement these methods:
- `initialize()`: Setup socket/connection
- `watchDog()`: Listen for incoming commands
- `shutdown()`: Clean up connections
#### Remote Driver Example
```python
class driver(remoteDriver):
def initialize(self, environment):
self.env = environment
# Start watchdog thread
self.env['runtime']['processManager'].addCustomEventThread(
self.watchDog, multiprocess=True
)
def watchDog(self, active, eventQueue):
# Listen for connections and process commands
while active.value:
# Accept connections
# Parse incoming data
# Send to event queue
eventQueue.put({
"Type": fenrirEventType.RemoteIncomming,
"Data": command_text
})
```
## Configuration
### Settings System
Settings are hierarchical:
1. Command-line options (`-o`)
2. Configuration file
3. Hard-coded defaults
### Adding Settings
1. Add default value to `core/settingsData.py`
2. Access via `self.env['runtime']['settingsManager'].getSetting(section, key)`
## Debugging
### Debug Levels
- 0: DEACTIVE
- 1: ERROR
- 2: WARNING
- 3: INFO
### Debug Output
```python
self.env['runtime']['debug'].writeDebugOut(
'Debug message',
debug.debugLevel.INFO
)
```
### Testing Commands
```bash
# Test specific functionality
sudo fenrir -f -d -o "general#debugLevel=3"
# Test with custom config
sudo fenrir -f -s /path/to/test.conf
```
## Contributing
### Code Style
- Follow PEP 8
- Use descriptive variable names
- Add docstrings for complex functions
- Handle exceptions gracefully
### Testing
- Test with different drivers
- Test keyboard layouts
- Test on different terminals
- Verify accessibility features
### Submitting Changes
1. Fork the repository
2. Create feature branch
3. Make changes with clear commit messages
4. Test thoroughly
5. Submit pull request
## API Reference
### Environment Structure
The `environment` dict contains all runtime data:
```python
environment = {
'runtime': {
'settingsManager': settingsManager,
'commandManager': commandManager,
'screenManager': screenManager,
'inputManager': inputManager,
'outputManager': outputManager,
'debug': debugManager,
# ... other managers
},
'screen': {
'newContentText': '',
'oldContentText': '',
'newCursor': {'x': 0, 'y': 0},
'oldCursor': {'x': 0, 'y': 0},
# ... screen data
},
'general': {
'prevCommand': '',
'currCommand': '',
# ... general data
}
}
```
### Common Operations
#### Speaking Text
```python
self.env['runtime']['outputManager'].presentText('Hello')
```
#### Playing Sounds
```python
self.env['runtime']['outputManager'].playSoundIcon('Accept')
```
#### Getting Settings
```python
rate = self.env['runtime']['settingsManager'].getSetting('speech', 'rate')
```
#### Cursor Information
```python
x = self.env['screen']['newCursor']['x']
y = self.env['screen']['newCursor']['y']
```
#### Screen Content
```python
text = self.env['screen']['newContentText']
lines = text.split('\n')
current_line = lines[self.env['screen']['newCursor']['y']]
```
## Maintenance
### Release Process
1. Update version in `fenrirVersion.py`
2. Update changelog
3. Test on multiple systems
4. Tag release
5. Update documentation
### Compatibility
- Maintain Python 3.6+ compatibility
- Test on multiple Linux distributions
- Ensure driver compatibility
- Check dependencies
## Resources
- **Repository**: https://git.stormux.org/storm/fenrir
- **Wiki**: https://git.stormux.org/storm/fenrir/wiki
- **Issues**: Use repository issue tracker
- **Community**: IRC irc.stormux.org #stormux
- **Email**: stormux+subscribe@groups.io

File diff suppressed because it is too large Load Diff

View File

@ -1202,47 +1202,6 @@ link:#Settings[Settings]
=== Commandline Arguments === Commandline Arguments
Fenrir supports several command-line options:
....
fenrir [OPTIONS]
....
==== Available Options
`+-h, --help+`::
Show help message and exit.
`+-v, --version+`::
Show version information and exit.
`+-f, --foreground+`::
Run Fenrir in the foreground instead of as a daemon.
`+-s, --setting SETTING-FILE+`::
Path to a custom settings file.
`+-o, --options SECTION#SETTING=VALUE;..+`::
Override settings file options (see below for details).
`+-d, --debug+`::
Enable debug mode. Debug information will be logged.
`+-p, --print+`::
Print debug messages to screen in addition to logging them.
`+-e, --emulated-pty+`::
Use PTY emulation with escape sequences for input. This enables usage in desktop/X11/Wayland environments and terminal emulators.
`+-E, --emulated-evdev+`::
Use PTY emulation with evdev for input (single instance mode).
`+-F, --force-all-screens+`::
Force Fenrir to respond on all screens, ignoring the ignoreScreen setting. This temporarily overrides screen filtering for the current session.
`+-i, -I, --ignore-screen <SCREEN>+`::
Ignore specific screen(s). Can be used multiple times to ignore multiple screens. This is equivalent to setting ignoreScreen in the configuration file and will be combined with any existing ignore settings.
==== Set settings options ==== Set settings options
You can specify options that overwrite the setting.conf. This is done You can specify options that overwrite the setting.conf. This is done
@ -1265,154 +1224,9 @@ or change the debug level to verbose
fenrir -o "general#debugLevel=3" fenrir -o "general#debugLevel=3"
.... ....
Example using force all screens option:
....
fenrir -F
....
You can find the available sections and variables here #Settings See You can find the available sections and variables here #Settings See
Syntax link:#settings.conf syntax[#settings.conf syntax] Syntax link:#settings.conf syntax[#settings.conf syntax]
=== Remote Control
Fenrir includes a powerful remote control system that allows external applications and scripts to control Fenrir through Unix sockets or TCP connections.
==== Configuration
Enable remote control in settings.conf:
....
[remote]
enable=True
driver=unixDriver
enableSettingsRemote=True
enableCommandRemote=True
....
==== Using socat with Unix Sockets
The `+socat+` command provides the easiest way to send commands to Fenrir:
===== Basic Speech Control
....
# Interrupt current speech
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Speak custom text
echo "command say Hello, this is a test message" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Temporarily disable speech (until next keystroke)
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
....
===== Settings Control
....
# Enable highlight tracking mode
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Change speech rate
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Change punctuation level (none/some/most/all)
echo "setting set general#punctuationLevel=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Voice and TTS control
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Multiple settings at once
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuationLevel=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Reset all settings to defaults
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
....
===== Clipboard Operations
....
# Place text into clipboard
echo "command clipboard This text will be copied to clipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
# Export clipboard to file
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
....
===== Application Control
....
# Quit Fenrir
echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
....
==== Command Reference
===== Available Commands
*Speech Commands:*
* `+command say <text>+` - Speak the specified text
* `+command interrupt+` - Stop current speech
* `+command tempdisablespeech+` - Disable speech until next key press
*Clipboard Commands:*
* `+command clipboard <text>+` - Add text to clipboard
* `+command exportclipboard+` - Export clipboard to file
*Window Commands:*
* `+command window <x1> <y1> <x2> <y2>+` - Define window area
* `+command resetwindow+` - Reset to full screen
*VMenu Commands:*
* `+command vmenu <menu_path>+` - Set virtual menu context
* `+command resetvmenu+` - Reset virtual menu
*Application Commands:*
* `+command quitapplication+` - Quit Fenrir
===== Available Settings
*Settings Commands:*
* `+setting set <section>#<key>=<value>+` - Set configuration value
* `+setting reset+` - Reset all settings to defaults
* `+setting save [path]+` - Save current settings
*Key Settings You Can Control:*
*Speech Settings:*
* `+speech#enabled=True/False+` - Enable/disable speech
* `+speech#rate=0.1-1.0+` - Speech rate (speed)
* `+speech#pitch=0.1-1.0+` - Speech pitch (tone)
* `+speech#volume=0.1-1.0+` - Speech volume
* `+speech#voice=voice_name+` - Voice selection (e.g., "en-us+f3")
* `+speech#module=module_name+` - TTS module (e.g., "espeak-ng")
*General Settings:*
* `+general#punctuationLevel=none/some/most/all+` - Punctuation verbosity
* `+general#autoSpellCheck=True/False+` - Automatic spell checking
* `+general#emoticons=True/False+` - Enable emoticon replacement
*Sound Settings:*
* `+sound#enabled=True/False+` - Enable/disable sound
* `+sound#volume=0.1-1.0+` - Sound volume
*Focus Settings:*
* `+focus#cursor=True/False+` - Follow text cursor
* `+focus#highlight=True/False+` - Follow text highlighting
*Keyboard Settings:*
* `+keyboard#charEchoMode=0-2+` - Character echo (0=none, 1=always, 2=capslock only)
* `+keyboard#wordEcho=True/False+` - Echo complete words
*Screen Settings:*
* `+screen#ignoreScreen=1,2,3+` - TTY screens to ignore
==== settings.conf syntax ==== settings.conf syntax
the syntax of the link:#Settings[settings.conf] is quite simple and the syntax of the link:#Settings[settings.conf] is quite simple and

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,12 @@
#!/usr/bin/env bash #!/bin/bash
#Basic install script for Fenrir. #Basic install script for Fenrir.
read -rp "This will install Fenrir. Press ctrl+C to cancel, or enter to continue." read -p "This will install Fenrir. Press ctrl+C to cancel, or enter to continue." continue
# Fenrir main application # Fenrir main application
install -m755 -d /opt/fenrirscreenreader install -m755 -d /opt/fenrirscreenreader
cp -af src/* /opt/fenrirscreenreader cp -af src/* /opt/fenrirscreenreader
ln -fs /opt/fenrirscreenreader/fenrir-daemon /usr/bin/fenrir-daemon
ln -fs /opt/fenrirscreenreader/fenrir /usr/bin/fenrir ln -fs /opt/fenrirscreenreader/fenrir /usr/bin/fenrir
# tools # tools
install -m755 -d /usr/share/fenrirscreenreader/tools install -m755 -d /usr/share/fenrirscreenreader/tools
@ -32,9 +33,8 @@ cp -af config/sound/template /usr/share/sounds/fenrirscreenreader/template
# config # config
if [ -f "/etc/fenrirscreenreader/settings/settings.conf" ]; then if [ -f "/etc/fenrirscreenreader/settings/settings.conf" ]; then
echo "Do you want to overwrite your current global settings? (y/n)" echo "Do you want to overwrite your current global settings? (y/n)"
read -r yn read yn
yn="${yn:0:1}" if [ $yn = "Y" -o $yn = "y" ]; then
if [[ "${yn^}" == "Y" ]]; then
mv /etc/fenrirscreenreader/settings/settings.conf /etc/fenrirscreenreader/settings/settings.conf.bak mv /etc/fenrirscreenreader/settings/settings.conf /etc/fenrirscreenreader/settings/settings.conf.bak
echo "Your old settings.conf has been backed up to settings.conf.bak." echo "Your old settings.conf has been backed up to settings.conf.bak."
install -m644 -D "config/settings/settings.conf" /etc/fenrirscreenreader/settings/settings.conf install -m644 -D "config/settings/settings.conf" /etc/fenrirscreenreader/settings/settings.conf

42
pyproject.toml Normal file
View File

@ -0,0 +1,42 @@
[build-system]
requires = ["setuptools >= 61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "fenrir-screenreader"
version="2025.01.28"
authors = [
{name = "Hunter Jozwiak", email = "hunter.t.joz@gmail.com"},
{name="Storm Dragon", email="storm_dragon@stormux.org"},
{name="Jeremiah Ticket", email="seashellpromises@gmail.com"},
{name="Chrys", email="chrys@linux-a11y.org"},
]
maintainers = [
{name = "Hunter Jozwiak", email = "hunter.t.joz@gmail.com"},
{name = "Storm dragon", email = "storm_dragon@stormux.org"}]
keywords=['screenreader', 'a11y', 'accessibility', 'terminal', 'TTY', 'console']
classifiers=[
"Programming Language :: Python",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Development Status :: 5 - Production/Stable",
"Topic :: Multimedia :: Sound/Audio :: Speech",
"Environment :: Console",
]
description = "A TTY screenreader for Linux."
readme = "README.md"
requires-python = ">=3.6"
dependencies = [
"daemonize>=2.5.0",
"dbus-python>=1.2.18",
"evdev>=1.7.1",
"pexpect>=4.9.0",
"pyte>=0.8.1",
"pyudev>=0.23.2",
]
[project.scripts]
fenrir = "fenrirscreenreader:cli.main"
[dependency-groups]
dev = [
"ruff>=0.0.17",
]

10
pyproject.toml~ Normal file
View File

@ -0,0 +1,10 @@
[project]
name = "fenrir-screenreader"
author="Storm Dragon, Jeremiah, Chrys and others"
version = "2024.12.20"
description = "A TTY screenreader for Linux."
readme = "README.md"
requires-python = ">=3.6"
dependencies = [
"evdev>=1.7.1",
]

View File

@ -1,10 +0,0 @@
daemonize
dbus-python
evdev
pexpect
pyenchant
pyperclip
pyte
pyudev
pyxdg
setproctitle

132
setup.py
View File

@ -1,132 +0,0 @@
#!/usr/bin/env python3
import os, glob, sys
import os.path
from shutil import copyfile
from setuptools import find_namespace_packages
from setuptools import setup
# handle flags for package manager like aurman and pacaur.
# Allow both environment variable and command line flag
forceSettingsFlag = (
"--force-settings" in sys.argv or
os.environ.get('FENRIR_FORCE_SETTINGS') == '1'
)
if "--force-settings" in sys.argv:
sys.argv.remove("--force-settings")
dataFiles = []
# Handle locale files
localeFiles = glob.glob('locale/*/LC_MESSAGES/*.mo')
for localeFile in localeFiles:
lang = localeFile.split(os.sep)[1]
destDir = f'/usr/share/locale/{lang}/LC_MESSAGES'
dataFiles.append((destDir, [localeFile]))
# Handle other configuration files
directories = glob.glob('config/*')
for directory in directories:
files = glob.glob(directory+'/*')
destDir = ''
if 'config/punctuation' in directory :
destDir = '/etc/fenrirscreenreader/punctuation'
elif 'config/keyboard' in directory:
destDir = '/etc/fenrirscreenreader/keyboard'
elif 'config/settings' in directory:
destDir = '/etc/fenrirscreenreader/settings'
if not forceSettingsFlag:
try:
files = [f for f in files if not f.endswith('settings.conf')]
except Exception as e:
pass
elif 'config/scripts' in directory:
destDir = '/usr/share/fenrirscreenreader/scripts'
if destDir != '':
dataFiles.append((destDir, files))
files = glob.glob('config/sound/default/*')
destDir = '/usr/share/sounds/fenrirscreenreader/default'
dataFiles.append((destDir, files))
files = glob.glob('config/sound//template/*')
destDir = '/usr/share/sounds/fenrirscreenreader/template'
dataFiles.append((destDir, files))
files = glob.glob('tools/*')
dataFiles.append(('/usr/share/fenrirscreenreader/tools', files))
dataFiles.append(('/usr/share/man/man1', ['docs/fenrir.1']))
def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
setup(
# Application name:
name="fenrir-screenreader",
# description
description="A TTY Screen Reader for Linux.",
long_description=read('README.md'),
long_description_content_type="text/markdown",
keywords=['screenreader', 'a11y', 'accessibility', 'terminal', 'TTY', 'console'],
license="License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
url="https://git.stormux.org/storm/fenrir/",
classifiers=[
"Programming Language :: Python",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Development Status :: 5 - Production/Stable",
"Topic :: Multimedia :: Sound/Audio :: Speech",
"Environment :: Console",
],
# Application author details:
author="Storm Dragon, Jeremiah, Chrys and others",
author_email="storm_dragon@stormux.org",
# Packages
package_dir={'': 'src'},
packages=find_namespace_packages(
where='src',
include=['fenrirscreenreader*']
),
scripts=['src/fenrir'],
# Include additional files into the package
include_package_data=True,
zip_safe=False,
data_files=dataFiles,
# Dependent packages (distributions)
python_requires='>=3.6',
install_requires=[
"evdev>=1.1.2",
"daemonize>=2.5.0",
"dbus-python>=1.2.8",
"pyperclip",
"pyudev>=0.21.0",
"setuptools",
"setproctitle",
"pexpect",
"pyte>=0.7.0",
],
)
if not forceSettingsFlag:
print('')
# create settings file from example if not exist
if not os.path.isfile('/etc/fenrirscreenreader/settings/settings.conf'):
try:
copyfile('config/fenrirscreenreader/settings/settings.conf', '/etc/fenrirscreenreader/settings/settings.conf')
print('create settings file in /etc/fenrirscreenreader/settings/settings.conf')
except OSError as e:
print(f"Could not copy settings file to destination: {e}")
else:
print('settings.conf file found. It is not overwritten automatical')
print('')
print('To have Fenrir start at boot:')
print('sudo systemctl enable fenrir')
print('Pulseaudio users may want to run:')
print('/usr/share/fenrirscreenreader/tools/configure_pulse.sh')
print('once as their user account and once as root to configure Pulseaudio.')
print('Please install the following packages manually:')
print('- Speech-dispatcher: for the default speech driver')
print('- Espeak: as basic TTS engine')
print('- sox: is a player for the generic sound driver')

67
src/fenrir → src/fenrirscreenreader/cli.py Executable file → Normal file
View File

@ -1,25 +1,21 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributors.
"""Module for managing the command line interface of Fenrir."""
import argparse
import inspect
import os import os
import sys import sys
import inspect
import argparse
from daemonize import Daemonize from daemonize import Daemonize
from fenrirscreenreader import fenrirVersion
from fenrirscreenreader.core import fenrirManager
# Get the fenrir installation path # Get the fenrir installation path
fenrirPath = os.path.dirname(os.path.realpath( fenrirPath = os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe()))))
os.path.abspath(inspect.getfile(inspect.currentframe())))) if not fenrirPath in sys.path:
if fenrirPath not in sys.path:
sys.path.append(fenrirPath) sys.path.append(fenrirPath)
from .core import fenrirManager
from . import fenrirVersion
def create_argument_parser(): def create_argument_parser():
"""Create and return the argument parser for Fenrir""" """Create and return the argument parser for Fenrir"""
@ -30,7 +26,7 @@ def create_argument_parser():
argumentParser.add_argument( argumentParser.add_argument(
'-v', '--version', '-v', '--version',
action='version', action='version',
version=f'Fenrir screen reader version {fenrirVersion.version}-{fenrirVersion.code_name}', version=f'Fenrir screen reader version {fenrirVersion.version}-{fenrirVersion.codeName}',
help='Show version information and exit' help='Show version information and exit'
) )
argumentParser.add_argument( argumentParser.add_argument(
@ -70,65 +66,31 @@ def create_argument_parser():
action='store_true', action='store_true',
help='Use PTY emulation with evdev for input (single instance)' help='Use PTY emulation with evdev for input (single instance)'
) )
argumentParser.add_argument(
'-F',
'--force-all-screens',
action='store_true',
help='Force Fenrir to respond on all screens, ignoring ignoreScreen setting')
argumentParser.add_argument(
'-i', '-I', '--ignore-screen',
metavar='SCREEN',
action='append',
help='Ignore specific screen(s). Can be used multiple times. Same as ignoreScreen setting.'
)
return argumentParser return argumentParser
def validate_arguments(cliArgs): def validate_arguments(cliArgs):
"""Validate command line arguments""" """Validate command line arguments"""
if cliArgs.options: if cliArgs.options:
for option in cliArgs.options.split(';'): for option in cliArgs.options.split(';'):
if option and ('#' not in option or '=' not in option): if option and ('#' not in option or '=' not in option):
return False, f"Invalid option format: {option}\nExpected format: SECTION#SETTING=VALUE" return False, f"Invalid option format: {option}\nExpected format: SECTION#SETTING=VALUE"
if cliArgs.emulated_pty and cliArgs.emulated_evdev: if cliArgs.emulated_pty and cliArgs.emulated_evdev:
return False, "Cannot use both --emulated-pty and --emulated-evdev simultaneously" return False, "Cannot use both --emulated-pty and --emulated-evdev simultaneously"
return True, None return True, None
def run_fenrir(): def run_fenrir():
"""Main function that runs Fenrir""" """Main function that runs Fenrir"""
fenrirApp = None fenrirApp = fenrirManager.fenrirManager(cliArgs)
try: fenrirApp.proceed()
fenrirApp = fenrirManager.FenrirManager(cliArgs) del fenrirApp
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(): def main():
global cliArgs global cliArgs
argumentParser = create_argument_parser() argumentParser = create_argument_parser()
cliArgs = argumentParser.parse_args() cliArgs = argumentParser.parse_args()
# Validate arguments # Validate arguments
isValid, errorMsg = validate_arguments(cliArgs) isValid, errorMsg = validate_arguments(cliArgs)
if not isValid: if not isValid:
@ -149,6 +111,5 @@ def main():
) )
daemonProcess.start() daemonProcess.start()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,20 +2,47 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(1, "read") 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

View File

@ -2,20 +2,47 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(10, "read") 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

View File

@ -2,20 +2,47 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(2, "read") 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

View File

@ -2,20 +2,47 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(3, "read") 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

View File

@ -2,20 +2,47 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(4, "read") 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

View File

@ -2,20 +2,47 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(5, "read") 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

View File

@ -2,20 +2,47 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(6, "read") 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

View File

@ -2,20 +2,47 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(7, "read") 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

View File

@ -2,20 +2,47 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(8, "read") 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

View File

@ -2,20 +2,47 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(9, "read") 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

View File

@ -1,211 +0,0 @@
#!/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,20 +2,26 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(1, "clear") 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

View File

@ -2,20 +2,26 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(10, "clear") 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

View File

@ -2,20 +2,26 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(2, "clear") 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

View File

@ -2,20 +2,26 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(3, "clear") 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

View File

@ -2,20 +2,26 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(4, "clear") 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

View File

@ -2,20 +2,26 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(5, "clear") 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

View File

@ -2,20 +2,26 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(6, "clear") 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

View File

@ -2,20 +2,26 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(7, "clear") 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

View File

@ -2,20 +2,26 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(8, "clear") 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

View File

@ -2,20 +2,26 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os
from fenrirscreenreader.core.i18n import _ class command():
_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): def __init__(self):
super().__init__(9, "clear") 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,105 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
import os
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 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
settings_root = "/etc/fenrirscreenreader/"
if not os.path.exists(settings_root):
# Fallback to source directory
import fenrirscreenreader
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"]
else:
layouts.sort()
return layouts
def run(self):
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", ""
)
# Get available layouts
available_layouts = self.get_available_layouts()
# Find next layout in cycle
try:
current_index = available_layouts.index(current_layout)
next_index = (current_index + 1) % len(available_layouts)
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"].set_setting(
"keyboard", "keyboardLayout", next_layout
)
# Reload shortcuts with new layout
try:
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"]["DebugManager"].write_debug_out(
"Error reloading shortcuts: " + str(e), debug.DebugLevel.ERROR
)
self.env["runtime"]["OutputManager"].present_text(
_("Error switching keyboard layout"), interrupt=True
)
def set_callback(self, callback):
pass

View File

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

View File

@ -2,20 +2,38 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util initialized = False
import os try:
import alsaaudio
initialized = True
except:
pass
from fenrirscreenreader.core.i18n import _ from fenrirscreenreader.core import debug
_base_path = os.path.join(os.path.dirname(__file__), "adjustment_base.py") class command():
_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): def __init__(self):
super().__init__("alsa", "volume", "dec") 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

View File

@ -2,20 +2,32 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os import math
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): def __init__(self):
super().__init__("sound", "volume", "dec") 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

View File

@ -2,20 +2,28 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os import math
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): def __init__(self):
super().__init__("speech", "pitch", "dec") 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

View File

@ -2,20 +2,29 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os import math
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): def __init__(self):
super().__init__("speech", "rate", "dec") 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

View File

@ -2,20 +2,30 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os import math
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): def __init__(self):
super().__init__("speech", "volume", "dec") 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

View File

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

View File

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

View File

@ -2,96 +2,76 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.core import debug
import subprocess, os
from subprocess import Popen, PIPE
import _thread import _thread
import importlib
import os
import pyperclip class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self): def __init__(self):
pass pass
def initialize(self, environment):
def initialize(self, environment, script_path=""):
self.env = environment self.env = environment
self.script_path = script_path
def shutdown(self): def shutdown(self):
pass pass
def getDescription(self):
def get_description(self): return _('Export current fenrir clipboard to X or GUI clipboard')
return _("Export current fenrir clipboard to X or GUI clipboard") def run(self):
_thread.start_new_thread(self._threadRun , ())
def run(self): def _threadRun(self):
_thread.start_new_thread(self._thread_run, ())
def _thread_run(self):
try: try:
# Check if clipboard is empty if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'):
if self.env["runtime"]["MemoryManager"].is_index_list_empty( self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True)
"clipboardHistory" return
):
self.env["runtime"]["OutputManager"].present_text( clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory')
_("clipboard empty"), interrupt=True user = self.env['general']['currUser']
# First try to find xclip in common locations
xclip_paths = [
'/usr/bin/xclip',
'/bin/xclip',
'/usr/local/bin/xclip'
]
xclip_path = None
for path in xclip_paths:
if os.path.isfile(path) and os.access(path, os.X_OK):
xclip_path = path
break
if not xclip_path:
self.env['runtime']['outputManager'].presentText(
'xclip not found in common locations',
interrupt=True
) )
return return
# Get current clipboard content for display in range(10):
clipboard = self.env["runtime"][ p = Popen(
"MemoryManager" ['su', user, '-p', '-c', f"{xclip_path} -d :{display} -selection clipboard"],
].get_index_list_element("clipboardHistory") stdin=PIPE, stdout=PIPE, stderr=PIPE, preexec_fn=os.setpgrp
)
# Remember original display environment variable if it exists stdout, stderr = p.communicate(input=clipboard.encode('utf-8'))
original_display = os.environ.get("DISPLAY", "")
success = False self.env['runtime']['outputManager'].interruptOutput()
# Try different display options stderr = stderr.decode('utf-8')
for i in range(10): stdout = stdout.decode('utf-8')
display = f":{i}"
try: if stderr == '':
# Set display environment variable
os.environ["DISPLAY"] = display
# Attempt to set clipboard content
# Weird workaround for some distros
importlib.reload(pyperclip)
pyperclip.copy(clipboard)
# If we get here without exception, we found a working
# display
success = True
break break
except Exception:
# Failed for this display, try next one if stderr != '':
continue self.env['runtime']['outputManager'].presentText(stderr, soundIcon='', interrupt=False)
# Restore original display setting
if original_display:
os.environ["DISPLAY"] = original_display
else: else:
os.environ.pop("DISPLAY", None) self.env['runtime']['outputManager'].presentText('exported to the X session.', interrupt=True)
# Notify the user of the result
if success:
self.env["runtime"]["OutputManager"].present_text(
_("exported to the X session."), interrupt=True
)
else:
self.env["runtime"]["OutputManager"].present_text(
_(
"failed to export to X clipboard. No available display "
"found."
),
interrupt=True,
)
except Exception as e: except Exception as e:
self.env["runtime"]["OutputManager"].present_text( self.env['runtime']['outputManager'].presentText(str(e), soundIcon='', interrupt=False)
str(e), sound_icon="", interrupt=False
)
def set_callback(self, callback):
def setCallback(self, callback):
pass pass

View File

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

View File

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

View File

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

View File

@ -2,86 +2,53 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.core import debug
import subprocess, os
from subprocess import Popen, PIPE
import _thread import _thread
import importlib class command():
import os
import pyperclip
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self): def __init__(self):
pass pass
def initialize(self, environment, scriptPath=''):
def initialize(self, environment, script_path=""):
self.env = environment self.env = environment
self.script_path = script_path self.scriptPath = scriptPath
def shutdown(self): def shutdown(self):
pass pass
def getDescription(self):
def get_description(self):
return _("imports the graphical clipboard to Fenrir's clipboard") return _("imports the graphical clipboard to Fenrir's clipboard")
def run(self):
def run(self): _thread.start_new_thread(self._threadRun , ())
_thread.start_new_thread(self._thread_run, ()) def _threadRun(self):
def _thread_run(self):
try: try:
# Remember original display environment variable if it exists # Find xclip path
original_display = os.environ.get("DISPLAY", "") xclip_paths = ['/usr/bin/xclip', '/bin/xclip', '/usr/local/bin/xclip']
clipboard_content = None xclip_path = None
for path in xclip_paths:
# Try different display options if os.path.isfile(path) and os.access(path, os.X_OK):
for i in range(10): xclip_path = path
display = f":{i}" break
try: if not xclip_path:
# Set display environment variable self.env['runtime']['outputManager'].presentText('xclip not found in common locations', interrupt=True)
os.environ["DISPLAY"] = display return
# Attempt to get clipboard content xClipboard = ''
# Weird workaround for some distros for display in range(10):
importlib.reload(pyperclip) p = Popen('su ' + self.env['general']['currUser'] + ' -p -c "' + xclip_path + ' -d :' + str(display) + ' -o"', stdout=PIPE, stderr=PIPE, shell=True)
clipboard_content = pyperclip.paste() stdout, stderr = p.communicate()
# If we get here without exception, we found a working self.env['runtime']['outputManager'].interruptOutput()
# display stderr = stderr.decode('utf-8')
if clipboard_content: xClipboard = stdout.decode('utf-8')
break if (stderr == ''):
except Exception: break
# Failed for this display, try next one if stderr != '':
continue self.env['runtime']['outputManager'].presentText(stderr , soundIcon='', interrupt=False)
# Restore original display setting
if original_display:
os.environ["DISPLAY"] = original_display
else: else:
os.environ.pop("DISPLAY", None) self.env['runtime']['memoryManager'].addValueToFirstIndex('clipboardHistory', xClipboard)
self.env['runtime']['outputManager'].presentText('Import to Clipboard', soundIcon='CopyToClipboard', interrupt=True)
# Process the clipboard content if we found any self.env['runtime']['outputManager'].presentText(xClipboard, 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"].present_text(
"No text found in clipboard or no accessible display",
interrupt=True,
)
except Exception as e: except Exception as e:
self.env["runtime"]["OutputManager"].present_text( self.env['runtime']['outputManager'].presentText(e , soundIcon='', interrupt=False)
str(e), sound_icon="", interrupt=False
) def setCallback(self, callback):
def set_callback(self, callback):
pass pass

View File

@ -2,20 +2,38 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util initialized = False
import os try:
import alsaaudio
initialized = True
except:
pass
from fenrirscreenreader.core.i18n import _ from fenrirscreenreader.core import debug
_base_path = os.path.join(os.path.dirname(__file__), "adjustment_base.py") class command():
_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): def __init__(self):
super().__init__("alsa", "volume", "inc") 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

View File

@ -2,20 +2,31 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os import math
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): def __init__(self):
super().__init__("sound", "volume", "inc") 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

View File

@ -2,20 +2,29 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os import math
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): def __init__(self):
super().__init__("speech", "pitch", "inc") 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

View File

@ -2,20 +2,29 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os import math
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): def __init__(self):
super().__init__("speech", "rate", "inc") 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

View File

@ -2,20 +2,29 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
import importlib.util from fenrirscreenreader.core import debug
import os import math
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): def __init__(self):
super().__init__("speech", "volume", "inc") 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

View File

@ -2,49 +2,35 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.core.i18n import _ from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import line_utils from fenrirscreenreader.utils import line_utils
class command():
class command:
def __init__(self): def __init__(self):
pass pass
def initialize(self, environment): def initialize(self, environment):
self.env = environment self.env = environment
def shutdown(self): def shutdown(self):
pass pass
def getDescription(self):
def get_description(self): return _('Presents the indentation level for the current line')
return _("Presents the indentation level for the current line")
def run(self): def run(self):
# Prefer review cursor over text cursor # Prefer review cursor over text cursor
if self.env["screen"]["newCursorReview"]: if self.env['screen']['newCursorReview']:
cursor_pos = self.env["screen"]["newCursorReview"].copy() cursorPos = self.env['screen']['newCursorReview'].copy()
else: else:
cursor_pos = self.env["screen"]["new_cursor"].copy() cursorPos = self.env['screen']['newCursor'].copy()
x, y, curr_line = line_utils.get_current_line( x, y, currLine = \
cursor_pos["x"], line_utils.getCurrentLine(cursorPos['x'], cursorPos['y'], self.env['screen']['newContentText'])
cursor_pos["y"],
self.env["screen"]["new_content_text"], 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)
if curr_line.isspace(): def setCallback(self, callback):
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 pass

View File

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

View File

@ -0,0 +1,23 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.core import debug
class command():
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Presents the text which was last received')
def run(self):
self.env['runtime']['outputManager'].presentText(self.env['screen']['newDelta'], interrupt=True)
def setCallback(self, callback):
pass

View File

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

View File

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

View File

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

View File

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

View File

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

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