Updated documentation. Attempted to track down a bug that causes disable speech sound to play with no interaction.?
This commit is contained in:
@ -1,4 +1,389 @@
|
||||
1. Basic
|
||||
2. Commands
|
||||
3. Useful API
|
||||
# Fenrir Development Guide
|
||||
|
||||
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
|
3259
docs/fenrir.1
3259
docs/fenrir.1
File diff suppressed because it is too large
Load Diff
183
docs/fenrir.adoc
183
docs/fenrir.adoc
@ -1202,6 +1202,44 @@ link:#Settings[Settings]
|
||||
|
||||
=== 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.
|
||||
|
||||
==== Set settings options
|
||||
|
||||
You can specify options that overwrite the setting.conf. This is done
|
||||
@ -1224,9 +1262,154 @@ or change the debug level to verbose
|
||||
fenrir -o "general#debugLevel=3"
|
||||
....
|
||||
|
||||
Example using force all screens option:
|
||||
|
||||
....
|
||||
fenrir -F
|
||||
....
|
||||
|
||||
You can find the available sections and variables here #Settings See
|
||||
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
|
||||
|
||||
the syntax of the link:#Settings[settings.conf] is quite simple and
|
||||
|
1891
docs/user.md
1891
docs/user.md
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user