129 lines
4.6 KiB
Markdown
129 lines
4.6 KiB
Markdown
## Development Philosophy
|
|
|
|
**Clean code over backward compatibility.** Breaking changes are acceptable in major versions.
|
|
|
|
- PEP8 compliance (snake_case for all variables/functions/settings)
|
|
- Remove deprecated code completely - no compatibility hacks
|
|
- Trust users to update configs when upgrading
|
|
|
|
**Exception**: Never break core accessibility (speech output, basic navigation).
|
|
|
|
## Core Architecture
|
|
|
|
### Drivers
|
|
- **Screen**: `vcsaDriver` (TTY), `ptyDriver` (terminal emulation)
|
|
- **Input**: `evdevDriver` (evdev), `x11Driver` (X11 terminal mode)
|
|
- **Speech**: `speechdDriver` (speech-dispatcher), `genericDriver` (subprocess)
|
|
- **Sound**: `gstreamerDriver` (GStreamer), `genericDriver` (Sox subprocess)
|
|
- **Remote**: `unixDriver` (Unix sockets), `tcpDriver`
|
|
|
|
### Command System
|
|
Commands in trigger folders execute automatically:
|
|
- `onKeyInput/`, `onCursorChange/`, `onScreenUpdate/`, `onScreenChanged/`, `onHeartBeat/`
|
|
- Numeric prefixes control priority (lower = higher priority): `15000-char_echo.py`
|
|
- Manual commands in `commands/commands/`
|
|
|
|
### Core Managers (in `src/fenrirscreenreader/core/`)
|
|
`fenrirManager.py`, `commandManager.py`, `eventManager.py`, `screenManager.py`, `inputManager.py`, `outputManager.py`
|
|
|
|
### Configuration
|
|
- Main: `config/settings/settings.conf`
|
|
- Keyboards: `config/keyboard/` (desktop.conf, laptop.conf)
|
|
- Sounds: `config/sound/`
|
|
- Punctuation: `config/punctuation/`
|
|
|
|
## 🚨 CRITICAL: Files to NEVER Modify
|
|
|
|
**These are timing-critical - only fix critical bugs, never refactor:**
|
|
- `evdevDriver.py` - Input event processing
|
|
- `vcsaDriver.py` - Screen monitoring
|
|
|
|
Symptoms of breakage: echo changes, input lag, missing screen updates, sync issues.
|
|
|
|
## Development Commands
|
|
|
|
```bash
|
|
# Run from source (requires root)
|
|
cd src/ && sudo ./fenrir -f -d # foreground with debug
|
|
|
|
# Validation before commit
|
|
python3 tools/validate_syntax.py --fix
|
|
python3 tools/validate_release.py --quick
|
|
|
|
# Tests
|
|
pytest tests/
|
|
pytest tests/ --cov=src/fenrirscreenreader --cov-report=html
|
|
```
|
|
|
|
**Note**: Standard TTY Fenrir blocks - only one instance at a time. `fenrir -x`
|
|
can run multiple foreground X terminal instances. Ask user to run tests that
|
|
need real Fenrir instances or root access.
|
|
|
|
## Creating Commands
|
|
|
|
Use `commands/command_template.py` as base. Required methods:
|
|
- `initialize(self, environment)`, `shutdown()`, `run()`, `get_description()`
|
|
|
|
### Import Pattern (Required)
|
|
Fenrir's command loader doesn't support relative imports:
|
|
```python
|
|
import os, importlib.util
|
|
_base_path = os.path.join(os.path.dirname(__file__), 'base_file.py')
|
|
_spec = importlib.util.spec_from_file_location("base_module", _base_path)
|
|
_module = importlib.util.module_from_spec(_spec)
|
|
_spec.loader.exec_module(_module)
|
|
BaseClass = _module.BaseClass
|
|
```
|
|
|
|
### Consolidated Base Classes
|
|
- **Bookmarks**: `bookmark_base.py` - `BookmarkCommand(id, 'read'|'set'|'clear')`
|
|
- **Adjustments**: `adjustment_base.py` - `AdjustmentCommand('speech'|'sound', 'rate'|'pitch'|'volume', 'inc'|'dec')`
|
|
- **VMenu Search**: `vmenu_search_base.py` - `VMenuSearchCommand('a'-'z')`
|
|
|
|
## VMenu System
|
|
|
|
Application-specific menus in `vmenu-profiles/KEY/{app}/`:
|
|
- Directories = submenus, `.py` files = actions
|
|
- Activate: `Fenrir+F10`, navigate with arrows, Enter to execute
|
|
|
|
## Remote Control
|
|
|
|
Unix socket: `/tmp/fenrirscreenreader-deamon.sock`
|
|
TCP: localhost:22447
|
|
|
|
```bash
|
|
echo "command say Hello" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
|
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
|
echo "setting set speech#rate=0.8" | nc localhost 22447
|
|
```
|
|
|
|
In `fenrir -x`, each instance has a private socket:
|
|
`/tmp/fenrirscreenreader-<pid>.sock`. One instance may also own the standard
|
|
socket. Use `ls`/`list` on the standard socket to discover registered instances
|
|
and their socket paths. Untargeted remote commands use a short cross-process
|
|
claim lock so only one instance handles the same broadcast command; direct
|
|
commands to a private instance socket still run on that instance.
|
|
|
|
Disable in untrusted environments: `[remote] enable=False`
|
|
|
|
## Key Implementation Details
|
|
|
|
- Commands via `command_mod.command()` instantiation
|
|
- Bookmark structure: `env['commandBuffer']['bookMarks'][ID][app]['1'/'2']`
|
|
- VMenu search: `env['runtime']['vmenuManager'].searchEntry(char)`
|
|
|
|
## Recent Fixes (Reference)
|
|
|
|
- Enhanced application detection for screen/tmux sessions
|
|
- Table navigation consistency (sound feedback)
|
|
- Blank line detection in 22 command files
|
|
- Character/space review during navigation
|
|
|
|
## Safe vs Risky Changes
|
|
|
|
**Safe**: Commands, VMenu profiles, config handling, sound/speech drivers, docs
|
|
|
|
**Risky (extra testing)**: Core managers, event processing
|
|
|
|
**Avoid**: evdevDriver, vcsaDriver, timing-critical code
|