Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 900a027643 | |||
| 0e50175463 | |||
| 7283f04778 | |||
| 8d3495f74f | |||
| a6cd47dafc | |||
| 0bb2e52deb | |||
| b8eb815a86 | |||
| beca468338 | |||
| a26fe26c8c | |||
| 508fd11610 | |||
| afe0e71a1d | |||
| 9e8d0b3869 | |||
| d7f86ca0de | |||
| 49a79d2722 | |||
| 4ab024d115 | |||
| c4ae27a01b | |||
| 668d39b444 | |||
| 8b25afbf5a | |||
| efeb040f75 | |||
| 7a17b36d50 | |||
| 047a31b4bf | |||
| 096aef9f08 | |||
| 76472b83b5 | |||
| a52bf624ec | |||
| f4e28a246f | |||
| 560ceb26c9 | |||
| 61868c94e5 |
@@ -222,7 +222,7 @@ Fenrir supports two main keyboard layouts:
|
||||
Configure in `/etc/fenrir/settings/settings.conf`:
|
||||
```ini
|
||||
[keyboard]
|
||||
keyboardLayout=desktop # or 'laptop'
|
||||
keyboard_layout=desktop # or 'laptop'
|
||||
```
|
||||
|
||||
### First Time Setup
|
||||
@@ -255,9 +255,9 @@ Enable remote control in `/etc/fenrir/settings/settings.conf`:
|
||||
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
|
||||
socket_file= # custom socket path (optional)
|
||||
enable_settings_remote=True # allow settings changes
|
||||
enable_command_remote=True # allow command execution
|
||||
```
|
||||
|
||||
### Remote Drivers
|
||||
@@ -299,8 +299,8 @@ echo "setting set speech#pitch=0.6" | socat - UNIX-CLIENT:/tmp/fenrirscreenreade
|
||||
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
|
||||
echo "setting set general#punctuation_level=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||
echo "setting set general#punctuation_level=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
|
||||
@@ -311,14 +311,14 @@ echo "setting set sound#enabled=False" | socat - UNIX-CLIENT:/tmp/fenrirscreenre
|
||||
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
|
||||
echo "setting set keyboard#char_echo_mode=1" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||
echo "setting set keyboard#word_echo=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
|
||||
echo "setting set screen#ignore_screen=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
|
||||
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||
|
||||
# Reset all settings to defaults
|
||||
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||
@@ -421,7 +421,7 @@ setting <action> [parameters]
|
||||
- `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
|
||||
- `speech#auto_read_incoming=True/False` - Auto-read new text
|
||||
|
||||
*Sound Settings:*
|
||||
- `sound#enabled=True/False` - Enable/disable sound
|
||||
@@ -430,32 +430,32 @@ setting <action> [parameters]
|
||||
- `sound#theme=theme_name` - Sound theme
|
||||
|
||||
*General Settings:*
|
||||
- `general#punctuationLevel=none/some/most/all` - Punctuation verbosity
|
||||
- `general#debugLevel=0-3` - Debug level
|
||||
- `general#punctuation_level=none/some/most/all` - Punctuation verbosity
|
||||
- `general#debug_level=0-3` - Debug level
|
||||
- `general#emoticons=True/False` - Enable emoticon replacement
|
||||
- `general#autoSpellCheck=True/False` - Automatic spell checking
|
||||
- `general#auto_spell_check=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
|
||||
- `keyboard#char_echo_mode=0-2` - Character echo (0=none, 1=always, 2=capslock only)
|
||||
- `keyboard#word_echo=True/False` - Echo complete words
|
||||
- `keyboard#char_delete_echo=True/False` - Echo deleted characters
|
||||
- `keyboard#interrupt_on_key_press=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
|
||||
- `screen#ignore_screen=1,2,3` - TTY screens to ignore
|
||||
- `screen#autodetect_ignore_screen=True/False` - Auto-detect screens to ignore
|
||||
- `screen#screen_update_delay=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
|
||||
- `time#present_time=True/False` - Announce time
|
||||
- `time#present_date=True/False` - Announce date changes
|
||||
- `time#delay_sec=seconds` - Announcement interval
|
||||
- `time#on_minutes=00,30` - Specific minutes to announce
|
||||
|
||||
## Table Navigation
|
||||
|
||||
@@ -623,7 +623,7 @@ rsync -av source/ destination/ # File synchronization
|
||||
### Customization
|
||||
|
||||
Progress monitoring can be configured through settings:
|
||||
- **Default enabled**: Set `progressMonitoring=True` in sound section
|
||||
- **Default enabled**: Set `progress_monitoring=True` in sound section
|
||||
- **Sound integration**: Works with all sound drivers (sox, gstreamer)
|
||||
- **Remote control**: Enable/disable through remote commands
|
||||
|
||||
@@ -677,8 +677,8 @@ send_fenrir_command("setting set speech#rate=0.9")
|
||||
- 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`
|
||||
- Settings changes can be disabled via `enable_settings_remote=False`
|
||||
- Command execution can be disabled via `enable_command_remote=False`
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
@@ -688,7 +688,7 @@ send_fenrir_command("setting set speech#rate=0.9")
|
||||
- Ensure remote driver is enabled in settings
|
||||
|
||||
**Commands not working:**
|
||||
- Verify `enableCommandRemote=True` in settings
|
||||
- Verify `enable_command_remote=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`
|
||||
|
||||
@@ -710,7 +710,7 @@ fenrir [OPTIONS]
|
||||
- `-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
|
||||
- `-F, --force-all-screens` - Force Fenrir to respond on all screens, ignoring ignore_screen setting
|
||||
- `-i, -I, --ignore-screen SCREEN` - Ignore specific screen(s). Can be used multiple times. Combines with existing ignore settings.
|
||||
|
||||
### Examples:
|
||||
@@ -724,7 +724,7 @@ 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)
|
||||
# Force Fenrir to work on all screens (ignore ignore_screen setting)
|
||||
sudo fenrir -F
|
||||
|
||||
# Ignore specific screens
|
||||
|
||||
@@ -83,6 +83,7 @@ KEY_FENRIR,KEY_CTRL,KEY_P=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_CTRL,KEY_SHIFT,KEY_E=cycle_key_echo
|
||||
key_FENRIR,KEY_KPENTER=toggle_auto_read
|
||||
KEY_FENRIR,KEY_CTRL,KEY_T=toggle_auto_time
|
||||
KEY_FENRIR,KEY_KPASTERISK=toggle_highlight_tracking
|
||||
|
||||
@@ -81,6 +81,7 @@ KEY_FENRIR,KEY_SHIFT,KEY_CTRL,KEY_P=toggle_punctuation_level
|
||||
KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check
|
||||
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_ENTER=toggle_output
|
||||
KEY_FENRIR,KEY_SHIFT,KEY_E=toggle_emoticons
|
||||
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_E=cycle_key_echo
|
||||
KEY_FENRIR,KEY_CTRL,KEY_T=toggle_auto_time
|
||||
KEY_FENRIR,KEY_Y=toggle_highlight_tracking
|
||||
#=toggle_barrier
|
||||
|
||||
+165
-106
@@ -3,14 +3,13 @@
|
||||
enabled=True
|
||||
|
||||
# Select the driver used to play sounds, choices are genericDriver and gstreamerDriver.
|
||||
# Generic driver uses fewer dependencies but spawns a process for each sound played including progress bar beeps
|
||||
# Gstreamer is the default.
|
||||
driver=gstreamerDriver
|
||||
#driver=genericDriver
|
||||
|
||||
# Sound themes. These are the pack of sounds used for sound alerts.
|
||||
# Sound packs may be located at /usr/share/sounds
|
||||
# For system wide availability, or ~/.local/share/fenrirscreenreader/sounds
|
||||
# For the current user.
|
||||
theme=default
|
||||
|
||||
# Sound volume controls how loud the sounds for your selected soundpack are.
|
||||
@@ -24,12 +23,12 @@ volume=0.7
|
||||
# fenrirFrequence = the frequency to play
|
||||
# fenrirDuration = the duration of the frequency
|
||||
# the following command is used to play a soundfile
|
||||
genericPlayFileCommand=play -q -v fenrirVolume fenrirSoundFile
|
||||
generic_play_file_command=play -q -v fenrirVolume fenrirSoundFile
|
||||
#the following command is used to generate a frequency beep
|
||||
genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence
|
||||
generic_frequency_command=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence
|
||||
|
||||
# Enable progress bar monitoring with ascending tones by default
|
||||
progressMonitoring=True
|
||||
progress_monitoring=True
|
||||
|
||||
[speech]
|
||||
# Turn speech on or off:
|
||||
@@ -45,7 +44,13 @@ rate=0.5
|
||||
# Pitch controls the pitch of the voice, select from 0, lowest, to 1.0, highest.
|
||||
pitch=0.5
|
||||
# Pitch for capital letters
|
||||
capitalPitch=0.9
|
||||
capital_pitch=0.9
|
||||
# How to indicate capital letters:
|
||||
# pitch = change speech pitch (uses capital_pitch value)
|
||||
# beep = play Caps.wav sound icon
|
||||
# both = play beep AND change pitch
|
||||
# none = no special indication
|
||||
capital_indicator=pitch
|
||||
|
||||
# Volume controls the loudness of the voice, select from 0, quietest, to 1.0, loudest.
|
||||
volume=1.0
|
||||
@@ -65,10 +70,26 @@ volume=1.0
|
||||
#language=en
|
||||
|
||||
# Read new text as it happens?
|
||||
autoReadIncoming=True
|
||||
auto_read_incoming=True
|
||||
|
||||
# Speak individual numbers instead of whole string.
|
||||
readNumbersAsDigits = False
|
||||
read_numbers_as_digits = False
|
||||
|
||||
# Flood control: batch rapid updates instead of speaking each one
|
||||
# Number of updates within rapid_update_window to trigger batching
|
||||
rapid_update_threshold=5
|
||||
|
||||
# Time window (seconds) for detecting rapid updates
|
||||
rapid_update_window=0.3
|
||||
|
||||
# How often to speak batched content (seconds)
|
||||
batch_flush_interval=0.5
|
||||
|
||||
# Maximum lines to keep when batching (keeps newest, drops oldest)
|
||||
max_batch_lines=100
|
||||
|
||||
# Only enable flood control if this many new lines appear in the window
|
||||
flood_line_threshold=500
|
||||
|
||||
# genericSpeechCommand is the command that is executed for talking
|
||||
# the following variables are replaced with values
|
||||
@@ -81,105 +102,135 @@ readNumbersAsDigits = False
|
||||
# fenrirVolume = is replaced with the current volume
|
||||
# fenrirPitch = is replaced with the current pitch
|
||||
# fenrirRate = is replaced with the current speed (speech rate)
|
||||
genericSpeechCommand=espeak-ng -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice -- "fenrirText"
|
||||
generic_speech_command=espeak-ng -a fenrir_volume -s fenrir_rate -p fenrir_pitch -v fenrir_voice -- "fenrir_text"
|
||||
|
||||
# min and max values of the TTS system that is used in genericSpeechCommand
|
||||
fenrirMinVolume=0
|
||||
fenrirMaxVolume=200
|
||||
fenrirMinPitch=0
|
||||
fenrirMaxPitch=99
|
||||
fenrirMinRate=80
|
||||
fenrirMaxRate=450
|
||||
# min and max values of the TTS system that is used in generic_speech_command
|
||||
fenrir_min_volume=0
|
||||
fenrir_max_volume=200
|
||||
fenrir_min_pitch=0
|
||||
fenrir_max_pitch=99
|
||||
fenrir_min_rate=80
|
||||
fenrir_max_rate=450
|
||||
|
||||
[screen]
|
||||
# Screen driver: vcsaDriver (Linux TTY/virtual console), ptyDriver (terminal emulation)
|
||||
driver=vcsaDriver
|
||||
# Text encoding: auto (auto-detect), utf-8, latin1, etc.
|
||||
encoding=auto
|
||||
screenUpdateDelay=0.05
|
||||
ignoreScreen=7
|
||||
autodetectIgnoreScreen=True
|
||||
# Delay in seconds between screen updates (lower = more responsive, higher = less CPU)
|
||||
# Recommended: 0.05 for most systems
|
||||
screen_update_delay=0.05
|
||||
# TTY number to completely ignore (e.g., 7 for X11/graphical login screen)
|
||||
ignore_screen=7
|
||||
# Automatically detect and ignore graphical TTYs (X11, Wayland sessions)
|
||||
autodetect_ignore_screen=True
|
||||
|
||||
[keyboard]
|
||||
driver=evdevDriver
|
||||
# filter input devices NOMICE, ALL or a DEVICE NAME
|
||||
device=ALL
|
||||
# gives Fenrir exclusive access to the keyboard and lets it control keystrokes.
|
||||
grabDevices=True
|
||||
ignoreShortcuts=False
|
||||
grab_devices=True
|
||||
# Ignore shortcut bindings and pass all keys through without processing Fenrir commands.
|
||||
# When True, Fenrir will only monitor screen content without intercepting keyboard input.
|
||||
# the current shortcut layout located in /etc/fenrirscreenreader/keyboard
|
||||
keyboardLayout=desktop
|
||||
ignore_shortcuts=False
|
||||
keyboard_layout=desktop
|
||||
# echo chars while typing.
|
||||
# 0 = None
|
||||
# 1 = always
|
||||
# 2 = only while capslock (not compatible with capslock as fenrir key)
|
||||
charEchoMode=1
|
||||
char_echo_mode=1
|
||||
# echo deleted chars
|
||||
charDeleteEcho=True
|
||||
char_delete_echo=True
|
||||
# echo word after pressing space
|
||||
wordEcho=False
|
||||
word_echo=False
|
||||
# interrupt speech on any keypress
|
||||
interruptOnKeyPress=True
|
||||
interrupt_on_key_press=True
|
||||
# you can filter the keys on that the speech should interrupt (empty = all keys, otherwhise the given keys)
|
||||
interruptOnKeyPressFilter=
|
||||
interrupt_on_key_press_filter=
|
||||
# timeout for double tap in sec
|
||||
doubleTapTimeout=0.2
|
||||
double_tap_timeout=0.2
|
||||
|
||||
[general]
|
||||
# Debug levels: 0=DEACTIVE, 1=ERROR, 2=WARNING, 3=INFO (most verbose)
|
||||
# Debug levels: 0=NONE, 1=ERROR, 2=WARNING, 3=INFO (most verbose)
|
||||
# For production use, WARNING (2) provides good balance of useful info without spam
|
||||
debugLevel=2
|
||||
# The default is 0, no logging.
|
||||
debug_level=0
|
||||
# debugMode sets where the debug output should send to:
|
||||
# debugMode=File writes to debugFile (Default:/tmp/fenrir-PID.log)
|
||||
# debugMode=File writes to debug_file (Default:/tmp/fenrir-PID.log)
|
||||
# debugMode=Print just prints on the screen
|
||||
debugMode=File
|
||||
debugFile=
|
||||
punctuationProfile=default
|
||||
punctuationLevel=some
|
||||
respectPunctuationPause=True
|
||||
debug_mode=File
|
||||
debug_file=
|
||||
# Punctuation settings control how punctuation is spoken during text review.
|
||||
# Profile selects a punctuation definition file from config/punctuation/ (e.g., default.conf)
|
||||
punctuation_profile=default
|
||||
punctuation_level=some
|
||||
respect_punctuation_pause=True
|
||||
# Replace undefined punctuation with spaces instead of removing them
|
||||
# This improves readability of text with punctuation like [X]mute, IP addresses, etc.
|
||||
replaceUndefinedPunctuationWithSpace=True
|
||||
newLinePause=True
|
||||
numberOfClipboards=50
|
||||
replace_undefined_punctuation_with_space=True
|
||||
# Pause speech briefly at newline characters for better readability
|
||||
new_line_pause=True
|
||||
number_of_clipboards=50
|
||||
# used path for "export_clipboard_to_file"
|
||||
# $user is replaced by username
|
||||
#clipboardExportPath=/home/$user/fenrirClipboard
|
||||
clipboardExportPath=/tmp/fenrirClipboard
|
||||
clipboard_export_path=/tmp/fenrirClipboard
|
||||
# Convert text emoticons like :) to descriptive text (e.g., "smiling face")
|
||||
emoticons=True
|
||||
# define the current Fenrir key
|
||||
fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT
|
||||
scriptKeys=KEY_COMPOSE
|
||||
timeFormat=%%I:%%M%%P
|
||||
dateFormat=%%A, %%B %%d, %%Y
|
||||
autoSpellCheck=True
|
||||
spellCheckLanguage=en_US
|
||||
# path for your scripts "scriptKeys" functionality
|
||||
scriptPath=/usr/share/fenrirscreenreader/scripts
|
||||
# overload commands, and create new one without changing Fenrir default
|
||||
commandPath=
|
||||
#fenrirBGColor = the backgroundcolor
|
||||
#fenrirFGColor = the foregroundcolor
|
||||
#fenrirUnderline = speak the underline attribute
|
||||
#fenrirBold = speak the bold attribute
|
||||
#fenrirBlink = speak the blink attribute
|
||||
#fenrirFont = the font
|
||||
#fenrirFontSize = the fontsize
|
||||
attributeFormatString=Background fenrirBGColor,Foreground fenrirFGColor,fenrirUnderline,fenrirBold,fenrirBlink, Font fenrirFont,Fontsize fenrirFontSize
|
||||
# present indentation
|
||||
autoPresentIndent=False
|
||||
# speak is only invoked on changeing ident level, sound always
|
||||
# 0 = sound and speak
|
||||
# 1 = sound only
|
||||
# 2 = speak only
|
||||
autoPresentIndentMode=1
|
||||
# play a sound when attributes change
|
||||
hasAttributes=True
|
||||
# shell for PTY emulatiun (empty = default shell)
|
||||
# Define the Fenrir modifier key(s) - used to trigger Fenrir commands
|
||||
# Examples: KEY_KP0 (numpad 0), KEY_META (Super/Windows), KEY_INSERT
|
||||
# Multiple keys: KEY_KP0,KEY_META,KEY_INSERT
|
||||
fenrir_keys=KEY_KP0,KEY_META,KEY_INSERT
|
||||
# Script key - used to execute custom scripts in script_path
|
||||
script_keys=KEY_COMPOSE
|
||||
# Time format using Python strftime codes (https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior)
|
||||
# Default: %%I:%%M%%P (12-hour format, e.g., "06:38pm")
|
||||
# 24-hour format: %%H:%%M (e.g., "18:38")
|
||||
# Common codes: %%I=12hr hour, %%H=24hr hour, %%M=minute, %%S=second, %%P=am/pm lowercase, %%p=AM/PM uppercase
|
||||
time_format=%%I:%%M%%P
|
||||
# Date format using Python strftime codes
|
||||
# Default: %%A, %%B %%d, %%Y (e.g., "Tuesday, December 10, 2024")
|
||||
# ISO format: %%Y-%%m-%%d (e.g., "2024-12-10")
|
||||
# Common codes: %%A=weekday name, %%B=month name, %%d=day, %%Y=year with century, %%m=month number
|
||||
date_format=%%A, %%B %%d, %%Y
|
||||
# Automatically spell check words when reviewing character-by-character
|
||||
auto_spell_check=True
|
||||
# Language for spell checking (format: language_COUNTRY, e.g., en_US, en_GB, es_ES)
|
||||
spell_check_language=en_US
|
||||
# path for your scripts "script_keys" functionality
|
||||
script_path=/usr/share/fenrirscreenreader/scripts
|
||||
# Override default commands or add custom commands without modifying Fenrir installation
|
||||
# Leave empty to use default commands only
|
||||
command_path=
|
||||
# Format string for announcing text attributes (colors, formatting)
|
||||
# Available variables:
|
||||
# fenrirBGColor = the background color
|
||||
# fenrirFGColor = the foreground color
|
||||
# fenrirUnderline = speak the underline attribute
|
||||
# fenrirBold = speak the bold attribute
|
||||
# fenrirBlink = speak the blink attribute
|
||||
# fenrirFont = the font name
|
||||
# fenrirFontSize = the font size
|
||||
attribute_format_string=Background fenrirBGColor,Foreground fenrirFGColor,fenrirUnderline,fenrirBold,fenrirBlink, Font fenrirFont,Fontsize fenrirFontSize
|
||||
# Automatically announce indentation level changes (useful for Python, YAML, etc.)
|
||||
auto_present_indent=False
|
||||
# How to present indentation changes:
|
||||
# 0 = sound and speak (both audio feedback and voice announcement)
|
||||
# 1 = sound only (just play a tone)
|
||||
# 2 = speak only (just voice announcement)
|
||||
auto_present_indent_mode=1
|
||||
# Play a sound when text attributes (color, bold, etc.) change
|
||||
has_attributes=True
|
||||
# Shell to use for PTY emulation mode (empty = use system default shell)
|
||||
# Examples: /bin/bash, /bin/zsh, /usr/bin/fish
|
||||
shell=
|
||||
|
||||
[focus]
|
||||
#follow the text cursor
|
||||
# Follow and announce text cursor position changes
|
||||
cursor=True
|
||||
#follow highlighted text changes
|
||||
# Follow and announce highlighted/selected text changes (useful in menus)
|
||||
highlight=False
|
||||
|
||||
[remote]
|
||||
@@ -191,40 +242,43 @@ driver=unixDriver
|
||||
# tcp port
|
||||
port=22447
|
||||
# socket filepath
|
||||
socketFile=
|
||||
socket_file=
|
||||
# allow settings to overwrite
|
||||
enableSettingsRemote=True
|
||||
enable_settings_remote=True
|
||||
# allow commands to be executed
|
||||
enableCommandRemote=True
|
||||
enable_command_remote=True
|
||||
|
||||
[barrier]
|
||||
# Enable barrier detection - automatically detects table/box borders for improved navigation
|
||||
enabled=False
|
||||
leftBarriers=│└┌─
|
||||
rightBarriers=│┘┐─
|
||||
# Characters that represent left-side barriers/borders (for table/box detection)
|
||||
left_barriers=│└┌─
|
||||
# Characters that represent right-side barriers/borders (for table/box detection)
|
||||
right_barriers=│┘┐─
|
||||
|
||||
[review]
|
||||
lineBreak=True
|
||||
endOfScreen=True
|
||||
# leave the review when pressing a key
|
||||
leaveReviewOnCursorChange=True
|
||||
# leave the review when changing the screen
|
||||
leaveReviewOnScreenChange=True
|
||||
|
||||
[promote]
|
||||
enabled=True
|
||||
inactiveTimeoutSec=120
|
||||
list=
|
||||
# Announce line breaks during review mode
|
||||
line_break=True
|
||||
# Announce when reaching the end of screen during review
|
||||
end_of_screen=True
|
||||
# Exit review mode when cursor position changes (e.g., when typing)
|
||||
leave_review_on_cursor_change=True
|
||||
# Exit review mode when switching to a different TTY/screen
|
||||
leave_review_on_screen_change=True
|
||||
|
||||
[menu]
|
||||
vmenuPath=
|
||||
# quickMenu: Semicolon-separated list of settings for quick adjustment
|
||||
# Custom path for VMenu (virtual menu) profiles
|
||||
# Leave empty to use default location (/etc/fenrirscreenreader/vmenu-profiles/)
|
||||
vmenu_path=
|
||||
# Quick menu: Semicolon-separated list of settings for rapid adjustment via VMenu
|
||||
# Access with Fenrir+F10, navigate to "Quick Settings"
|
||||
# Format: section#setting;section#setting;...
|
||||
# Supported settings:
|
||||
# - speech#rate, speech#pitch, speech#volume (0.0-1.0)
|
||||
# - speech#module, speech#voice (speechdDriver only, auto-added)
|
||||
# Note: speech#module and speech#voice are automatically added when
|
||||
# speechdDriver is active. Do not add them manually.
|
||||
quickMenu=speech#rate;speech#pitch;speech#volume
|
||||
quick_menu=speech#rate;speech#pitch;speech#volume
|
||||
|
||||
[prompt]
|
||||
# Custom prompt patterns for silence until prompt feature
|
||||
@@ -242,27 +296,32 @@ quickMenu=speech#rate;speech#pitch;speech#volume
|
||||
# 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=
|
||||
custom_patterns=
|
||||
|
||||
# Specific prompt strings to match exactly (useful for very specific custom prompts)
|
||||
# Format: exactMatches=prompt1,prompt2,prompt3
|
||||
# Format: exact_matches=prompt1,prompt2,prompt3
|
||||
# Examples:
|
||||
# exactMatches=[storm@fenrir ~] $,[root@fenrir ~] #,Continue installation? [Y/n]
|
||||
exactMatches=
|
||||
# exact_matches=[storm@fenrir ~] $,[root@fenrir ~] #,Continue installation? [Y/n]
|
||||
exact_matches=
|
||||
|
||||
[time]
|
||||
# automatic time announcement
|
||||
# Enable automatic time announcements
|
||||
enabled=False
|
||||
# present time
|
||||
presentTime=True
|
||||
# present date (on change)
|
||||
presentDate=True
|
||||
# present time after a given period of seconds
|
||||
delaySec=0
|
||||
# present time after to given minutes example every 15 minutes: 00,15,30,45
|
||||
# if delaySec is >0 onMinutes is ignored
|
||||
onMinutes=00,30
|
||||
# announce via soundicon (not interrupting)
|
||||
# Announce the current time
|
||||
present_time=True
|
||||
# Announce the date (only when it changes, e.g., at midnight)
|
||||
present_date=True
|
||||
# Announce time every N seconds (0 = disabled)
|
||||
# If delay_sec > 0, on_minutes is ignored
|
||||
delay_sec=0
|
||||
# Announce time at specific minutes of each hour (comma-separated)
|
||||
# Examples:
|
||||
# 00 = Only on the hour (1:00, 2:00, 3:00, etc.)
|
||||
# 00,30 = On the hour and half-hour (1:00, 1:30, 2:00, 2:30, etc.)
|
||||
# 00,15,30,45 = Every 15 minutes
|
||||
# Note: This is ignored if delay_sec > 0
|
||||
on_minutes=00,30
|
||||
# Play a sound icon before time announcement (non-interrupting)
|
||||
announce=True
|
||||
# interrupt current speech for time announcement
|
||||
# Interrupt current speech to announce time immediately
|
||||
interrupt=False
|
||||
|
||||
Binary file not shown.
@@ -46,8 +46,6 @@ ErrorSpeech='ErrorSpeech.wav'
|
||||
ErrorScreen='ErrorScreen.wav'
|
||||
# If you cursor over an text that has attributs (like color)
|
||||
HasAttributes='has_attribute.wav'
|
||||
# fenrir can promote strings if they appear on the screen.
|
||||
PromotedText='PromotedText.wav'
|
||||
# missspelled indicator
|
||||
mispell='mispell.wav'
|
||||
# the for capital letter
|
||||
|
||||
@@ -50,8 +50,6 @@ ErrorBraille=''
|
||||
ErrorScreen=''
|
||||
# If you cursor over an text that has attributs (like color)
|
||||
HasAttributes=''
|
||||
# fenrir can promote strings if they appear on the screen.
|
||||
PromotedText=''
|
||||
# misspelled indicator
|
||||
mispell=''
|
||||
# the for capital letter:
|
||||
|
||||
+33
-83
@@ -1095,23 +1095,6 @@ announce=True
|
||||
interrupt=False
|
||||
....
|
||||
|
||||
==== Promoted List
|
||||
|
||||
Promoted Lists are a nice feature if you are away from your computer or
|
||||
performing more longer tasks. you can define a list of words which you
|
||||
want to hear a sound icon for after a period of inactivity. Example if
|
||||
the word "Chrys" appears after 120 Seconds of inactivity:
|
||||
|
||||
....
|
||||
[promote]
|
||||
enabled=True
|
||||
inactiveTimeoutSec=120
|
||||
list=Chrys
|
||||
....
|
||||
|
||||
See section link:#Promote[Promote] in `+settings.conf+` for more
|
||||
information.
|
||||
|
||||
=== Dictionary
|
||||
|
||||
You can make use of different kinds of built-in dictionary's. A
|
||||
@@ -1286,8 +1269,8 @@ Enable remote control in settings.conf:
|
||||
[remote]
|
||||
enable=True
|
||||
driver=unixDriver
|
||||
enableSettingsRemote=True
|
||||
enableCommandRemote=True
|
||||
enable_settings_remote=True
|
||||
enable_command_remote=True
|
||||
....
|
||||
|
||||
==== Using socat with Unix Sockets
|
||||
@@ -1317,13 +1300,13 @@ echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenr
|
||||
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
|
||||
echo "setting set general#punctuation_level=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
|
||||
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||
|
||||
# Reset all settings to defaults
|
||||
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||
@@ -1394,8 +1377,8 @@ echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-dea
|
||||
* `+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#punctuation_level=none/some/most/all+` - Punctuation verbosity
|
||||
* `+general#auto_spell_check=True/False+` - Automatic spell checking
|
||||
* `+general#emoticons=True/False+` - Enable emoticon replacement
|
||||
|
||||
*Sound Settings:*
|
||||
@@ -1407,11 +1390,11 @@ echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-dea
|
||||
* `+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#char_echo_mode=0-2+` - Character echo (0=none, 1=always, 2=capslock only)
|
||||
* `+keyboard#word_echo=True/False+` - Echo complete words
|
||||
|
||||
*Screen Settings:*
|
||||
* `+screen#ignoreScreen=1,2,3+` - TTY screens to ignore
|
||||
* `+screen#ignore_screen=1,2,3+` - TTY screens to ignore
|
||||
|
||||
==== settings.conf syntax
|
||||
|
||||
@@ -1511,14 +1494,14 @@ frequencies.
|
||||
sound file.
|
||||
|
||||
....
|
||||
genericPlayFileCommand=<your command for playing a file>
|
||||
generic_play_file_command=<your command for playing a file>
|
||||
....
|
||||
|
||||
`+genericFrequencyCommand+` defines the command that is used playing
|
||||
frequencies.
|
||||
|
||||
....
|
||||
genericFrequencyCommand=<your command for playing a frequence>
|
||||
generic_frequency_command=<your command for playing a frequence>
|
||||
....
|
||||
|
||||
The following variables are substituted in `+genericPlayFileCommand+`
|
||||
@@ -1532,13 +1515,13 @@ and `+genericFrequencyCommand+`:
|
||||
Example genericPlayFileCommand (default)
|
||||
|
||||
....
|
||||
genericPlayFileCommand=play -q -v fenrirVolume fenrirSoundFile
|
||||
generic_play_file_command=play -q -v fenrirVolume fenrirSoundFile
|
||||
....
|
||||
|
||||
Example genericFrequencyCommand (default)
|
||||
|
||||
....
|
||||
genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence
|
||||
generic_frequency_command=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence
|
||||
....
|
||||
|
||||
==== Speech
|
||||
@@ -1579,7 +1562,7 @@ Values: Range Minimum:`+0.0+` is lowest, Maximum:`+1.0+` is highest.
|
||||
A Pitch for capital letters can be set.
|
||||
|
||||
....
|
||||
capitalPitch=0.9
|
||||
capital_pitch=0.9
|
||||
....
|
||||
|
||||
Values: Range Minimum:`+0.0+` is lowest, Maximum:`+1.0+` is highest.
|
||||
@@ -1681,7 +1664,7 @@ the pico module:
|
||||
language=de-DE
|
||||
....
|
||||
|
||||
Read new text as it occurs autoReadIncoming=True Values: on=`+True+`,
|
||||
Read new text as it occurs auto_read_incoming=True Values: on=`+True+`,
|
||||
off=`+False+`
|
||||
|
||||
==== Screen
|
||||
@@ -1711,7 +1694,7 @@ Values:`+cp850+` is used for Western languages like USA or Europe.
|
||||
The driver updates Fenrir with changes on the screen.
|
||||
|
||||
....
|
||||
screenUpdateDelay=0.05
|
||||
screen_update_delay=0.05
|
||||
....
|
||||
|
||||
Values: in Seconds
|
||||
@@ -1776,7 +1759,7 @@ Gives Fenrir exclusive access to the keyboard and lets it control
|
||||
keystrokes. This is needed to intercept Fenrir related shortcuts.
|
||||
|
||||
....
|
||||
grabDevices=True
|
||||
grab_devices=True
|
||||
....
|
||||
|
||||
Values: on=`+True+`, off=`+False+`
|
||||
@@ -1785,7 +1768,7 @@ The following makes sense if you are using a second screenreader and
|
||||
want to have some hooked events. Fenrir ignores all shortcuts then.
|
||||
|
||||
....
|
||||
ignoreShortcuts=False
|
||||
ignore_shortcuts=False
|
||||
....
|
||||
|
||||
Values: on=`+True+`, off=`+False+`
|
||||
@@ -1793,7 +1776,7 @@ Values: on=`+True+`, off=`+False+`
|
||||
The current keyboard layout used for shortcuts.
|
||||
|
||||
....
|
||||
keyboardLayout=desktop
|
||||
keyboard_layout=desktop
|
||||
....
|
||||
|
||||
Values: An absolute Path to a Keyboard definition file or a Filename
|
||||
@@ -1810,7 +1793,7 @@ Values: on=`+True+`, off=`+False+`
|
||||
Announce deleted characters
|
||||
|
||||
....
|
||||
charDeleteEcho=True
|
||||
char_delete_echo=True
|
||||
....
|
||||
|
||||
Values: on=`+True+`, off=`+False+`
|
||||
@@ -1818,7 +1801,7 @@ Values: on=`+True+`, off=`+False+`
|
||||
Announce word after pressing space
|
||||
|
||||
....
|
||||
wordEcho=False
|
||||
word_echo=False
|
||||
....
|
||||
|
||||
Values: on=`+True+`, off=`+False+`
|
||||
@@ -1826,7 +1809,7 @@ Values: on=`+True+`, off=`+False+`
|
||||
Interrupt speech on any keypress
|
||||
|
||||
....
|
||||
interruptOnKeyPress=False
|
||||
interrupt_on_key_press=False
|
||||
....
|
||||
|
||||
Values: on=`+True+`, off=`+False+`
|
||||
@@ -1834,7 +1817,7 @@ Values: on=`+True+`, off=`+False+`
|
||||
You can filter the keys that speech should interrupt
|
||||
|
||||
....
|
||||
interruptOnKeyPressFilter=
|
||||
interrupt_on_key_press_filter=
|
||||
....
|
||||
|
||||
Values: (List) empty = all keys, otherwise interrupt with specified keys
|
||||
@@ -1842,7 +1825,7 @@ Values: (List) empty = all keys, otherwise interrupt with specified keys
|
||||
The timeout that is used for double tap shortcuts
|
||||
|
||||
....
|
||||
doubleTapTimeout=0.2
|
||||
double_tap_timeout=0.2
|
||||
....
|
||||
|
||||
Values: Seconds
|
||||
@@ -1862,7 +1845,7 @@ Values: off=0, error=1, warning=2, info=3
|
||||
the current punctuation and dict file in use:
|
||||
|
||||
....
|
||||
punctuationProfile=default
|
||||
punctuation_profile=default
|
||||
....
|
||||
|
||||
Values: Text, see available profiles in `+/etc/fenrir/punctuation+` or
|
||||
@@ -1871,7 +1854,7 @@ in `+sourceTree/config/punctuation+`
|
||||
The current punctuation level in use:
|
||||
|
||||
....
|
||||
punctuationLevel=some
|
||||
punctuation_level=some
|
||||
....
|
||||
|
||||
Values: Text, See available levels in the used punctuation file.
|
||||
@@ -1879,7 +1862,7 @@ Values: Text, See available levels in the used punctuation file.
|
||||
Respect pause for punctuations:
|
||||
|
||||
....
|
||||
respectPunctuationPause=True
|
||||
respect_punctuation_pause=True
|
||||
....
|
||||
|
||||
Values: on=`+True+`, off=`+False+`
|
||||
@@ -1887,7 +1870,7 @@ Values: on=`+True+`, off=`+False+`
|
||||
Add a pause on Line break:
|
||||
|
||||
....
|
||||
newLinePause=True
|
||||
new_line_pause=True
|
||||
....
|
||||
|
||||
Values: on=`+True+`, off=`+False+`
|
||||
@@ -1905,7 +1888,7 @@ Values: Text, Systemfilepath
|
||||
The number of available clipboards:
|
||||
|
||||
....
|
||||
numberOfClipboards=10
|
||||
number_of_clipboards=10
|
||||
....
|
||||
|
||||
Values: Integer, 1 - 999
|
||||
@@ -1921,7 +1904,7 @@ Values: on=`+True+`, off=`+False+`
|
||||
Define the current Fenrir keys:
|
||||
|
||||
....
|
||||
fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT
|
||||
fenrir_keys=KEY_KP0,KEY_META,KEY_INSERT
|
||||
....
|
||||
|
||||
Values, Text list, separated by comma.
|
||||
@@ -1955,7 +1938,7 @@ https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior[d
|
||||
Enable or Disable spellcheck whilst typing:
|
||||
|
||||
....
|
||||
autoSpellCheck=True
|
||||
auto_spell_check=True
|
||||
....
|
||||
|
||||
Values: on=`+True+`, off=`+False+`
|
||||
@@ -1963,7 +1946,7 @@ Values: on=`+True+`, off=`+False+`
|
||||
The use of the dictionary with spellcheck:
|
||||
|
||||
....
|
||||
spellCheckLanguage=en_US
|
||||
spell_check_language=en_US
|
||||
....
|
||||
|
||||
Values: Text, see aspell dictionary's.
|
||||
@@ -2044,44 +2027,11 @@ Values: on=`+True+`, off=`+False+`
|
||||
Leave the review mode when changing the screen (From TTY3 to TTY4):
|
||||
|
||||
....
|
||||
leaveReviewOnScreenChange=True
|
||||
leave_review_on_screen_change=True
|
||||
....
|
||||
|
||||
Values: on=`+True+`, off=`+False+`
|
||||
|
||||
==== Promote
|
||||
|
||||
"Promoted Lists" are configured in the section `+[promote]+`. Turn
|
||||
Promoted Lists" on or off:
|
||||
|
||||
....
|
||||
enabled=True
|
||||
....
|
||||
|
||||
Values: on=`+True+`, off=`+False+`
|
||||
|
||||
The minimum time interval of inactivity to activate promoting. By
|
||||
default it promotes after 120 Seconds inactivity:
|
||||
|
||||
....
|
||||
inactiveTimeoutSec=120
|
||||
....
|
||||
|
||||
Values: in Seconds
|
||||
|
||||
Define a list of promoted words comma seperated:
|
||||
|
||||
....
|
||||
list=
|
||||
....
|
||||
|
||||
Values: text (comma seperated) Example to promote the word "nickname" or
|
||||
a bash prompt:
|
||||
|
||||
....
|
||||
list=nickname,$:,#:
|
||||
....
|
||||
|
||||
==== Time
|
||||
|
||||
The automated time announcement is configured in the section `+[time]+`.
|
||||
|
||||
+11
-11
@@ -102,17 +102,17 @@ volume=0.7
|
||||
|
||||
[keyboard]
|
||||
driver=evdevDriver
|
||||
keyboardLayout=desktop
|
||||
keyboard_layout=desktop
|
||||
|
||||
[screen]
|
||||
driver=vcsaDriver
|
||||
ignoreScreen=
|
||||
ignore_screen=
|
||||
|
||||
[remote]
|
||||
enable=True
|
||||
driver=unixDriver
|
||||
enableSettingsRemote=True
|
||||
enableCommandRemote=True
|
||||
enable_settings_remote=True
|
||||
enable_command_remote=True
|
||||
```
|
||||
|
||||
## Remote Control
|
||||
@@ -126,8 +126,8 @@ Enable remote control in settings:
|
||||
enable=True
|
||||
driver=unixDriver # or tcpDriver
|
||||
port=22447 # for TCP driver
|
||||
enableSettingsRemote=True # allow settings changes
|
||||
enableCommandRemote=True # allow command execution
|
||||
enable_settings_remote=True # allow settings changes
|
||||
enable_command_remote=True # allow command execution
|
||||
```
|
||||
|
||||
### Basic Usage with socat
|
||||
@@ -155,14 +155,14 @@ echo "setting set speech#pitch=0.6" | socat - UNIX-CLIENT:/tmp/fenrirscreenreade
|
||||
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#punctuation_level=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
|
||||
echo "setting set speech#module=espeak-ng" | 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
|
||||
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||
|
||||
# Reset all settings
|
||||
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||
@@ -208,11 +208,11 @@ echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-dea
|
||||
- `command resetvmenu` - Reset virtual menu
|
||||
|
||||
**Key Settings You Can Change:**
|
||||
- Punctuation level: `setting set general#punctuationLevel=all`
|
||||
- Punctuation level: `setting set general#punctuation_level=all`
|
||||
- Speech parameters: `setting set speech#rate=0.8;speech#pitch=0.6`
|
||||
- Voice selection: `setting set speech#voice=en-us+f3`
|
||||
- Character echo: `setting set keyboard#charEchoMode=1`
|
||||
- Screen ignore: `setting set screen#ignoreScreen=1,2,3`
|
||||
- Character echo: `setting set keyboard#char_echo_mode=1`
|
||||
- Screen ignore: `setting set screen#ignore_screen=1,2,3`
|
||||
|
||||
### Scripting Integration
|
||||
|
||||
|
||||
+30
-56
@@ -729,15 +729,6 @@ Example on fix minutes in an hour. example every quarter "delaySec=0" and "onMin
|
||||
onMinutes=00,15,30,45
|
||||
announce=True
|
||||
interrupt=False
|
||||
==== Promoted List ====
|
||||
Promoted Lists are a nice feature if you are away from your computer or performing more longer tasks.
|
||||
you can define a list of words which you want to hear a sound icon for after a period of inactivity.
|
||||
Example if the word "Chrys" appears after 120 Seconds of inactivity:
|
||||
[promote]
|
||||
enabled=True
|
||||
inactiveTimeoutSec=120
|
||||
list=Chrys
|
||||
See section [[#Promote|Promote]] in ''settings.conf'' for more information.
|
||||
==== Punctuation ====
|
||||
Fenrir handles punctuation levels and names for you with several provided dictionaries.
|
||||
|
||||
@@ -867,9 +858,9 @@ Values: ''0.0'' is quietest, ''1.0'' is loudest.
|
||||
The generic sound driver uses shell commands for play sound and frequencies.
|
||||
|
||||
''genericPlayFileCommand'' defines the command that is used to play a sound file.
|
||||
genericPlayFileCommand=<your command for playing a file>
|
||||
generic_play_file_command=<your command for playing a file>
|
||||
''genericFrequencyCommand'' defines the command that is used playing frequencies.
|
||||
genericFrequencyCommand=<your command for playing a frequence>
|
||||
generic_frequency_command=<your command for playing a frequence>
|
||||
|
||||
The following variables are substituted in ''genericPlayFileCommand'' and ''genericFrequencyCommand'':
|
||||
* ''fenrirVolume'' = the current volume setting
|
||||
@@ -878,9 +869,9 @@ The following variables are substituted in ''genericPlayFileCommand'' and ''gene
|
||||
* ''fenrirDuration'' = the duration of the frequency
|
||||
|
||||
Example genericPlayFileCommand (default)
|
||||
genericPlayFileCommand=play -q -v fenrirVolume fenrirSoundFile
|
||||
generic_play_file_command=play -q -v fenrirVolume fenrirSoundFile
|
||||
Example genericFrequencyCommand (default)
|
||||
genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence
|
||||
generic_frequency_command=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence
|
||||
==== Speech ====
|
||||
Speech is configured in section ''[speech]''.
|
||||
Turn speech on or off:
|
||||
@@ -910,7 +901,7 @@ Pitch controls the pitch of the voice.
|
||||
Values: Range Minimum:''0.0'' is lowest, Maximum:''1.0'' is highest.
|
||||
|
||||
A Pitch for capital letters can be set.
|
||||
capitalPitch=0.9
|
||||
capital_pitch=0.9
|
||||
Values: Range Minimum:''0.0'' is lowest, Maximum:''1.0'' is highest.
|
||||
|
||||
The Volume controls the loudness of the voice.
|
||||
@@ -931,7 +922,7 @@ Select the language you want Fenrir to use.
|
||||
Values: Text, see your TTS synths documentation what is available.
|
||||
|
||||
Read new text as it occurs
|
||||
autoReadIncoming=True
|
||||
auto_read_incoming=True
|
||||
Values: on=''True'', off=''False''
|
||||
|
||||
=== Generic Driver ===
|
||||
@@ -948,16 +939,16 @@ The following variables are substituted in ''genericSpeechCommand'':
|
||||
* ''fenrirRate'' = is replaced with the current speed (speech rate)
|
||||
|
||||
Example genericSpeechCommand (default):
|
||||
genericSpeechCommand=espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice "fenrirText"
|
||||
generic_speech_command=espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice "fenrirText"
|
||||
|
||||
These are the minimum and maximum values of the TTS system used in genericSpeechCommand. They are needed to calculate the abstract range in volume, rate and pitch 0.0 - 1.0.
|
||||
|
||||
FenrirMinVolume=0
|
||||
fenrirMaxVolume=200
|
||||
fenrirMinPitch=0
|
||||
fenrirMaxPitch=99
|
||||
fenrirMinRate=80
|
||||
fenrirMaxRate=450
|
||||
fenrir_max_volume=200
|
||||
fenrir_min_pitch=0
|
||||
fenrir_max_pitch=99
|
||||
fenrir_min_rate=80
|
||||
fenrir_max_rate=450
|
||||
|
||||
The current volume, pitch and rate is calculated like this
|
||||
value = min + [volume,pitch,rate] * (min - max )
|
||||
@@ -1033,7 +1024,7 @@ The encoding of the screen
|
||||
Values:''cp850'' is used for Western languages like USA or Europe.
|
||||
|
||||
The driver updates Fenrir with changes on the screen.
|
||||
screenUpdateDelay=0.05
|
||||
screen_update_delay=0.05
|
||||
Values: in Seconds
|
||||
|
||||
If you want Fenrir to not be active on any screen for various reasons. Maybe an X server or Wayland is running on that screen. You can make Fenrir ignore it or multiple screens seperated by '','' with:
|
||||
@@ -1064,15 +1055,15 @@ Values:
|
||||
* ''<Device Name>'' just use the device with the given name.
|
||||
|
||||
Gives Fenrir exclusive access to the keyboard and lets it control keystrokes. This is needed to intercept Fenrir related shortcuts.
|
||||
grabDevices=True
|
||||
grab_devices=True
|
||||
Values: on=''True'', off=''False''
|
||||
|
||||
The following makes sense if you are using a second screenreader and want to have some hooked events. Fenrir ignores all shortcuts then.
|
||||
ignoreShortcuts=False
|
||||
ignore_shortcuts=False
|
||||
Values: on=''True'', off=''False''
|
||||
|
||||
The current keyboard layout used for shortcuts.
|
||||
keyboardLayout=desktop
|
||||
keyboard_layout=desktop
|
||||
Values: An absolute Path to a Keyboard definition file or a Filename without extension located in ''/etc/fenrir/keyboard''
|
||||
|
||||
Announce characters while typing.
|
||||
@@ -1080,23 +1071,23 @@ Announce characters while typing.
|
||||
Values: on=''True'', off=''False''
|
||||
|
||||
Announce deleted characters
|
||||
charDeleteEcho=True
|
||||
char_delete_echo=True
|
||||
Values: on=''True'', off=''False''
|
||||
|
||||
Announce word after pressing space
|
||||
wordEcho=False
|
||||
word_echo=False
|
||||
Values: on=''True'', off=''False''
|
||||
|
||||
Interrupt speech on any keypress
|
||||
interruptOnKeyPress=False
|
||||
interrupt_on_key_press=False
|
||||
Values: on=''True'', off=''False''
|
||||
|
||||
You can filter the keys that speech should interrupt
|
||||
interruptOnKeyPressFilter=
|
||||
interrupt_on_key_press_filter=
|
||||
Values: (List) empty = all keys, otherwise interrupt with specified keys
|
||||
|
||||
The timeout that is used for double tap shortcuts
|
||||
doubleTapTimeout=0.2
|
||||
double_tap_timeout=0.2
|
||||
Values: Seconds
|
||||
==== General ====
|
||||
Overall settings can be configured from the section ''[general]''.
|
||||
@@ -1106,19 +1097,19 @@ Set the current debug level:
|
||||
Values: off=0, error=1, warning=2, info=3
|
||||
|
||||
the current punctuation and dict file in use:
|
||||
punctuationProfile=default
|
||||
punctuation_profile=default
|
||||
Values: Text, see available profiles in ''/etc/fenrir/punctuation'' or in ''sourceTree/config/punctuation''
|
||||
|
||||
The current punctuation level in use:
|
||||
punctuationLevel=some
|
||||
punctuation_level=some
|
||||
Values: Text, See available levels in the used punctuation file.
|
||||
|
||||
Respect pause for punctuations:
|
||||
respectPunctuationPause=True
|
||||
respect_punctuation_pause=True
|
||||
Values: on=''True'', off=''False''
|
||||
|
||||
Add a pause on Line break:
|
||||
newLinePause=True
|
||||
new_line_pause=True
|
||||
Values: on=''True'', off=''False''
|
||||
|
||||
Specify the path where the clipboard should be exported to.
|
||||
@@ -1128,7 +1119,7 @@ The variable ''$user'' is replaced by the current logged username.
|
||||
Values: Text, Systemfilepath
|
||||
|
||||
The number of available clipboards:
|
||||
numberOfClipboards=10
|
||||
number_of_clipboards=10
|
||||
Values: Integer, 1 - 999
|
||||
|
||||
Replace emoticons like :) or ;) with text insertions:
|
||||
@@ -1136,7 +1127,7 @@ Replace emoticons like :) or ;) with text insertions:
|
||||
Values: on=''True'', off=''False''
|
||||
|
||||
Define the current Fenrir keys:
|
||||
fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT
|
||||
fenrir_keys=KEY_KP0,KEY_META,KEY_INSERT
|
||||
Values, Text list, separated by comma.
|
||||
|
||||
Define the current script keys:
|
||||
@@ -1152,11 +1143,11 @@ The date format to be used for (date command) output:
|
||||
Values: see python specification for [[https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior|datetime.strftime]]
|
||||
|
||||
Enable or Disable spellcheck whilst typing:
|
||||
autoSpellCheck=True
|
||||
auto_spell_check=True
|
||||
Values: on=''True'', off=''False''
|
||||
|
||||
The use of the dictionary with spellcheck:
|
||||
spellCheckLanguage=en_US
|
||||
spell_check_language=en_US
|
||||
Values: Text, see aspell dictionary's.
|
||||
|
||||
Folder Path for your scripts "scriptKey" functionality:
|
||||
@@ -1197,25 +1188,8 @@ Leave the review mode when pressing a key:
|
||||
Values: on=''True'', off=''False''
|
||||
|
||||
Leave the review mode when changing the screen (From TTY3 to TTY4):
|
||||
leaveReviewOnScreenChange=True
|
||||
leave_review_on_screen_change=True
|
||||
Values: on=''True'', off=''False''
|
||||
==== Promote ====
|
||||
"Promoted Lists" are configured in the section ''[promote]''.
|
||||
Turn Promoted Lists" on or off:
|
||||
enabled=True
|
||||
Values: on=''True'', off=''False''
|
||||
|
||||
The minimum time interval of inactivity to activate promoting.
|
||||
By default it promotes after 120 Seconds inactivity:
|
||||
inactiveTimeoutSec=120
|
||||
Values: in Seconds
|
||||
|
||||
Define a list of promoted words comma seperated:
|
||||
list=
|
||||
Values: text (comma seperated)
|
||||
Example to promote the word "nickname" or a bash prompt:
|
||||
list=nickname,$:,#:
|
||||
|
||||
==== Time ====
|
||||
The automated time announcement is configured in the section ''[time]''.
|
||||
Time announcement is disabled by default.
|
||||
|
||||
@@ -22,7 +22,7 @@ class command:
|
||||
self.env["runtime"]["MemoryManager"].add_index_list(
|
||||
"clipboardHistory",
|
||||
self.env["runtime"]["SettingsManager"].get_setting_as_int(
|
||||
"general", "numberOfClipboards"
|
||||
"general", "number_of_clipboards"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -36,11 +36,11 @@ class command:
|
||||
def update_spell_language(self):
|
||||
self.spellChecker = enchant.Dict(
|
||||
self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "spellCheckLanguage"
|
||||
"general", "spell_check_language"
|
||||
)
|
||||
)
|
||||
self.language = self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "spellCheckLanguage"
|
||||
"general", "spell_check_language"
|
||||
)
|
||||
|
||||
def run(self):
|
||||
@@ -48,7 +48,7 @@ class command:
|
||||
return
|
||||
if (
|
||||
self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "spellCheckLanguage"
|
||||
"general", "spell_check_language"
|
||||
)
|
||||
!= self.language
|
||||
):
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Fenrir TTY screen reader
|
||||
# By Chrys, Storm Dragon, and contributors.
|
||||
|
||||
|
||||
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 _("Cycle through key echo modes: character, word, off")
|
||||
|
||||
def run(self):
|
||||
settings_manager = self.env["runtime"]["SettingsManager"]
|
||||
output_manager = self.env["runtime"]["OutputManager"]
|
||||
|
||||
# Get current settings
|
||||
char_echo_mode = settings_manager.get_setting("keyboard", "char_echo_mode")
|
||||
word_echo = settings_manager.get_setting_as_bool("keyboard", "word_echo")
|
||||
|
||||
# Determine current state and cycle to next
|
||||
# States: character (char=1, word=False) -> word (char=0, word=True) -> off (char=0, word=False)
|
||||
if char_echo_mode == "1" and not word_echo:
|
||||
# Currently character echo, switch to word echo
|
||||
settings_manager.set_setting("keyboard", "char_echo_mode", "0")
|
||||
settings_manager.set_setting("keyboard", "word_echo", "True")
|
||||
output_manager.present_text(
|
||||
_("Echo by word"), interrupt=True
|
||||
)
|
||||
elif word_echo:
|
||||
# Currently word echo, switch to off
|
||||
settings_manager.set_setting("keyboard", "char_echo_mode", "0")
|
||||
settings_manager.set_setting("keyboard", "word_echo", "False")
|
||||
output_manager.present_text(
|
||||
_("Echo off"), interrupt=True
|
||||
)
|
||||
else:
|
||||
# Currently off (or caps mode), switch to character echo
|
||||
settings_manager.set_setting("keyboard", "char_echo_mode", "1")
|
||||
settings_manager.set_setting("keyboard", "word_echo", "False")
|
||||
output_manager.present_text(
|
||||
_("Echo by character"), interrupt=True
|
||||
)
|
||||
|
||||
def set_callback(self, callback):
|
||||
pass
|
||||
@@ -59,7 +59,7 @@ class command:
|
||||
|
||||
def run(self):
|
||||
current_layout = self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"keyboard", "keyboardLayout"
|
||||
"keyboard", "keyboard_layout"
|
||||
)
|
||||
|
||||
# Extract layout name from full path if needed
|
||||
@@ -83,7 +83,7 @@ class command:
|
||||
|
||||
# Update setting and reload shortcuts
|
||||
self.env["runtime"]["SettingsManager"].set_setting(
|
||||
"keyboard", "keyboardLayout", next_layout
|
||||
"keyboard", "keyboard_layout", next_layout
|
||||
)
|
||||
|
||||
# Reload shortcuts with new layout
|
||||
|
||||
@@ -26,7 +26,7 @@ class command:
|
||||
def run(self):
|
||||
clipboard_file_path = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting("general", "clipboardExportPath")
|
||||
].get_setting("general", "clipboard_export_path")
|
||||
clipboard_file_path = clipboard_file_path.replace(
|
||||
"$user", self.env["general"]["curr_user"]
|
||||
)
|
||||
|
||||
@@ -22,7 +22,7 @@ class command:
|
||||
return _("sends the following keypress to the terminal or application")
|
||||
|
||||
def run(self):
|
||||
self.env["input"]["keyForeward"] = 3
|
||||
self.env["input"]["key_forward"] = 3
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("Forward next keypress"), interrupt=True
|
||||
)
|
||||
|
||||
@@ -26,7 +26,7 @@ class command:
|
||||
def run(self):
|
||||
clipboard_file_path = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting("general", "clipboardExportPath")
|
||||
].get_setting("general", "clipboard_export_path")
|
||||
clipboard_file_path = clipboard_file_path.replace(
|
||||
"$user", self.env["general"]["curr_user"]
|
||||
)
|
||||
|
||||
@@ -18,7 +18,7 @@ class command:
|
||||
self.env["runtime"]["MemoryManager"].add_index_list(
|
||||
"clipboardHistory",
|
||||
self.env["runtime"]["SettingsManager"].get_setting_as_int(
|
||||
"general", "numberOfClipboards"
|
||||
"general", "number_of_clipboards"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -18,17 +18,17 @@ class command:
|
||||
def initialize(self, environment):
|
||||
self.env = environment
|
||||
# Use commandBuffer like other commands
|
||||
if "progressMonitoring" not in self.env["commandBuffer"]:
|
||||
if "progress_monitoring" not in self.env["commandBuffer"]:
|
||||
# Check if progress monitoring should be enabled by default from
|
||||
# settings
|
||||
try:
|
||||
default_enabled = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting_as_bool("sound", "progressMonitoring")
|
||||
].get_setting_as_bool("sound", "progress_monitoring")
|
||||
except Exception as e:
|
||||
# If setting doesn't exist, default to False
|
||||
default_enabled = False
|
||||
self.env["commandBuffer"]["progressMonitoring"] = default_enabled
|
||||
self.env["commandBuffer"]["progress_monitoring"] = default_enabled
|
||||
self.env["commandBuffer"]["lastProgressTime"] = 0
|
||||
self.env["commandBuffer"]["lastProgressValue"] = -1
|
||||
|
||||
@@ -40,12 +40,12 @@ class command:
|
||||
|
||||
def run(self):
|
||||
# Check if commandBuffer exists
|
||||
if "progressMonitoring" not in self.env["commandBuffer"]:
|
||||
self.env["commandBuffer"]["progressMonitoring"] = False
|
||||
if "progress_monitoring" not in self.env["commandBuffer"]:
|
||||
self.env["commandBuffer"]["progress_monitoring"] = False
|
||||
self.env["commandBuffer"]["lastProgressTime"] = 0
|
||||
self.env["commandBuffer"]["lastProgressValue"] = -1
|
||||
|
||||
if self.env["commandBuffer"]["progressMonitoring"]:
|
||||
if self.env["commandBuffer"]["progress_monitoring"]:
|
||||
self.stop_progress_monitoring()
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("Progress monitoring disabled"), interrupt=True
|
||||
@@ -57,17 +57,17 @@ class command:
|
||||
)
|
||||
|
||||
def start_progress_monitoring(self):
|
||||
self.env["commandBuffer"]["progressMonitoring"] = True
|
||||
self.env["commandBuffer"]["progress_monitoring"] = True
|
||||
self.env["commandBuffer"]["lastProgressTime"] = time.time()
|
||||
self.env["commandBuffer"]["lastProgressValue"] = -1
|
||||
# Don't control speech - let user decide with silence_until_prompt
|
||||
|
||||
def stop_progress_monitoring(self):
|
||||
self.env["commandBuffer"]["progressMonitoring"] = False
|
||||
self.env["commandBuffer"]["progress_monitoring"] = False
|
||||
# Don't control speech - progress monitor is beep-only
|
||||
|
||||
def detect_progress(self, text):
|
||||
if not self.env["commandBuffer"]["progressMonitoring"]:
|
||||
if not self.env["commandBuffer"]["progress_monitoring"]:
|
||||
return
|
||||
|
||||
# Skip progress detection if current screen looks like a prompt
|
||||
|
||||
@@ -36,11 +36,11 @@ class command:
|
||||
def update_spell_language(self):
|
||||
self.spellChecker = enchant.Dict(
|
||||
self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "spellCheckLanguage"
|
||||
"general", "spell_check_language"
|
||||
)
|
||||
)
|
||||
self.language = self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "spellCheckLanguage"
|
||||
"general", "spell_check_language"
|
||||
)
|
||||
|
||||
def run(self):
|
||||
@@ -51,7 +51,7 @@ class command:
|
||||
return
|
||||
if (
|
||||
self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "spellCheckLanguage"
|
||||
"general", "spell_check_language"
|
||||
)
|
||||
!= self.language
|
||||
):
|
||||
|
||||
@@ -22,8 +22,8 @@ class command:
|
||||
return _("Interrupts the current presentation")
|
||||
|
||||
def run(self):
|
||||
if len(self.env["input"]["prevDeepestInput"]) > len(
|
||||
self.env["input"]["currInput"]
|
||||
if len(self.env["input"]["prev_deepest_input"]) > len(
|
||||
self.env["input"]["curr_input"]
|
||||
):
|
||||
return
|
||||
self.env["runtime"]["OutputManager"].interrupt_output()
|
||||
|
||||
@@ -36,11 +36,11 @@ class command:
|
||||
return
|
||||
self.spellChecker = enchant.Dict(
|
||||
self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "spellCheckLanguage"
|
||||
"general", "spell_check_language"
|
||||
)
|
||||
)
|
||||
self.language = self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "spellCheckLanguage"
|
||||
"general", "spell_check_language"
|
||||
)
|
||||
|
||||
def run(self):
|
||||
@@ -51,7 +51,7 @@ class command:
|
||||
return
|
||||
if (
|
||||
self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "spellCheckLanguage"
|
||||
"general", "spell_check_language"
|
||||
)
|
||||
!= self.language
|
||||
):
|
||||
|
||||
@@ -25,15 +25,15 @@ class command:
|
||||
def run(self):
|
||||
self.env["runtime"]["SettingsManager"].set_setting(
|
||||
"general",
|
||||
"autoPresentIndent",
|
||||
"auto_present_indent",
|
||||
str(
|
||||
not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"general", "autoPresentIndent"
|
||||
"general", "auto_present_indent"
|
||||
)
|
||||
),
|
||||
)
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"general", "autoPresentIndent"
|
||||
"general", "auto_present_indent"
|
||||
):
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("autoindent enabled"), sound_icon="", interrupt=True
|
||||
|
||||
@@ -25,15 +25,15 @@ class command:
|
||||
def run(self):
|
||||
self.env["runtime"]["SettingsManager"].set_setting(
|
||||
"speech",
|
||||
"autoReadIncoming",
|
||||
"auto_read_incoming",
|
||||
str(
|
||||
not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"speech", "autoReadIncoming"
|
||||
"speech", "auto_read_incoming"
|
||||
)
|
||||
),
|
||||
)
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"speech", "autoReadIncoming"
|
||||
"speech", "auto_read_incoming"
|
||||
):
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("autoread enabled"), sound_icon="", interrupt=True
|
||||
|
||||
@@ -24,15 +24,15 @@ class command:
|
||||
def run(self):
|
||||
self.env["runtime"]["SettingsManager"].set_setting(
|
||||
"general",
|
||||
"autoSpellCheck",
|
||||
"auto_spell_check",
|
||||
str(
|
||||
not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"general", "autoSpellCheck"
|
||||
"general", "auto_spell_check"
|
||||
)
|
||||
),
|
||||
)
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"general", "autoSpellCheck"
|
||||
"general", "auto_spell_check"
|
||||
):
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("auto spellcheck enabled"), sound_icon="", interrupt=True
|
||||
|
||||
@@ -25,7 +25,7 @@ class command:
|
||||
if self.env["runtime"]["PunctuationManager"].cycle_punctuation():
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "punctuationLevel"
|
||||
"general", "punctuation_level"
|
||||
),
|
||||
interrupt=True,
|
||||
ignore_punctuation=True,
|
||||
|
||||
@@ -23,31 +23,31 @@ class command:
|
||||
|
||||
def run(self):
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"keyboard", "interruptOnKeyPress"
|
||||
"keyboard", "interrupt_on_key_press"
|
||||
):
|
||||
return
|
||||
if self.env["runtime"]["InputManager"].no_key_pressed():
|
||||
return
|
||||
if self.env["runtime"]["ScreenManager"].is_screen_change():
|
||||
return
|
||||
if len(self.env["input"]["currInput"]) <= len(
|
||||
self.env["input"]["prevInput"]
|
||||
if len(self.env["input"]["curr_input"]) <= len(
|
||||
self.env["input"]["prev_input"]
|
||||
):
|
||||
return
|
||||
# if the filter is set
|
||||
if (
|
||||
self.env["runtime"]["SettingsManager"]
|
||||
.get_setting("keyboard", "interruptOnKeyPressFilter")
|
||||
.get_setting("keyboard", "interrupt_on_key_press_filter")
|
||||
.strip()
|
||||
!= ""
|
||||
):
|
||||
filter_list = (
|
||||
self.env["runtime"]["SettingsManager"]
|
||||
.get_setting("keyboard", "interruptOnKeyPressFilter")
|
||||
.get_setting("keyboard", "interrupt_on_key_press_filter")
|
||||
.split(",")
|
||||
)
|
||||
for currInput in self.env["input"]["currInput"]:
|
||||
if currInput not in filter_list:
|
||||
for curr_key in self.env["input"]["curr_input"]:
|
||||
if curr_key not in filter_list:
|
||||
return
|
||||
self.env["runtime"]["OutputManager"].interrupt_output()
|
||||
|
||||
|
||||
@@ -24,14 +24,14 @@ class command:
|
||||
def run(self):
|
||||
# enabled?
|
||||
active = self.env["runtime"]["SettingsManager"].get_setting_as_int(
|
||||
"keyboard", "charEchoMode"
|
||||
"keyboard", "char_echo_mode"
|
||||
)
|
||||
# 0 = off
|
||||
if active == 0:
|
||||
return
|
||||
# 2 = caps only
|
||||
if active == 2:
|
||||
if not self.env["input"]["newCapsLock"]:
|
||||
if not self.env["input"]["new_caps_lock"]:
|
||||
return
|
||||
# big changes are no char (but the value is bigger than one maybe the
|
||||
# differ needs longer than you can type, so a little strange random
|
||||
|
||||
@@ -26,7 +26,7 @@ class command:
|
||||
def run(self):
|
||||
# is it enabled?
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"keyboard", "wordEcho"
|
||||
"keyboard", "word_echo"
|
||||
):
|
||||
return
|
||||
# is navigation?
|
||||
|
||||
@@ -39,23 +39,23 @@ class command:
|
||||
return
|
||||
self.spellChecker = enchant.Dict(
|
||||
self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "spellCheckLanguage"
|
||||
"general", "spell_check_language"
|
||||
)
|
||||
)
|
||||
self.language = self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "spellCheckLanguage"
|
||||
"general", "spell_check_language"
|
||||
)
|
||||
|
||||
def run(self):
|
||||
if not initialized:
|
||||
return
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"general", "autoSpellCheck"
|
||||
"general", "auto_spell_check"
|
||||
):
|
||||
return
|
||||
if (
|
||||
self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "spellCheckLanguage"
|
||||
"general", "spell_check_language"
|
||||
)
|
||||
!= self.language
|
||||
):
|
||||
|
||||
@@ -23,7 +23,7 @@ class command:
|
||||
|
||||
def run(self):
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"keyboard", "charDeleteEcho"
|
||||
"keyboard", "char_delete_echo"
|
||||
):
|
||||
return
|
||||
# detect typing or chilling
|
||||
|
||||
+10
-3
@@ -46,7 +46,7 @@ class command:
|
||||
|
||||
# echo word insteed of char
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"keyboard", "wordEcho"
|
||||
"keyboard", "word_echo"
|
||||
):
|
||||
if (
|
||||
abs(
|
||||
@@ -71,6 +71,13 @@ class command:
|
||||
self.env["screen"]["new_cursor"]["y"],
|
||||
self.env["screen"]["new_content_text"],
|
||||
)
|
||||
# Don't interrupt ongoing auto-read announcements
|
||||
do_interrupt = True
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"speech", "auto_read_incoming"
|
||||
):
|
||||
do_interrupt = False
|
||||
|
||||
if curr_char.isspace():
|
||||
# Only announce spaces during pure navigation (arrow keys)
|
||||
# Check if this is really navigation by looking at input history
|
||||
@@ -87,14 +94,14 @@ class command:
|
||||
char_utils.present_char_for_review(
|
||||
self.env,
|
||||
curr_char,
|
||||
interrupt=True,
|
||||
interrupt=do_interrupt,
|
||||
announce_capital=True,
|
||||
flush=False,
|
||||
)
|
||||
else:
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
curr_char,
|
||||
interrupt=True,
|
||||
interrupt=do_interrupt,
|
||||
ignore_punctuation=True,
|
||||
announce_capital=True,
|
||||
flush=False,
|
||||
|
||||
@@ -152,11 +152,18 @@ class command:
|
||||
curr_delta = delta_text
|
||||
if (len(curr_delta.strip()) != len(curr_delta) and curr_delta.strip() != ""):
|
||||
curr_delta = curr_delta.strip()
|
||||
|
||||
|
||||
# Don't interrupt ongoing auto-read announcements
|
||||
do_interrupt = True
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"speech", "auto_read_incoming"
|
||||
):
|
||||
do_interrupt = False
|
||||
|
||||
# Enhanced announcement with better handling of empty completions
|
||||
if curr_delta:
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
curr_delta, interrupt=True, announce_capital=True, flush=False
|
||||
curr_delta, interrupt=do_interrupt, announce_capital=True, flush=False
|
||||
)
|
||||
|
||||
def set_callback(self, callback):
|
||||
|
||||
@@ -66,8 +66,15 @@ class command:
|
||||
):
|
||||
return
|
||||
|
||||
# Don't interrupt ongoing auto-read announcements
|
||||
do_interrupt = True
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"speech", "auto_read_incoming"
|
||||
):
|
||||
do_interrupt = False
|
||||
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
curr_word, interrupt=True, flush=False
|
||||
curr_word, interrupt=do_interrupt, flush=False
|
||||
)
|
||||
|
||||
def set_callback(self, callback):
|
||||
|
||||
+13
-7
@@ -30,8 +30,8 @@ class command:
|
||||
if self.env["runtime"]["ScreenManager"].is_screen_change():
|
||||
self.lastIdent = 0
|
||||
return
|
||||
# this leads to problems in vim -> status line change -> no
|
||||
# announcement, so we do check the lengh as hack
|
||||
# Don't announce cursor movements when auto-read is handling incoming text
|
||||
# This prevents interrupting ongoing auto-read announcements
|
||||
if self.env["runtime"]["ScreenManager"].is_delta():
|
||||
return
|
||||
|
||||
@@ -44,28 +44,34 @@ class command:
|
||||
self.env["screen"]["new_cursor"]["y"],
|
||||
self.env["screen"]["new_content_text"],
|
||||
)
|
||||
# Don't interrupt ongoing auto-read announcements with cursor movement
|
||||
do_interrupt = True
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"speech", "auto_read_incoming"
|
||||
):
|
||||
do_interrupt = False
|
||||
|
||||
if curr_line.isspace():
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("blank"), sound_icon="EmptyLine", interrupt=True, flush=False
|
||||
_("blank"), sound_icon="EmptyLine", interrupt=do_interrupt, flush=False
|
||||
)
|
||||
else:
|
||||
# ident
|
||||
curr_ident = len(curr_line) - len(curr_line.lstrip())
|
||||
if self.lastIdent == -1:
|
||||
self.lastIdent = curr_ident
|
||||
do_interrupt = True
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"general", "autoPresentIndent"
|
||||
"general", "auto_present_indent"
|
||||
):
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_int(
|
||||
"general", "autoPresentIndentMode"
|
||||
"general", "auto_present_indent_mode"
|
||||
) in [0, 1]:
|
||||
if self.lastIdent != curr_ident:
|
||||
self.env["runtime"]["OutputManager"].play_frequence(
|
||||
curr_ident * 50, 0.1, interrupt=do_interrupt
|
||||
)
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_int(
|
||||
"general", "autoPresentIndentMode"
|
||||
"general", "auto_present_indent_mode"
|
||||
) in [0, 2]:
|
||||
if self.lastIdent != curr_ident:
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
|
||||
@@ -68,10 +68,10 @@ class command:
|
||||
|
||||
# Only beep/announce if indentation level has changed
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"general", "autoPresentIndent"
|
||||
"general", "auto_present_indent"
|
||||
) and self.lastIdent != curr_ident:
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_int(
|
||||
"general", "autoPresentIndentMode"
|
||||
"general", "auto_present_indent_mode"
|
||||
) in [0, 1]:
|
||||
self.env["runtime"]["OutputManager"].play_frequence(
|
||||
curr_ident * 50, 0.1, interrupt=False
|
||||
|
||||
@@ -23,7 +23,7 @@ class command:
|
||||
|
||||
def run(self):
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"review", "leaveReviewOnCursorChange"
|
||||
"review", "leave_review_on_cursor_change"
|
||||
):
|
||||
return
|
||||
if self.env["runtime"]["CursorManager"].is_review_mode():
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Fenrir TTY screen reader
|
||||
# By Chrys, Storm Dragon, and contributors.
|
||||
|
||||
import time
|
||||
|
||||
|
||||
class command:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def initialize(self, environment):
|
||||
self.env = environment
|
||||
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
def get_description(self):
|
||||
return ""
|
||||
|
||||
def run(self):
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"speech", "auto_read_incoming"
|
||||
):
|
||||
return
|
||||
|
||||
if "pendingPromptText" not in self.env["commandBuffer"]:
|
||||
return
|
||||
|
||||
pending_text = self.env["commandBuffer"]["pendingPromptText"]
|
||||
if not pending_text:
|
||||
return
|
||||
|
||||
pending_time = self.env["commandBuffer"].get("pendingPromptTime", 0)
|
||||
delay = self.env["runtime"]["SettingsManager"].get_setting_as_float(
|
||||
"speech", "batch_flush_interval"
|
||||
)
|
||||
if time.time() - pending_time < delay:
|
||||
return
|
||||
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
pending_text, interrupt=False, flush=False
|
||||
)
|
||||
self.env["commandBuffer"]["pendingPromptText"] = ""
|
||||
|
||||
def set_callback(self, callback):
|
||||
pass
|
||||
@@ -22,31 +22,31 @@ class command:
|
||||
|
||||
def run(self):
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"keyboard", "interruptOnKeyPress"
|
||||
"keyboard", "interrupt_on_key_press"
|
||||
):
|
||||
return
|
||||
if self.env["runtime"]["InputManager"].no_key_pressed():
|
||||
return
|
||||
if self.env["runtime"]["ScreenManager"].is_screen_change():
|
||||
return
|
||||
if len(self.env["input"]["currInput"]) <= len(
|
||||
self.env["input"]["prevInput"]
|
||||
if len(self.env["input"]["curr_input"]) <= len(
|
||||
self.env["input"]["prev_input"]
|
||||
):
|
||||
return
|
||||
# if the filter is set
|
||||
if (
|
||||
self.env["runtime"]["SettingsManager"]
|
||||
.get_setting("keyboard", "interruptOnKeyPressFilter")
|
||||
.get_setting("keyboard", "interrupt_on_key_press_filter")
|
||||
.strip()
|
||||
!= ""
|
||||
):
|
||||
filter_list = (
|
||||
self.env["runtime"]["SettingsManager"]
|
||||
.get_setting("keyboard", "interruptOnKeyPressFilter")
|
||||
.get_setting("keyboard", "interrupt_on_key_press_filter")
|
||||
.split(",")
|
||||
)
|
||||
for currInput in self.env["input"]["currInput"]:
|
||||
if currInput not in filter_list:
|
||||
for curr_key in self.env["input"]["curr_input"]:
|
||||
if curr_key not in filter_list:
|
||||
return
|
||||
self.env["runtime"]["OutputManager"].interrupt_output()
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ class command:
|
||||
def run(self):
|
||||
if self.env["runtime"]["InputManager"].no_key_pressed():
|
||||
return
|
||||
if len(self.env["input"]["prevInput"]) > 0:
|
||||
if len(self.env["input"]["prev_input"]) > 0:
|
||||
return
|
||||
if not self.env["commandBuffer"]["enableSpeechOnKeypress"]:
|
||||
return
|
||||
|
||||
@@ -23,11 +23,11 @@ class command:
|
||||
|
||||
def run(self):
|
||||
if (
|
||||
self.env["input"]["oldCapsLock"]
|
||||
== self.env["input"]["newCapsLock"]
|
||||
self.env["input"]["old_caps_lock"]
|
||||
== self.env["input"]["new_caps_lock"]
|
||||
):
|
||||
return
|
||||
if self.env["input"]["newCapsLock"]:
|
||||
if self.env["input"]["new_caps_lock"]:
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("Capslock on"), interrupt=True
|
||||
)
|
||||
|
||||
@@ -23,11 +23,11 @@ class command:
|
||||
|
||||
def run(self):
|
||||
if (
|
||||
self.env["input"]["oldScrollLock"]
|
||||
== self.env["input"]["newScrollLock"]
|
||||
self.env["input"]["old_scroll_lock"]
|
||||
== self.env["input"]["new_scroll_lock"]
|
||||
):
|
||||
return
|
||||
if self.env["input"]["newScrollLock"]:
|
||||
if self.env["input"]["new_scroll_lock"]:
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("Scrolllock on"), interrupt=True
|
||||
)
|
||||
|
||||
@@ -22,12 +22,12 @@ class command:
|
||||
return "No description found"
|
||||
|
||||
def run(self):
|
||||
if self.env["input"]["oldNumLock"] == self.env["input"]["newNumLock"]:
|
||||
if self.env["input"]["old_num_lock"] == self.env["input"]["new_num_lock"]:
|
||||
return
|
||||
|
||||
# Only announce numlock changes if an actual numlock key was pressed
|
||||
# AND the LED state actually changed (some numpads send spurious NUMLOCK events)
|
||||
current_input = self.env["input"]["currInput"]
|
||||
current_input = self.env["input"]["curr_input"]
|
||||
|
||||
# Check if this is a genuine numlock key press by verifying:
|
||||
# 1. KEY_NUMLOCK is in the current input sequence
|
||||
@@ -40,7 +40,7 @@ class command:
|
||||
)
|
||||
|
||||
if is_genuine_numlock:
|
||||
if self.env["input"]["newNumLock"]:
|
||||
if self.env["input"]["new_num_lock"]:
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("Numlock on"), interrupt=True
|
||||
)
|
||||
|
||||
@@ -23,7 +23,7 @@ class command:
|
||||
|
||||
def run(self):
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"review", "leaveReviewOnScreenChange"
|
||||
"review", "leave_review_on_screen_change"
|
||||
):
|
||||
return
|
||||
self.env["runtime"]["CursorManager"].clear_review_cursor()
|
||||
|
||||
@@ -25,8 +25,8 @@ class command:
|
||||
# Only run if progress monitoring is enabled
|
||||
try:
|
||||
if (
|
||||
"progressMonitoring" in self.env["commandBuffer"]
|
||||
and self.env["commandBuffer"]["progressMonitoring"]
|
||||
"progress_monitoring" in self.env["commandBuffer"]
|
||||
and self.env["commandBuffer"]["progress_monitoring"]
|
||||
):
|
||||
# Check if current line is a prompt - if so, reset progress
|
||||
# state
|
||||
@@ -40,13 +40,19 @@ class command:
|
||||
):
|
||||
self.detect_progress(self.env["screen"]["new_delta"])
|
||||
except Exception as e:
|
||||
# Silently ignore errors to avoid disrupting normal operation
|
||||
pass
|
||||
# Log errors for debugging instead of silently ignoring
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
"Progress detector error: " + str(e),
|
||||
debug.DebugLevel.ERROR,
|
||||
)
|
||||
|
||||
def is_real_progress_update(self):
|
||||
"""Check if this is a real progress update vs screen change/window switch"""
|
||||
# If the screen/application changed, it's not a progress update
|
||||
if self.env["runtime"]["ScreenManager"].is_screen_change():
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
"Progress filter: screen change detected", debug.DebugLevel.INFO
|
||||
)
|
||||
return False
|
||||
|
||||
# If there was a large cursor movement, it's likely navigation, not
|
||||
@@ -62,6 +68,10 @@ class command:
|
||||
)
|
||||
# Large movements suggest navigation, not progress output
|
||||
if y_move > 2 or x_move > 20:
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
f"Progress filter: large cursor move y={y_move} x={x_move}",
|
||||
debug.DebugLevel.INFO,
|
||||
)
|
||||
return False
|
||||
|
||||
# Check if delta is too large (screen change) vs small incremental
|
||||
@@ -71,16 +81,27 @@ class command:
|
||||
if (
|
||||
delta_length > 200
|
||||
): # Allow longer progress lines like Claude Code's status
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
f"Progress filter: delta too long ({delta_length})",
|
||||
debug.DebugLevel.INFO,
|
||||
)
|
||||
return False
|
||||
|
||||
# If delta contains newlines and is substantial, let incoming handler
|
||||
# deal with it to avoid interfering with multi-line text output
|
||||
if '\n' in delta_text and delta_length > 50:
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
f"Progress filter: multiline delta ({delta_length} chars)",
|
||||
debug.DebugLevel.INFO,
|
||||
)
|
||||
return False
|
||||
|
||||
# Check if current line looks like a prompt - progress unlikely during
|
||||
# prompts
|
||||
if self.is_current_line_prompt():
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
"Progress filter: prompt detected", debug.DebugLevel.INFO
|
||||
)
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -284,10 +305,61 @@ class command:
|
||||
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
||||
return
|
||||
|
||||
# Pattern 6: Claude Code progress indicators
|
||||
claude_progress_match = re.search(r'[·✶✢✻✽*].*?\(esc to interrupt[^)]*\)', text)
|
||||
# Pattern 6: Claude Code working indicators (various symbols + activity text + "esc/ctrl+c to interrupt")
|
||||
# Matches any: [symbol] [Task description]… (... to interrupt ...)
|
||||
# Symbols include: * ✢ ✽ ✶ ✻ · • ◦ ○ ● ◆ and similar decorative characters
|
||||
# Example: ✽ Reviewing script for issues… (ctrl+c to interrupt · 33s · ↑ 1.6k tokens · thought for 4s)
|
||||
claude_progress_match = re.search(
|
||||
r'[*✢✽✶✻·•◦○●◆]\s+\w+.*?…\s*\(.*(?:esc|ctrl\+c) to interrupt.*\)',
|
||||
text,
|
||||
re.IGNORECASE,
|
||||
)
|
||||
if claude_progress_match:
|
||||
if current_time - self.env["commandBuffer"]["lastProgressTime"] >= 1.0:
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
"Playing Claude Code activity beep",
|
||||
debug.DebugLevel.INFO,
|
||||
)
|
||||
self.play_activity_beep()
|
||||
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
||||
return
|
||||
|
||||
# Pattern 6b: Claude Code tool invocation indicators (● Tool Name(...))
|
||||
# Example: ● Web Search("query here")
|
||||
tool_invocation_match = re.search(
|
||||
r'[●○◉•◦]\s+(?:Web\s*Search|Read|Write|Edit|Bash|Glob|Grep|Task|WebFetch)\s*\(',
|
||||
text,
|
||||
re.IGNORECASE,
|
||||
)
|
||||
if tool_invocation_match:
|
||||
if current_time - self.env["commandBuffer"]["lastProgressTime"] >= 1.0:
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
"Playing Claude Code tool invocation beep",
|
||||
debug.DebugLevel.INFO,
|
||||
)
|
||||
self.play_activity_beep()
|
||||
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
||||
return
|
||||
|
||||
# Pattern 6c: Bullet/white bullet activity lines (•/◦ ...)
|
||||
bullet_activity_match = re.search(
|
||||
(
|
||||
r'^\s*[•◦]\s+.*(?:…|\.{3,}|\b(?:thinking|working|processing|'
|
||||
r'analyzing|searching|reading|writing|planning|running|'
|
||||
r'executing|updating|building|installing|compiling|downloading|'
|
||||
r'reviewing|generating|responding|applying|fixing|editing|'
|
||||
r'creating|preparing|checking|opening|loading|fetching|'
|
||||
r'retrieving|scanning|indexing|summarizing)\b)'
|
||||
),
|
||||
text,
|
||||
re.IGNORECASE,
|
||||
)
|
||||
if bullet_activity_match:
|
||||
if current_time - self.env["commandBuffer"]["lastProgressTime"] >= 1.0:
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
"Playing bullet activity beep",
|
||||
debug.DebugLevel.INFO,
|
||||
)
|
||||
self.play_activity_beep()
|
||||
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
||||
return
|
||||
@@ -327,6 +399,23 @@ class command:
|
||||
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
||||
return
|
||||
|
||||
# Pattern 10: Task status indicators (● Task Output, ○ Task Running, etc.)
|
||||
# Matches bullet points with task-related status text
|
||||
task_status_match = re.search(
|
||||
r'[●○◉]\s+(?:Task\s+)?(?:Output|Running|Pending|Working|Processing)\s+[a-zA-Z0-9]+',
|
||||
text,
|
||||
re.IGNORECASE,
|
||||
)
|
||||
if task_status_match:
|
||||
if current_time - self.env["commandBuffer"]["lastProgressTime"] >= 1.5:
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
"Playing task status activity beep",
|
||||
debug.DebugLevel.INFO,
|
||||
)
|
||||
self.play_activity_beep()
|
||||
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
||||
return
|
||||
|
||||
def play_progress_tone(self, percentage):
|
||||
# Map 0-100% to 400-1200Hz frequency range
|
||||
frequency = 400 + (percentage * 8)
|
||||
|
||||
@@ -158,6 +158,16 @@ class command:
|
||||
|
||||
def _restore_speech(self):
|
||||
"""Helper method to restore speech when prompt is detected"""
|
||||
# If speech is already enabled, just clear flags to avoid unnecessary
|
||||
# interrupts on prompt return
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"speech", "enabled"
|
||||
):
|
||||
self.env["commandBuffer"]["silenceUntilPrompt"] = False
|
||||
if "enableSpeechOnKeypress" in self.env["commandBuffer"]:
|
||||
self.env["commandBuffer"]["enableSpeechOnKeypress"] = False
|
||||
return
|
||||
|
||||
# Disable silence mode
|
||||
self.env["commandBuffer"]["silenceUntilPrompt"] = False
|
||||
# Also disable the keypress-based speech restoration since we're
|
||||
|
||||
@@ -10,7 +10,11 @@ from fenrirscreenreader.core.i18n import _
|
||||
|
||||
class command:
|
||||
def __init__(self):
|
||||
pass
|
||||
self._update_times = []
|
||||
self._line_count_times = []
|
||||
self._batched_text = []
|
||||
self._last_flush_time = 0
|
||||
self._in_flood_mode = False
|
||||
|
||||
def initialize(self, environment):
|
||||
self.env = environment
|
||||
@@ -21,6 +25,73 @@ class command:
|
||||
def get_description(self):
|
||||
return _("Announces incoming text changes")
|
||||
|
||||
def _reset_flood_state(self):
|
||||
self._update_times = []
|
||||
self._line_count_times = []
|
||||
self._batched_text = []
|
||||
self._last_flush_time = 0
|
||||
self._in_flood_mode = False
|
||||
|
||||
def _is_rapid_updates(self):
|
||||
current_time = time.time()
|
||||
window = self.env["runtime"]["SettingsManager"].get_setting_as_float(
|
||||
"speech", "rapid_update_window"
|
||||
)
|
||||
threshold = self.env["runtime"]["SettingsManager"].get_setting_as_int(
|
||||
"speech", "rapid_update_threshold"
|
||||
)
|
||||
|
||||
self._update_times = [
|
||||
ts for ts in self._update_times if current_time - ts < window
|
||||
]
|
||||
self._update_times.append(current_time)
|
||||
|
||||
return len(self._update_times) >= threshold
|
||||
|
||||
def _is_high_volume(self, delta_text):
|
||||
current_time = time.time()
|
||||
window = self.env["runtime"]["SettingsManager"].get_setting_as_float(
|
||||
"speech", "rapid_update_window"
|
||||
)
|
||||
threshold = self.env["runtime"]["SettingsManager"].get_setting_as_int(
|
||||
"speech", "flood_line_threshold"
|
||||
)
|
||||
|
||||
line_count = max(1, delta_text.count("\n") + 1)
|
||||
self._line_count_times = [
|
||||
(ts, count)
|
||||
for ts, count in self._line_count_times
|
||||
if current_time - ts < window
|
||||
]
|
||||
self._line_count_times.append((current_time, line_count))
|
||||
|
||||
total_lines = sum(count for _, count in self._line_count_times)
|
||||
return total_lines >= threshold
|
||||
|
||||
def _add_to_batch(self, text):
|
||||
new_lines = text.splitlines()
|
||||
if text.endswith("\n"):
|
||||
new_lines.append("")
|
||||
self._batched_text.extend(new_lines)
|
||||
|
||||
max_lines = self.env["runtime"]["SettingsManager"].get_setting_as_int(
|
||||
"speech", "max_batch_lines"
|
||||
)
|
||||
if len(self._batched_text) > max_lines:
|
||||
self._batched_text = self._batched_text[-max_lines:]
|
||||
|
||||
def _flush_batch(self):
|
||||
if not self._batched_text:
|
||||
return
|
||||
|
||||
text = "\n".join(self._batched_text)
|
||||
self._batched_text = []
|
||||
self._last_flush_time = time.time()
|
||||
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
text, interrupt=False, flush=False
|
||||
)
|
||||
|
||||
def _was_handled_by_tab_completion(self, delta_text):
|
||||
"""Check if this delta was already handled by tab completion to avoid duplicates"""
|
||||
if "tabCompletion" not in self.env["commandBuffer"]:
|
||||
@@ -42,7 +113,7 @@ class command:
|
||||
|
||||
def run(self):
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"speech", "autoReadIncoming"
|
||||
"speech", "auto_read_incoming"
|
||||
):
|
||||
return
|
||||
# is there something to read?
|
||||
@@ -50,6 +121,9 @@ class command:
|
||||
return
|
||||
|
||||
delta_text = self.env["screen"]["new_delta"]
|
||||
|
||||
if self.env["runtime"]["ScreenManager"].is_screen_change():
|
||||
self._reset_flood_state()
|
||||
|
||||
# Skip if tab completion already handled this delta
|
||||
if self._was_handled_by_tab_completion(delta_text):
|
||||
@@ -71,6 +145,29 @@ class command:
|
||||
# <= 2:
|
||||
if "\n" not in delta_text:
|
||||
return
|
||||
|
||||
rapid = self._is_rapid_updates()
|
||||
high_volume = self._is_high_volume(delta_text)
|
||||
|
||||
if (rapid and high_volume) or self._in_flood_mode:
|
||||
if not self._in_flood_mode:
|
||||
self._last_flush_time = time.time()
|
||||
self._in_flood_mode = True
|
||||
|
||||
self._add_to_batch(delta_text)
|
||||
|
||||
interval = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting_as_float("speech", "batch_flush_interval")
|
||||
if time.time() - self._last_flush_time >= interval:
|
||||
self._flush_batch()
|
||||
|
||||
if not rapid or not high_volume:
|
||||
if self._batched_text:
|
||||
self._flush_batch()
|
||||
self._in_flood_mode = False
|
||||
return
|
||||
|
||||
# print(x_move, y_move, len(self.env['screen']['new_delta']), len(self.env['screen']['newNegativeDelta']))
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
delta_text, interrupt=False, flush=False
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import time
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Fenrir TTY screen reader
|
||||
# By Chrys, Storm Dragon, and contributors.
|
||||
|
||||
|
||||
class command:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def initialize(self, environment):
|
||||
self.env = environment
|
||||
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
def get_description(self):
|
||||
return "No Description found"
|
||||
|
||||
def run(self):
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"promote", "enabled"
|
||||
):
|
||||
return
|
||||
if (
|
||||
self.env["runtime"]["SettingsManager"]
|
||||
.get_setting("promote", "list")
|
||||
.strip(" \t\n")
|
||||
== ""
|
||||
):
|
||||
return
|
||||
if int(time.time() - self.env["input"]["lastInputTime"]) < self.env[
|
||||
"runtime"
|
||||
]["SettingsManager"].get_setting_as_int(
|
||||
"promote", "inactiveTimeoutSec"
|
||||
):
|
||||
return
|
||||
if (
|
||||
len(
|
||||
self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"promote", "list"
|
||||
)
|
||||
)
|
||||
== 0
|
||||
):
|
||||
return
|
||||
for promote in (
|
||||
self.env["runtime"]["SettingsManager"]
|
||||
.get_setting("promote", "list")
|
||||
.split(",")
|
||||
):
|
||||
if promote in self.env["screen"]["new_delta"]:
|
||||
self.env["runtime"]["OutputManager"].play_sound_icon(
|
||||
"PromotedText"
|
||||
)
|
||||
self.env["input"]["lastInputTime"] = time.time()
|
||||
return
|
||||
|
||||
def set_callback(self, callback):
|
||||
pass
|
||||
@@ -134,7 +134,7 @@ class config_command:
|
||||
|
||||
self.config.add_section("keyboard")
|
||||
self.config.set("keyboard", "driver", "evdevDriver")
|
||||
self.config.set("keyboard", "keyboardLayout", "desktop")
|
||||
self.config.set("keyboard", "keyboard_layout", "desktop")
|
||||
|
||||
self.config.add_section("screen")
|
||||
self.config.set("screen", "driver", "vcsaDriver")
|
||||
|
||||
+2
-2
@@ -21,13 +21,13 @@ class command(config_command):
|
||||
return "Set punctuation to All (every punctuation mark)"
|
||||
|
||||
def run(self):
|
||||
current_level = self.get_setting("general", "punctuationLevel", "some")
|
||||
current_level = self.get_setting("general", "punctuation_level", "some")
|
||||
|
||||
if current_level.lower() == "all":
|
||||
self.present_text("Punctuation level already set to All")
|
||||
return
|
||||
|
||||
success = self.set_setting("general", "punctuationLevel", "all")
|
||||
success = self.set_setting("general", "punctuation_level", "all")
|
||||
|
||||
if success:
|
||||
self.present_text("Punctuation level set to All - every punctuation mark will be spoken")
|
||||
|
||||
+2
-2
@@ -21,13 +21,13 @@ class command(config_command):
|
||||
return "Set punctuation to Most (detailed punctuation)"
|
||||
|
||||
def run(self):
|
||||
current_level = self.get_setting("general", "punctuationLevel", "some")
|
||||
current_level = self.get_setting("general", "punctuation_level", "some")
|
||||
|
||||
if current_level.lower() == "most":
|
||||
self.present_text("Punctuation level already set to Most")
|
||||
return
|
||||
|
||||
success = self.set_setting("general", "punctuationLevel", "most")
|
||||
success = self.set_setting("general", "punctuation_level", "most")
|
||||
|
||||
if success:
|
||||
self.present_text("Punctuation level set to Most - detailed punctuation will be spoken")
|
||||
|
||||
+2
-2
@@ -21,13 +21,13 @@ class command(config_command):
|
||||
return "Set punctuation to None (no punctuation spoken)"
|
||||
|
||||
def run(self):
|
||||
current_level = self.get_setting("general", "punctuationLevel", "some")
|
||||
current_level = self.get_setting("general", "punctuation_level", "some")
|
||||
|
||||
if current_level.lower() == "none":
|
||||
self.present_text("Punctuation level already set to None")
|
||||
return
|
||||
|
||||
success = self.set_setting("general", "punctuationLevel", "none")
|
||||
success = self.set_setting("general", "punctuation_level", "none")
|
||||
|
||||
if success:
|
||||
self.present_text("Punctuation level set to None - no punctuation will be spoken")
|
||||
|
||||
+2
-2
@@ -21,13 +21,13 @@ class command(config_command):
|
||||
return "Set punctuation to Some (basic punctuation only)"
|
||||
|
||||
def run(self):
|
||||
current_level = self.get_setting("general", "punctuationLevel", "some")
|
||||
current_level = self.get_setting("general", "punctuation_level", "some")
|
||||
|
||||
if current_level.lower() == "some":
|
||||
self.present_text("Punctuation level already set to Some")
|
||||
return
|
||||
|
||||
success = self.set_setting("general", "punctuationLevel", "some")
|
||||
success = self.set_setting("general", "punctuation_level", "some")
|
||||
|
||||
if success:
|
||||
self.present_text("Punctuation level set to Some - basic punctuation will be spoken")
|
||||
|
||||
+2
-2
@@ -21,13 +21,13 @@ class command(config_command):
|
||||
return "Set character echo to Always (echo all typed characters)"
|
||||
|
||||
def run(self):
|
||||
current_mode = self.get_setting("keyboard", "charEchoMode", "1")
|
||||
current_mode = self.get_setting("keyboard", "char_echo_mode", "1")
|
||||
|
||||
if current_mode == "1":
|
||||
self.present_text("Character echo already set to Always")
|
||||
return
|
||||
|
||||
success = self.set_setting("keyboard", "charEchoMode", "1")
|
||||
success = self.set_setting("keyboard", "char_echo_mode", "1")
|
||||
|
||||
if success:
|
||||
self.present_text("Character echo set to Always - all typed characters will be spoken")
|
||||
|
||||
+2
-2
@@ -21,13 +21,13 @@ class command(config_command):
|
||||
return "Set character echo to Caps Lock (echo only when caps lock is on)"
|
||||
|
||||
def run(self):
|
||||
current_mode = self.get_setting("keyboard", "charEchoMode", "1")
|
||||
current_mode = self.get_setting("keyboard", "char_echo_mode", "1")
|
||||
|
||||
if current_mode == "2":
|
||||
self.present_text("Character echo already set to Caps Lock mode")
|
||||
return
|
||||
|
||||
success = self.set_setting("keyboard", "charEchoMode", "2")
|
||||
success = self.set_setting("keyboard", "char_echo_mode", "2")
|
||||
|
||||
if success:
|
||||
self.present_text("Character echo set to Caps Lock mode - characters will be spoken only when caps lock is on")
|
||||
|
||||
+2
-2
@@ -21,13 +21,13 @@ class command(config_command):
|
||||
return "Set character echo to None (no character echo)"
|
||||
|
||||
def run(self):
|
||||
current_mode = self.get_setting("keyboard", "charEchoMode", "1")
|
||||
current_mode = self.get_setting("keyboard", "char_echo_mode", "1")
|
||||
|
||||
if current_mode == "0":
|
||||
self.present_text("Character echo already set to None")
|
||||
return
|
||||
|
||||
success = self.set_setting("keyboard", "charEchoMode", "0")
|
||||
success = self.set_setting("keyboard", "char_echo_mode", "0")
|
||||
|
||||
if success:
|
||||
self.present_text("Character echo set to None - no typed characters will be spoken")
|
||||
|
||||
+2
-2
@@ -21,8 +21,8 @@ class command(config_command):
|
||||
return "Toggle exclusive keyboard access"
|
||||
|
||||
def run(self):
|
||||
current_state = self.getBooleanSetting("keyboard", "grabDevices", True)
|
||||
new_state = self.toggleBooleanSetting("keyboard", "grabDevices")
|
||||
current_state = self.getBooleanSetting("keyboard", "grab_devices", True)
|
||||
new_state = self.toggleBooleanSetting("keyboard", "grab_devices")
|
||||
|
||||
if new_state != current_state:
|
||||
state_text = "enabled" if new_state else "disabled"
|
||||
|
||||
+2
-2
@@ -21,8 +21,8 @@ class command(config_command):
|
||||
return "Toggle word echo when pressing space"
|
||||
|
||||
def run(self):
|
||||
current_state = self.getBooleanSetting("keyboard", "wordEcho", False)
|
||||
new_state = self.toggleBooleanSetting("keyboard", "wordEcho")
|
||||
current_state = self.getBooleanSetting("keyboard", "word_echo", False)
|
||||
new_state = self.toggleBooleanSetting("keyboard", "word_echo")
|
||||
|
||||
if new_state != current_state:
|
||||
state_text = "enabled" if new_state else "disabled"
|
||||
|
||||
+7
-7
@@ -108,7 +108,7 @@ class command(config_command):
|
||||
"rate": "0.5",
|
||||
"pitch": "0.5",
|
||||
"volume": "1.0",
|
||||
"autoReadIncoming": "True",
|
||||
"auto_read_incoming": "True",
|
||||
}
|
||||
|
||||
# Basic sound defaults
|
||||
@@ -123,10 +123,10 @@ class command(config_command):
|
||||
self.config["keyboard"] = {
|
||||
"driver": "evdevDriver",
|
||||
"device": "ALL",
|
||||
"keyboardLayout": "desktop",
|
||||
"charEchoMode": "1",
|
||||
"wordEcho": "False",
|
||||
"charDeleteEcho": "True",
|
||||
"keyboard_layout": "desktop",
|
||||
"char_echo_mode": "1",
|
||||
"word_echo": "False",
|
||||
"char_delete_echo": "True",
|
||||
}
|
||||
|
||||
# Basic screen defaults
|
||||
@@ -137,9 +137,9 @@ class command(config_command):
|
||||
|
||||
# Basic general defaults
|
||||
self.config["general"] = {
|
||||
"punctuationLevel": "some",
|
||||
"punctuation_level": "some",
|
||||
"debug_level": "0",
|
||||
"numberOfClipboards": "50",
|
||||
"number_of_clipboards": "50",
|
||||
}
|
||||
|
||||
# Write the configuration
|
||||
|
||||
@@ -112,7 +112,7 @@ class ByteManager:
|
||||
if self.lastByteKey == converted_escape_sequence:
|
||||
if time.time() - self.lastInputTime <= self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting_as_float("keyboard", "doubleTapTimeout"):
|
||||
].get_setting_as_float("keyboard", "double_tap_timeout"):
|
||||
self.repeat += 1
|
||||
shortcut_data = b""
|
||||
for i in range(self.repeat):
|
||||
|
||||
@@ -21,7 +21,7 @@ class CursorManager:
|
||||
Return False if numlock is ON (let keys type numbers)
|
||||
"""
|
||||
# Return False if numlock is ON
|
||||
return not self.env["input"]["newNumLock"]
|
||||
return not self.env["input"]["new_num_lock"]
|
||||
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
@@ -29,7 +29,7 @@ class DynamicKeyboardLayoutCommand:
|
||||
try:
|
||||
settingsManager = self.env["runtime"]["SettingsManager"]
|
||||
currentLayout = settingsManager.get_setting(
|
||||
"keyboard", "keyboardLayout"
|
||||
"keyboard", "keyboard_layout"
|
||||
)
|
||||
|
||||
# Check if already set (compare both full path and base name)
|
||||
@@ -44,7 +44,7 @@ class DynamicKeyboardLayoutCommand:
|
||||
try:
|
||||
# Update the setting in memory
|
||||
settingsManager.set_setting(
|
||||
"keyboard", "keyboardLayout", self.layoutPath
|
||||
"keyboard", "keyboard_layout", self.layoutPath
|
||||
)
|
||||
|
||||
# Save to the actual config file
|
||||
@@ -162,7 +162,7 @@ def get_keyboard_layouts(env):
|
||||
# Get current layout setting path
|
||||
try:
|
||||
currentLayoutSetting = env["runtime"]["SettingsManager"].get_setting(
|
||||
"keyboard", "keyboardLayout"
|
||||
"keyboard", "keyboard_layout"
|
||||
)
|
||||
if currentLayoutSetting and os.path.exists(currentLayoutSetting):
|
||||
currentLayoutDir = os.path.dirname(currentLayoutSetting)
|
||||
|
||||
@@ -17,8 +17,7 @@ from fenrirscreenreader.core.eventData import FenrirEventType
|
||||
class EventManager:
|
||||
def __init__(self):
|
||||
self.running = Value(c_bool, True)
|
||||
# Bounded queue to prevent memory exhaustion
|
||||
self._eventQueue = Queue(maxsize=100)
|
||||
self._eventQueue = Queue()
|
||||
self.clean_event_queue()
|
||||
|
||||
def initialize(self, environment):
|
||||
@@ -107,23 +106,5 @@ class EventManager:
|
||||
return False
|
||||
if event == FenrirEventType.ignore:
|
||||
return False
|
||||
# Use bounded queue - if full, this will block briefly or drop older
|
||||
# events
|
||||
try:
|
||||
self._eventQueue.put({"Type": event, "data": data}, timeout=0.1)
|
||||
except Exception as e:
|
||||
# Queue full - drop oldest event and add new one for critical
|
||||
# events
|
||||
if event in [
|
||||
FenrirEventType.screen_update,
|
||||
FenrirEventType.keyboard_input,
|
||||
]:
|
||||
try:
|
||||
self._eventQueue.get_nowait() # Remove oldest
|
||||
self._eventQueue.put(
|
||||
{"Type": event, "data": data}, timeout=0.1
|
||||
)
|
||||
except BaseException:
|
||||
pass # If still can't add, drop the event
|
||||
# For non-critical events, just drop them if queue is full
|
||||
self._eventQueue.put({"Type": event, "data": data})
|
||||
return True
|
||||
|
||||
@@ -69,9 +69,9 @@ class FenrirManager:
|
||||
].get_input_event()
|
||||
|
||||
if event["data"]:
|
||||
event["data"]["EventName"] = self.environment["runtime"][
|
||||
event["data"]["event_name"] = self.environment["runtime"][
|
||||
"InputManager"
|
||||
].convert_event_name(event["data"]["EventName"])
|
||||
].convert_event_name(event["data"]["event_name"])
|
||||
self.environment["runtime"]["InputManager"].handle_input_event(
|
||||
event["data"]
|
||||
)
|
||||
@@ -121,8 +121,8 @@ class FenrirManager:
|
||||
self.environment["runtime"]["InputManager"].write_event_buffer()
|
||||
self.environment["runtime"]["InputManager"].handle_device_grab()
|
||||
|
||||
if self.environment["input"]["keyForeward"] > 0:
|
||||
self.environment["input"]["keyForeward"] -= 1
|
||||
if self.environment["input"]["key_forward"] > 0:
|
||||
self.environment["input"]["key_forward"] -= 1
|
||||
|
||||
self.environment["runtime"]["CommandManager"].execute_default_trigger(
|
||||
"onKeyInput"
|
||||
@@ -265,11 +265,11 @@ class FenrirManager:
|
||||
)
|
||||
|
||||
def detect_shortcut_command(self):
|
||||
if self.environment["input"]["keyForeward"] > 0:
|
||||
if self.environment["input"]["key_forward"] > 0:
|
||||
return
|
||||
|
||||
if len(self.environment["input"]["prevInput"]) > len(
|
||||
self.environment["input"]["currInput"]
|
||||
if len(self.environment["input"]["prev_input"]) > len(
|
||||
self.environment["input"]["curr_input"]
|
||||
):
|
||||
return
|
||||
|
||||
@@ -283,7 +283,7 @@ class FenrirManager:
|
||||
].no_key_pressed():
|
||||
if self.singleKeyCommand:
|
||||
self.singleKeyCommand = (
|
||||
len(self.environment["input"]["currInput"]) == 1
|
||||
len(self.environment["input"]["curr_input"]) == 1
|
||||
)
|
||||
|
||||
if not (
|
||||
|
||||
@@ -9,28 +9,30 @@ import time
|
||||
from fenrirscreenreader.core import debug
|
||||
|
||||
input_data = {
|
||||
"currInput": [],
|
||||
"prevDeepestInput": [],
|
||||
"eventBuffer": [],
|
||||
"curr_input": [],
|
||||
"prev_input": [],
|
||||
"prev_deepest_input": [],
|
||||
"event_buffer": [],
|
||||
"shortcut_repeat": 0,
|
||||
"fenrirKey": [],
|
||||
"scriptKey": [],
|
||||
"keyForeward": 0,
|
||||
"lastInputTime": time.time(),
|
||||
"oldNumLock": True,
|
||||
"newNumLock": True,
|
||||
"oldScrollLock": True,
|
||||
"newScrollLock": True,
|
||||
"oldCapsLock": False,
|
||||
"newCapsLock": False,
|
||||
"fenrir_key": [],
|
||||
"script_key": [],
|
||||
"key_forward": 0,
|
||||
"last_input_time": time.time(),
|
||||
"old_num_lock": True,
|
||||
"new_num_lock": True,
|
||||
"old_scroll_lock": True,
|
||||
"new_scroll_lock": True,
|
||||
"old_caps_lock": False,
|
||||
"new_caps_lock": False,
|
||||
}
|
||||
|
||||
input_event = {
|
||||
"EventName": "",
|
||||
"EventValue": "",
|
||||
"EventSec": 0,
|
||||
"EventUsec": 0,
|
||||
"EventState": 0,
|
||||
"event_name": "",
|
||||
"event_value": "",
|
||||
"event_sec": 0,
|
||||
"event_usec": 0,
|
||||
"event_state": 0,
|
||||
"event_type": 0,
|
||||
}
|
||||
|
||||
key_names = [
|
||||
|
||||
@@ -30,7 +30,7 @@ class InputDriver:
|
||||
def clear_event_buffer(self):
|
||||
if not self._initialized:
|
||||
return
|
||||
del self.env["input"]["eventBuffer"][:]
|
||||
del self.env["input"]["event_buffer"][:]
|
||||
|
||||
def update_input_devices(self, new_devices=None, init=False):
|
||||
if not self._initialized:
|
||||
|
||||
@@ -43,18 +43,18 @@ class InputManager:
|
||||
self.update_input_devices()
|
||||
|
||||
# init LEDs with current state
|
||||
self.env["input"]["newNumLock"] = self.env["runtime"][
|
||||
self.env["input"]["new_num_lock"] = self.env["runtime"][
|
||||
"InputDriver"
|
||||
].get_led_state()
|
||||
self.env["input"]["oldNumLock"] = self.env["input"]["newNumLock"]
|
||||
self.env["input"]["newCapsLock"] = self.env["runtime"][
|
||||
self.env["input"]["old_num_lock"] = self.env["input"]["new_num_lock"]
|
||||
self.env["input"]["new_caps_lock"] = self.env["runtime"][
|
||||
"InputDriver"
|
||||
].get_led_state(1)
|
||||
self.env["input"]["oldCapsLock"] = self.env["input"]["newCapsLock"]
|
||||
self.env["input"]["newScrollLock"] = self.env["runtime"][
|
||||
self.env["input"]["old_caps_lock"] = self.env["input"]["new_caps_lock"]
|
||||
self.env["input"]["new_scroll_lock"] = self.env["runtime"][
|
||||
"InputDriver"
|
||||
].get_led_state(2)
|
||||
self.env["input"]["oldScrollLock"] = self.env["input"]["newScrollLock"]
|
||||
self.env["input"]["old_scroll_lock"] = self.env["input"]["new_scroll_lock"]
|
||||
self.lastDeepestInput = []
|
||||
self.lastEvent = None
|
||||
self.env["input"]["shortcut_repeat"] = 1
|
||||
@@ -84,12 +84,12 @@ class InputManager:
|
||||
self.set_execute_device_grab()
|
||||
if not self.executeDeviceGrab:
|
||||
return
|
||||
if self.env["input"]["eventBuffer"] != []:
|
||||
if self.env["input"]["event_buffer"] != []:
|
||||
return
|
||||
if not self.no_key_pressed():
|
||||
return
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"keyboard", "grabDevices"
|
||||
"keyboard", "grab_devices"
|
||||
):
|
||||
self.executeDeviceGrab = False
|
||||
return
|
||||
@@ -176,75 +176,75 @@ class InputManager:
|
||||
return
|
||||
self.lastEvent = event_data
|
||||
# a hang apears.. try to fix
|
||||
if self.env["input"]["eventBuffer"] == []:
|
||||
if self.env["input"]["currInput"] != []:
|
||||
self.env["input"]["currInput"] = []
|
||||
if self.env["input"]["event_buffer"] == []:
|
||||
if self.env["input"]["curr_input"] != []:
|
||||
self.env["input"]["curr_input"] = []
|
||||
self.env["input"]["shortcut_repeat"] = 1
|
||||
|
||||
self.env["input"]["prevInput"] = self.env["input"]["currInput"].copy()
|
||||
if event_data["EventState"] == 0:
|
||||
if event_data["EventName"] in self.env["input"]["currInput"]:
|
||||
self.env["input"]["currInput"].remove(event_data["EventName"])
|
||||
if len(self.env["input"]["currInput"]) > 1:
|
||||
self.env["input"]["currInput"] = sorted(
|
||||
self.env["input"]["currInput"]
|
||||
self.env["input"]["prev_input"] = self.env["input"]["curr_input"].copy()
|
||||
if event_data["event_state"] == 0:
|
||||
if event_data["event_name"] in self.env["input"]["curr_input"]:
|
||||
self.env["input"]["curr_input"].remove(event_data["event_name"])
|
||||
if len(self.env["input"]["curr_input"]) > 1:
|
||||
self.env["input"]["curr_input"] = sorted(
|
||||
self.env["input"]["curr_input"]
|
||||
)
|
||||
elif len(self.env["input"]["currInput"]) == 0:
|
||||
elif len(self.env["input"]["curr_input"]) == 0:
|
||||
self.env["input"]["shortcut_repeat"] = 1
|
||||
self.lastInputTime = time.time()
|
||||
elif event_data["EventState"] == 1:
|
||||
if not event_data["EventName"] in self.env["input"]["currInput"]:
|
||||
self.env["input"]["currInput"].append(event_data["EventName"])
|
||||
if len(self.env["input"]["currInput"]) > 1:
|
||||
self.env["input"]["currInput"] = sorted(
|
||||
self.env["input"]["currInput"]
|
||||
elif event_data["event_state"] == 1:
|
||||
if not event_data["event_name"] in self.env["input"]["curr_input"]:
|
||||
self.env["input"]["curr_input"].append(event_data["event_name"])
|
||||
if len(self.env["input"]["curr_input"]) > 1:
|
||||
self.env["input"]["curr_input"] = sorted(
|
||||
self.env["input"]["curr_input"]
|
||||
)
|
||||
if len(self.lastDeepestInput) < len(
|
||||
self.env["input"]["currInput"]
|
||||
self.env["input"]["curr_input"]
|
||||
):
|
||||
self.set_last_deepest_input(
|
||||
self.env["input"]["currInput"].copy()
|
||||
self.env["input"]["curr_input"].copy()
|
||||
)
|
||||
elif self.lastDeepestInput == self.env["input"]["currInput"]:
|
||||
elif self.lastDeepestInput == self.env["input"]["curr_input"]:
|
||||
if time.time() - self.lastInputTime <= self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting_as_float("keyboard", "doubleTapTimeout"):
|
||||
].get_setting_as_float("keyboard", "double_tap_timeout"):
|
||||
self.env["input"]["shortcut_repeat"] += 1
|
||||
else:
|
||||
self.env["input"]["shortcut_repeat"] = 1
|
||||
self.handle_led_states(event_data)
|
||||
self.lastInputTime = time.time()
|
||||
elif event_data["EventState"] == 2:
|
||||
elif event_data["event_state"] == 2:
|
||||
self.lastInputTime = time.time()
|
||||
|
||||
self.env["input"]["oldNumLock"] = self.env["input"]["newNumLock"]
|
||||
self.env["input"]["newNumLock"] = self.env["runtime"][
|
||||
self.env["input"]["old_num_lock"] = self.env["input"]["new_num_lock"]
|
||||
self.env["input"]["new_num_lock"] = self.env["runtime"][
|
||||
"InputDriver"
|
||||
].get_led_state()
|
||||
self.env["input"]["oldCapsLock"] = self.env["input"]["newCapsLock"]
|
||||
self.env["input"]["newCapsLock"] = self.env["runtime"][
|
||||
self.env["input"]["old_caps_lock"] = self.env["input"]["new_caps_lock"]
|
||||
self.env["input"]["new_caps_lock"] = self.env["runtime"][
|
||||
"InputDriver"
|
||||
].get_led_state(1)
|
||||
self.env["input"]["oldScrollLock"] = self.env["input"]["newScrollLock"]
|
||||
self.env["input"]["newScrollLock"] = self.env["runtime"][
|
||||
self.env["input"]["old_scroll_lock"] = self.env["input"]["new_scroll_lock"]
|
||||
self.env["input"]["new_scroll_lock"] = self.env["runtime"][
|
||||
"InputDriver"
|
||||
].get_led_state(2)
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
"currInput " + str(self.env["input"]["currInput"]),
|
||||
"curr_input " + str(self.env["input"]["curr_input"]),
|
||||
debug.DebugLevel.INFO,
|
||||
)
|
||||
if self.no_key_pressed():
|
||||
self.env["input"]["prevInput"] = []
|
||||
self.env["input"]["prev_input"] = []
|
||||
|
||||
def handle_led_states(self, m_event):
|
||||
if self.curr_key_is_modifier():
|
||||
return
|
||||
try:
|
||||
if m_event["EventName"] == "KEY_NUMLOCK":
|
||||
if m_event["event_name"] == "KEY_NUMLOCK":
|
||||
self.env["runtime"]["InputDriver"].toggle_led_state()
|
||||
elif m_event["EventName"] == "KEY_CAPSLOCK":
|
||||
elif m_event["event_name"] == "KEY_CAPSLOCK":
|
||||
self.env["runtime"]["InputDriver"].toggle_led_state(1)
|
||||
elif m_event["EventName"] == "KEY_SCROLLLOCK":
|
||||
elif m_event["event_name"] == "KEY_SCROLLLOCK":
|
||||
self.env["runtime"]["InputDriver"].toggle_led_state(2)
|
||||
except Exception as e:
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
@@ -255,7 +255,7 @@ class InputManager:
|
||||
|
||||
def grab_all_devices(self):
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"keyboard", "grabDevices"
|
||||
"keyboard", "grab_devices"
|
||||
):
|
||||
try:
|
||||
return self.env["runtime"]["InputDriver"].grab_all_devices()
|
||||
@@ -265,7 +265,7 @@ class InputManager:
|
||||
|
||||
def ungrab_all_devices(self):
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"keyboard", "grabDevices"
|
||||
"keyboard", "grab_devices"
|
||||
):
|
||||
try:
|
||||
return self.env["runtime"]["InputDriver"].ungrab_all_devices()
|
||||
@@ -355,7 +355,7 @@ class InputManager:
|
||||
def write_event_buffer(self):
|
||||
try:
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"keyboard", "grabDevices"
|
||||
"keyboard", "grab_devices"
|
||||
):
|
||||
self.env["runtime"]["InputDriver"].write_event_buffer()
|
||||
self.clear_event_buffer()
|
||||
@@ -368,11 +368,11 @@ class InputManager:
|
||||
)
|
||||
|
||||
def no_key_pressed(self):
|
||||
return self.env["input"]["currInput"] == []
|
||||
return self.env["input"]["curr_input"] == []
|
||||
|
||||
def is_key_press(self):
|
||||
return (self.env["input"]["prevInput"] == []) and (
|
||||
self.env["input"]["currInput"] != []
|
||||
return (self.env["input"]["prev_input"] == []) and (
|
||||
self.env["input"]["curr_input"] != []
|
||||
)
|
||||
|
||||
def get_prev_deepest_shortcut(self):
|
||||
@@ -384,7 +384,7 @@ class InputManager:
|
||||
def get_prev_shortcut(self):
|
||||
shortcut = []
|
||||
shortcut.append(self.env["input"]["shortcut_repeat"])
|
||||
shortcut.append(self.env["input"]["prevInput"])
|
||||
shortcut.append(self.env["input"]["prev_input"])
|
||||
return str(shortcut)
|
||||
|
||||
def get_curr_shortcut(self, inputSequence=None):
|
||||
@@ -430,16 +430,16 @@ class InputManager:
|
||||
if not self.env["runtime"][
|
||||
"CursorManager"
|
||||
].should_process_numpad_commands():
|
||||
for key in self.env["input"]["currInput"]:
|
||||
for key in self.env["input"]["curr_input"]:
|
||||
if key in numpad_keys:
|
||||
# Return an empty/invalid shortcut that won't match any
|
||||
# command
|
||||
return "[]"
|
||||
|
||||
shortcut.append(self.env["input"]["currInput"])
|
||||
shortcut.append(self.env["input"]["curr_input"])
|
||||
|
||||
if len(self.env["input"]["prevInput"]) < len(
|
||||
self.env["input"]["currInput"]
|
||||
if len(self.env["input"]["prev_input"]) < len(
|
||||
self.env["input"]["curr_input"]
|
||||
):
|
||||
if self.env["input"][
|
||||
"shortcut_repeat"
|
||||
@@ -447,7 +447,7 @@ class InputManager:
|
||||
shortcut = []
|
||||
self.env["input"]["shortcut_repeat"] = 1
|
||||
shortcut.append(self.env["input"]["shortcut_repeat"])
|
||||
shortcut.append(self.env["input"]["currInput"])
|
||||
shortcut.append(self.env["input"]["curr_input"])
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
"curr_shortcut " + str(shortcut), debug.DebugLevel.INFO
|
||||
)
|
||||
@@ -456,15 +456,15 @@ class InputManager:
|
||||
def curr_key_is_modifier(self):
|
||||
if len(self.get_last_deepest_input()) != 1:
|
||||
return False
|
||||
return (self.env["input"]["currInput"][0] == "KEY_FENRIR") or (
|
||||
self.env["input"]["currInput"][0] == "KEY_SCRIPT"
|
||||
return (self.env["input"]["curr_input"][0] == "KEY_FENRIR") or (
|
||||
self.env["input"]["curr_input"][0] == "KEY_SCRIPT"
|
||||
)
|
||||
|
||||
def is_fenrir_key(self, event_name):
|
||||
return event_name in self.env["input"]["fenrirKey"]
|
||||
return event_name in self.env["input"]["fenrir_key"]
|
||||
|
||||
def is_script_key(self, event_name):
|
||||
return event_name in self.env["input"]["scriptKey"]
|
||||
return event_name in self.env["input"]["script_key"]
|
||||
|
||||
def get_command_for_shortcut(self, shortcut):
|
||||
if not self.shortcut_exists(shortcut):
|
||||
@@ -477,8 +477,8 @@ class InputManager:
|
||||
if not event_data:
|
||||
return
|
||||
key_name = ""
|
||||
if event_data["EventState"] == 1:
|
||||
key_name = event_data["EventName"].lower()
|
||||
if event_data["event_state"] == 1:
|
||||
key_name = event_data["event_name"].lower()
|
||||
if key_name.startswith("key_"):
|
||||
key_name = key_name[4:]
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
@@ -572,7 +572,7 @@ class InputManager:
|
||||
|
||||
# Get current layout path
|
||||
layout_setting = self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"keyboard", "keyboardLayout"
|
||||
"keyboard", "keyboard_layout"
|
||||
)
|
||||
|
||||
# Resolve full path if needed
|
||||
|
||||
@@ -49,7 +49,7 @@ class OutputManager:
|
||||
return
|
||||
if (
|
||||
self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"speech", "readNumbersAsDigits"
|
||||
"speech", "read_numbers_as_digits"
|
||||
)
|
||||
and len(text.strip()) > 1
|
||||
):
|
||||
@@ -65,15 +65,44 @@ class OutputManager:
|
||||
return
|
||||
if (len(text) > 1) and (text.strip(string.whitespace) == ""):
|
||||
return
|
||||
to_announce_capital = announce_capital and text[0].isupper()
|
||||
if to_announce_capital:
|
||||
if self.play_sound_icon("capital", False):
|
||||
to_announce_capital = False
|
||||
is_capital = self._should_announce_capital(text, announce_capital)
|
||||
use_pitch_for_capital = False
|
||||
|
||||
if is_capital:
|
||||
indicator = self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"speech", "capital_indicator"
|
||||
).lower()
|
||||
|
||||
if indicator == "none":
|
||||
pass # No indication
|
||||
elif indicator == "beep":
|
||||
# Play beep with interrupt=True to fix stacking
|
||||
self.play_sound_icon("capital", True)
|
||||
elif indicator == "pitch":
|
||||
use_pitch_for_capital = True
|
||||
elif indicator == "both":
|
||||
self.play_sound_icon("capital", True)
|
||||
use_pitch_for_capital = True
|
||||
else:
|
||||
# Default to pitch for unknown values
|
||||
use_pitch_for_capital = True
|
||||
|
||||
self.last_echo = text
|
||||
self.speak_text(
|
||||
text, interrupt, ignore_punctuation, to_announce_capital, flush
|
||||
text, interrupt, ignore_punctuation, use_pitch_for_capital, flush
|
||||
)
|
||||
|
||||
def _should_announce_capital(self, text, announce_capital):
|
||||
if not announce_capital or not text:
|
||||
return False
|
||||
if len(text) == 1:
|
||||
return text.isupper()
|
||||
if any(char.isspace() for char in text):
|
||||
return False
|
||||
if not any(char.isalpha() for char in text):
|
||||
return False
|
||||
return text.isupper()
|
||||
|
||||
def get_last_echo(self):
|
||||
return self.last_echo
|
||||
|
||||
@@ -157,7 +186,7 @@ class OutputManager:
|
||||
self.env["runtime"]["SpeechDriver"].set_pitch(
|
||||
self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting_as_float("speech", "capitalPitch")
|
||||
].get_setting_as_float("speech", "capital_pitch")
|
||||
)
|
||||
else:
|
||||
self.env["runtime"]["SpeechDriver"].set_pitch(
|
||||
@@ -221,7 +250,7 @@ class OutputManager:
|
||||
|
||||
try:
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"general", "newLinePause"
|
||||
"general", "new_line_pause"
|
||||
):
|
||||
clean_text = text.replace("\n", " , ")
|
||||
else:
|
||||
|
||||
@@ -52,7 +52,7 @@ class PunctuationManager:
|
||||
|
||||
# Check if we should replace undefined punctuation with spaces
|
||||
replace_with_space = self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"general", "replaceUndefinedPunctuationWithSpace"
|
||||
"general", "replace_undefined_punctuation_with_space"
|
||||
)
|
||||
|
||||
# If the setting is disabled, use the old behavior (remove completely)
|
||||
@@ -128,7 +128,7 @@ class PunctuationManager:
|
||||
) and key not in " ":
|
||||
if (
|
||||
self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "respectPunctuationPause"
|
||||
"general", "respect_punctuation_pause"
|
||||
)
|
||||
and len(key) == 1
|
||||
and key in "',.;:?!"
|
||||
@@ -161,13 +161,13 @@ class PunctuationManager:
|
||||
curr_punct_level = ""
|
||||
if (
|
||||
self.env["runtime"]["SettingsManager"]
|
||||
.get_setting("general", "punctuationLevel")
|
||||
.get_setting("general", "punctuation_level")
|
||||
.lower()
|
||||
in self.env["punctuation"]["LEVELDICT"]
|
||||
):
|
||||
curr_punct_level = self.env["punctuation"]["LEVELDICT"][
|
||||
self.env["runtime"]["SettingsManager"]
|
||||
.get_setting("general", "punctuationLevel")
|
||||
.get_setting("general", "punctuation_level")
|
||||
.lower()
|
||||
]
|
||||
else:
|
||||
@@ -183,7 +183,7 @@ class PunctuationManager:
|
||||
try:
|
||||
curr_index = punct_list.index(
|
||||
self.env["runtime"]["SettingsManager"]
|
||||
.get_setting("general", "punctuationLevel")
|
||||
.get_setting("general", "punctuation_level")
|
||||
.lower()
|
||||
) # curr punctuation
|
||||
except Exception as e:
|
||||
@@ -193,7 +193,7 @@ class PunctuationManager:
|
||||
curr_index = 0
|
||||
curr_level = punct_list[curr_index]
|
||||
self.env["runtime"]["SettingsManager"].set_setting(
|
||||
"general", "punctuationLevel", curr_level.lower()
|
||||
"general", "punctuation_level", curr_level.lower()
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ class QuickMenuManager(SpeechHelperMixin):
|
||||
|
||||
# Load base menu from config
|
||||
menu_string = self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"menu", "quickMenu"
|
||||
"menu", "quick_menu"
|
||||
)
|
||||
|
||||
# Dynamically add speech-dispatcher specific items
|
||||
|
||||
@@ -69,7 +69,7 @@ class RemoteManager:
|
||||
|
||||
def handle_settings_change_with_response(self, settings_text):
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"remote", "enableSettingsRemote"
|
||||
"remote", "enable_settings_remote"
|
||||
):
|
||||
return {
|
||||
"success": False,
|
||||
@@ -115,7 +115,7 @@ class RemoteManager:
|
||||
|
||||
def handle_settings_change(self, settings_text):
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"remote", "enableSettingsRemote"
|
||||
"remote", "enable_settings_remote"
|
||||
):
|
||||
return
|
||||
|
||||
@@ -137,7 +137,7 @@ class RemoteManager:
|
||||
|
||||
def handle_command_execution_with_response(self, command_text):
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"remote", "enableCommandRemote"
|
||||
"remote", "enable_command_remote"
|
||||
):
|
||||
return {
|
||||
"success": False,
|
||||
@@ -218,7 +218,7 @@ class RemoteManager:
|
||||
|
||||
def handle_command_execution(self, command_text):
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"remote", "enableCommandRemote"
|
||||
"remote", "enable_command_remote"
|
||||
):
|
||||
return
|
||||
|
||||
@@ -309,7 +309,7 @@ class RemoteManager:
|
||||
def export_clipboard(self):
|
||||
clipboard_file_path = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting("general", "clipboardExportPath")
|
||||
].get_setting("general", "clipboard_export_path")
|
||||
clipboard_file_path = clipboard_file_path.replace(
|
||||
"$user", self.env["general"]["curr_user"]
|
||||
)
|
||||
|
||||
@@ -429,11 +429,11 @@ class ScreenManager:
|
||||
ignore_screens = []
|
||||
fix_ignore_screens = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting("screen", "ignoreScreen")
|
||||
].get_setting("screen", "ignore_screen")
|
||||
if fix_ignore_screens != "":
|
||||
ignore_screens.extend(fix_ignore_screens.split(","))
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"screen", "autodetectIgnoreScreen"
|
||||
"screen", "autodetect_ignore_screen"
|
||||
):
|
||||
ignore_screens.extend(self.env["screen"]["autoIgnoreScreens"])
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
|
||||
@@ -12,59 +12,67 @@ settings_data = {
|
||||
"driver": "genericDriver",
|
||||
"theme": "default",
|
||||
"volume": 1.0,
|
||||
"genericPlayFileCommand": "play -q -v fenrirVolume fenrirSoundFile",
|
||||
"genericFrequencyCommand": "play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence",
|
||||
"generic_play_file_command": "play -q -v fenrirVolume fenrirSoundFile",
|
||||
"generic_frequency_command": "play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence",
|
||||
"progress_monitoring": True,
|
||||
},
|
||||
"speech": {
|
||||
"enabled": True,
|
||||
"driver": "genericDriver",
|
||||
"serverPath": "",
|
||||
"server_path": "",
|
||||
"rate": 0.75,
|
||||
"pitch": 0.5,
|
||||
"capitalPitch": 0.8,
|
||||
"capital_pitch": 0.8,
|
||||
"capital_indicator": "pitch",
|
||||
"volume": 1.0,
|
||||
"module": "",
|
||||
"voice": "en-us",
|
||||
"language": "",
|
||||
"autoReadIncoming": True,
|
||||
"readNumbersAsDigits": False,
|
||||
"genericSpeechCommand": 'espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice "fenrirText"',
|
||||
"fenrirMinVolume": 0,
|
||||
"fenrirMaxVolume": 200,
|
||||
"fenrirMinPitch": 0,
|
||||
"fenrirMaxPitch": 99,
|
||||
"fenrirMinRate": 80,
|
||||
"fenrirMaxRate": 450,
|
||||
"auto_read_incoming": True,
|
||||
"read_numbers_as_digits": False,
|
||||
"rapid_update_threshold": 5,
|
||||
"rapid_update_window": 0.3,
|
||||
"batch_flush_interval": 0.5,
|
||||
"max_batch_lines": 100,
|
||||
"flood_line_threshold": 500,
|
||||
"generic_speech_command": 'espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice "fenrirText"',
|
||||
"fenrir_min_volume": 0,
|
||||
"fenrir_max_volume": 200,
|
||||
"fenrir_min_pitch": 0,
|
||||
"fenrir_max_pitch": 99,
|
||||
"fenrir_min_rate": 80,
|
||||
"fenrir_max_rate": 450,
|
||||
},
|
||||
"screen": {
|
||||
"driver": "vcsaDriver",
|
||||
"encoding": "auto",
|
||||
"screenUpdateDelay": 0.1,
|
||||
"ignoreScreen": "",
|
||||
"autodetectIgnoreScreen": False,
|
||||
"screen_update_delay": 0.1,
|
||||
"ignore_screen": "",
|
||||
"autodetect_ignore_screen": False,
|
||||
},
|
||||
"general": {
|
||||
"debug_level": debug.DebugLevel.DEACTIVE,
|
||||
"debug_mode": "FILE",
|
||||
"debugFile": "",
|
||||
"punctuationProfile": "default",
|
||||
"punctuationLevel": "some",
|
||||
"respectPunctuationPause": True,
|
||||
"replaceUndefinedPunctuationWithSpace": True,
|
||||
"newLinePause": True,
|
||||
"numberOfClipboards": 10,
|
||||
"debug_file": "",
|
||||
"punctuation_profile": "default",
|
||||
"punctuation_level": "some",
|
||||
"respect_punctuation_pause": True,
|
||||
"replace_undefined_punctuation_with_space": True,
|
||||
"new_line_pause": True,
|
||||
"number_of_clipboards": 10,
|
||||
"clipboard_export_path": "/tmp/fenrirClipboard",
|
||||
"emoticons": True,
|
||||
"fenrirKeys": "KEY_KP0,KEY_META",
|
||||
"scriptKeys": "KEY_COMPOSE",
|
||||
"fenrir_keys": "KEY_KP0,KEY_META",
|
||||
"script_keys": "KEY_COMPOSE",
|
||||
"time_format": "%I:%M%P",
|
||||
"date_format": "%A, %B %d, %Y",
|
||||
"autoSpellCheck": False,
|
||||
"spellCheckLanguage": "en_US",
|
||||
"auto_spell_check": False,
|
||||
"spell_check_language": "en_US",
|
||||
"script_path": "/usr/share/fenrirscreenreader/scripts",
|
||||
"command_path": "/usr/share/fenrirscreenreader/commands",
|
||||
"attribute_format_string": "Background fenrirBGColor,Foreground fenrirFGColor,fenrirUnderline,fenrirBold,fenrirBlink, Font fenrirFont,Fontsize fenrirFontSize",
|
||||
"autoPresentIndent": False,
|
||||
"autoPresentIndentMode": 1,
|
||||
"auto_present_indent": False,
|
||||
"auto_present_indent_mode": 1,
|
||||
"has_attributes": True,
|
||||
"shell": "",
|
||||
},
|
||||
@@ -77,8 +85,8 @@ settings_data = {
|
||||
"driver": "unixDriver",
|
||||
"port": 22447,
|
||||
"socket_file": "",
|
||||
"enableSettingsRemote": True,
|
||||
"enableCommandRemote": True,
|
||||
"enable_settings_remote": True,
|
||||
"enable_command_remote": True,
|
||||
},
|
||||
"barrier": {
|
||||
"enabled": True,
|
||||
@@ -88,17 +96,12 @@ settings_data = {
|
||||
"review": {
|
||||
"line_break": True,
|
||||
"end_of_screen": True,
|
||||
"leaveReviewOnCursorChange": True,
|
||||
"leaveReviewOnScreenChange": True,
|
||||
"leave_review_on_cursor_change": True,
|
||||
"leave_review_on_screen_change": True,
|
||||
},
|
||||
"menu": {
|
||||
"vmenuPath": "",
|
||||
"quickMenu": "speech#rate;speech#pitch;speech#volume",
|
||||
},
|
||||
"promote": {
|
||||
"enabled": True,
|
||||
"inactiveTimeoutSec": 120,
|
||||
"list": "",
|
||||
"vmenu_path": "",
|
||||
"quick_menu": "speech#rate;speech#pitch;speech#volume",
|
||||
},
|
||||
"time": {
|
||||
"enabled": False,
|
||||
@@ -112,14 +115,14 @@ settings_data = {
|
||||
"keyboard": {
|
||||
"driver": "evdev",
|
||||
"device": "all",
|
||||
"grabDevices": True,
|
||||
"ignoreShortcuts": False,
|
||||
"keyboardLayout": "desktop",
|
||||
"charEchoMode": 2, # while capslock
|
||||
"charDeleteEcho": True,
|
||||
"wordEcho": True,
|
||||
"interruptOnKeyPress": True,
|
||||
"interruptOnKeyPressFilter": "",
|
||||
"doubleTapTimeout": 0.2,
|
||||
"grab_devices": True,
|
||||
"ignore_shortcuts": False,
|
||||
"keyboard_layout": "desktop",
|
||||
"char_echo_mode": 2, # while capslock
|
||||
"char_delete_echo": True,
|
||||
"word_echo": True,
|
||||
"interrupt_on_key_press": True,
|
||||
"interrupt_on_key_press_filter": "",
|
||||
"double_tap_timeout": 0.2,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -282,15 +282,15 @@ class SettingsManager:
|
||||
keys = keys.upper()
|
||||
key_list = keys.split(",")
|
||||
for key in key_list:
|
||||
if key not in self.env["input"]["fenrirKey"]:
|
||||
self.env["input"]["fenrirKey"].append(key)
|
||||
if key not in self.env["input"]["fenrir_key"]:
|
||||
self.env["input"]["fenrir_key"].append(key)
|
||||
|
||||
def set_script_keys(self, keys):
|
||||
keys = keys.upper()
|
||||
key_list = keys.split(",")
|
||||
for key in key_list:
|
||||
if key not in self.env["input"]["scriptKey"]:
|
||||
self.env["input"]["scriptKey"].append(key)
|
||||
if key not in self.env["input"]["script_key"]:
|
||||
self.env["input"]["script_key"].append(key)
|
||||
|
||||
def reset_setting_arg_dict(self):
|
||||
self.settingArgDict = {}
|
||||
@@ -498,7 +498,7 @@ class SettingsManager:
|
||||
# Set PTY driver settings
|
||||
pty_settings = {
|
||||
"screen": {"driver": "ptyDriver"},
|
||||
"keyboard": {"driver": "ptyDriver", "keyboardLayout": "pty"}
|
||||
"keyboard": {"driver": "ptyDriver", "keyboard_layout": "pty"}
|
||||
}
|
||||
for section, settings in pty_settings.items():
|
||||
for key, value in settings.items():
|
||||
@@ -507,12 +507,12 @@ class SettingsManager:
|
||||
self.set_setting("screen", "driver", "ptyDriver")
|
||||
self.set_setting("keyboard", "driver", "evdevDriver")
|
||||
|
||||
self.set_fenrir_keys(self.get_setting("general", "fenrirKeys"))
|
||||
self.set_script_keys(self.get_setting("general", "scriptKeys"))
|
||||
self.set_fenrir_keys(self.get_setting("general", "fenrir_keys"))
|
||||
self.set_script_keys(self.get_setting("general", "script_keys"))
|
||||
|
||||
environment["runtime"]["DebugManager"] = debugManager.DebugManager(
|
||||
self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"general", "debugFile"
|
||||
"general", "debug_file"
|
||||
)
|
||||
)
|
||||
environment["runtime"]["DebugManager"].initialize(environment)
|
||||
@@ -521,7 +521,7 @@ class SettingsManager:
|
||||
environment["runtime"]["force_all_screens"] = True
|
||||
|
||||
if cliArgs.ignore_screen:
|
||||
current_ignore_screen = self.get_setting("screen", "ignoreScreen")
|
||||
current_ignore_screen = self.get_setting("screen", "ignore_screen")
|
||||
if current_ignore_screen:
|
||||
ignore_screens = (
|
||||
current_ignore_screen.split(",") + cliArgs.ignore_screen
|
||||
@@ -529,7 +529,7 @@ class SettingsManager:
|
||||
else:
|
||||
ignore_screens = cliArgs.ignore_screen
|
||||
self.set_setting(
|
||||
"screen", "ignoreScreen", ",".join(ignore_screens)
|
||||
"screen", "ignore_screen", ",".join(ignore_screens)
|
||||
)
|
||||
|
||||
if not os.path.exists(
|
||||
@@ -561,43 +561,43 @@ class SettingsManager:
|
||||
environment["runtime"]["TextManager"].initialize(environment)
|
||||
|
||||
if not os.path.exists(
|
||||
self.get_setting("general", "punctuationProfile")
|
||||
self.get_setting("general", "punctuation_profile")
|
||||
):
|
||||
if os.path.exists(
|
||||
settings_root
|
||||
+ "punctuation/"
|
||||
+ self.get_setting("general", "punctuationProfile")
|
||||
+ self.get_setting("general", "punctuation_profile")
|
||||
):
|
||||
self.set_setting(
|
||||
"general",
|
||||
"punctuationProfile",
|
||||
"punctuation_profile",
|
||||
settings_root
|
||||
+ "punctuation/"
|
||||
+ self.get_setting("general", "punctuationProfile"),
|
||||
+ self.get_setting("general", "punctuation_profile"),
|
||||
)
|
||||
environment["runtime"]["PunctuationManager"].load_dicts(
|
||||
self.get_setting("general", "punctuationProfile")
|
||||
self.get_setting("general", "punctuation_profile")
|
||||
)
|
||||
if os.path.exists(
|
||||
settings_root
|
||||
+ "punctuation/"
|
||||
+ self.get_setting("general", "punctuationProfile")
|
||||
+ self.get_setting("general", "punctuation_profile")
|
||||
+ ".conf"
|
||||
):
|
||||
self.set_setting(
|
||||
"general",
|
||||
"punctuationProfile",
|
||||
"punctuation_profile",
|
||||
settings_root
|
||||
+ "punctuation/"
|
||||
+ self.get_setting("general", "punctuationProfile")
|
||||
+ self.get_setting("general", "punctuation_profile")
|
||||
+ ".conf",
|
||||
)
|
||||
environment["runtime"]["PunctuationManager"].load_dicts(
|
||||
self.get_setting("general", "punctuationProfile")
|
||||
self.get_setting("general", "punctuation_profile")
|
||||
)
|
||||
else:
|
||||
environment["runtime"]["PunctuationManager"].load_dicts(
|
||||
self.get_setting("general", "punctuationProfile")
|
||||
self.get_setting("general", "punctuation_profile")
|
||||
)
|
||||
|
||||
if fenrir_manager:
|
||||
@@ -644,86 +644,86 @@ class SettingsManager:
|
||||
|
||||
if environment["runtime"]["InputManager"].get_shortcut_type() == "KEY":
|
||||
if not os.path.exists(
|
||||
self.get_setting("keyboard", "keyboardLayout")
|
||||
self.get_setting("keyboard", "keyboard_layout")
|
||||
):
|
||||
if os.path.exists(
|
||||
settings_root
|
||||
+ "keyboard/"
|
||||
+ self.get_setting("keyboard", "keyboardLayout")
|
||||
+ self.get_setting("keyboard", "keyboard_layout")
|
||||
):
|
||||
self.set_setting(
|
||||
"keyboard",
|
||||
"keyboardLayout",
|
||||
"keyboard_layout",
|
||||
settings_root
|
||||
+ "keyboard/"
|
||||
+ self.get_setting("keyboard", "keyboardLayout"),
|
||||
+ self.get_setting("keyboard", "keyboard_layout"),
|
||||
)
|
||||
environment["runtime"]["InputManager"].load_shortcuts(
|
||||
self.get_setting("keyboard", "keyboardLayout")
|
||||
self.get_setting("keyboard", "keyboard_layout")
|
||||
)
|
||||
if os.path.exists(
|
||||
settings_root
|
||||
+ "keyboard/"
|
||||
+ self.get_setting("keyboard", "keyboardLayout")
|
||||
+ self.get_setting("keyboard", "keyboard_layout")
|
||||
+ ".conf"
|
||||
):
|
||||
self.set_setting(
|
||||
"keyboard",
|
||||
"keyboardLayout",
|
||||
"keyboard_layout",
|
||||
settings_root
|
||||
+ "keyboard/"
|
||||
+ self.get_setting("keyboard", "keyboardLayout")
|
||||
+ self.get_setting("keyboard", "keyboard_layout")
|
||||
+ ".conf",
|
||||
)
|
||||
environment["runtime"]["InputManager"].load_shortcuts(
|
||||
self.get_setting("keyboard", "keyboardLayout")
|
||||
self.get_setting("keyboard", "keyboard_layout")
|
||||
)
|
||||
else:
|
||||
environment["runtime"]["InputManager"].load_shortcuts(
|
||||
self.get_setting("keyboard", "keyboardLayout")
|
||||
self.get_setting("keyboard", "keyboard_layout")
|
||||
)
|
||||
elif (
|
||||
environment["runtime"]["InputManager"].get_shortcut_type()
|
||||
== "BYTE"
|
||||
):
|
||||
if not os.path.exists(
|
||||
self.get_setting("keyboard", "keyboardLayout")
|
||||
self.get_setting("keyboard", "keyboard_layout")
|
||||
):
|
||||
if os.path.exists(
|
||||
settings_root
|
||||
+ "keyboard/"
|
||||
+ self.get_setting("keyboard", "keyboardLayout")
|
||||
+ self.get_setting("keyboard", "keyboard_layout")
|
||||
):
|
||||
self.set_setting(
|
||||
"keyboard",
|
||||
"keyboardLayout",
|
||||
"keyboard_layout",
|
||||
settings_root
|
||||
+ "keyboard/"
|
||||
+ self.get_setting("keyboard", "keyboardLayout"),
|
||||
+ self.get_setting("keyboard", "keyboard_layout"),
|
||||
)
|
||||
environment["runtime"]["ByteManager"].load_byte_shortcuts(
|
||||
self.get_setting("keyboard", "keyboardLayout")
|
||||
self.get_setting("keyboard", "keyboard_layout")
|
||||
)
|
||||
if os.path.exists(
|
||||
settings_root
|
||||
+ "keyboard/"
|
||||
+ self.get_setting("keyboard", "keyboardLayout")
|
||||
+ self.get_setting("keyboard", "keyboard_layout")
|
||||
+ ".conf"
|
||||
):
|
||||
self.set_setting(
|
||||
"keyboard",
|
||||
"keyboardLayout",
|
||||
"keyboard_layout",
|
||||
settings_root
|
||||
+ "keyboard/"
|
||||
+ self.get_setting("keyboard", "keyboardLayout")
|
||||
+ self.get_setting("keyboard", "keyboard_layout")
|
||||
+ ".conf",
|
||||
)
|
||||
environment["runtime"]["ByteManager"].load_byte_shortcuts(
|
||||
self.get_setting("keyboard", "keyboardLayout")
|
||||
self.get_setting("keyboard", "keyboard_layout")
|
||||
)
|
||||
else:
|
||||
environment["runtime"]["ByteManager"].load_byte_shortcuts(
|
||||
self.get_setting("keyboard", "keyboardLayout")
|
||||
self.get_setting("keyboard", "keyboard_layout")
|
||||
)
|
||||
|
||||
environment["runtime"]["CursorManager"] = cursorManager.CursorManager()
|
||||
|
||||
@@ -40,13 +40,13 @@ class VmenuManager:
|
||||
# if there is no user configuration
|
||||
if (
|
||||
self.env["runtime"]["SettingsManager"].get_setting(
|
||||
"menu", "vmenuPath"
|
||||
"menu", "vmenu_path"
|
||||
)
|
||||
!= ""
|
||||
):
|
||||
self.defaultVMenuPath = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting("menu", "vmenuPath")
|
||||
].get_setting("menu", "vmenu_path")
|
||||
if not self.defaultVMenuPath.endswith("/"):
|
||||
self.defaultVMenuPath += "/"
|
||||
self.defaultVMenuPath += self.env["runtime"][
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
# Fenrir TTY screen reader
|
||||
# By Chrys, Storm Dragon, and contributors.
|
||||
|
||||
version = "2025.12.03"
|
||||
version = "2026.01.10"
|
||||
code_name = "master"
|
||||
|
||||
@@ -41,7 +41,7 @@ class driver(inputDriver):
|
||||
def clear_event_buffer(self):
|
||||
if not self._initialized:
|
||||
return
|
||||
del self.env["input"]["eventBuffer"][:]
|
||||
del self.env["input"]["event_buffer"][:]
|
||||
print("Input Debug Driver: clear_event_buffer")
|
||||
|
||||
def update_input_devices(self, new_devices=None, init=False):
|
||||
|
||||
@@ -259,7 +259,7 @@ class driver(inputDriver):
|
||||
"input_watchdog: EVENT:" + str(event),
|
||||
debug.DebugLevel.INFO,
|
||||
)
|
||||
self.env["input"]["eventBuffer"].append(
|
||||
self.env["input"]["event_buffer"].append(
|
||||
[device, udevice, event]
|
||||
)
|
||||
if event.type == evdev.events.EV_KEY:
|
||||
@@ -271,11 +271,11 @@ class driver(inputDriver):
|
||||
event = device.read_one()
|
||||
continue
|
||||
if not isinstance(
|
||||
curr_map_event["EventName"], str
|
||||
curr_map_event["event_name"], str
|
||||
):
|
||||
event = device.read_one()
|
||||
continue
|
||||
if curr_map_event["EventState"] in [0, 1, 2]:
|
||||
if curr_map_event["event_state"] in [0, 1, 2]:
|
||||
event_queue.put(
|
||||
{
|
||||
"Type": FenrirEventType.keyboard_input,
|
||||
@@ -284,7 +284,8 @@ class driver(inputDriver):
|
||||
)
|
||||
event_fired = True
|
||||
else:
|
||||
if event.type in [2, 3]:
|
||||
# Forward non-keyboard events: 2=EV_REL, 3=EV_ABS, 17=EV_LED
|
||||
if event.type in [2, 3, 17]:
|
||||
foreward = True
|
||||
|
||||
event = device.read_one()
|
||||
@@ -300,7 +301,7 @@ class driver(inputDriver):
|
||||
def write_event_buffer(self):
|
||||
if not self._initialized:
|
||||
return
|
||||
for iDevice, uDevice, event in self.env["input"]["eventBuffer"]:
|
||||
for iDevice, uDevice, event in self.env["input"]["event_buffer"]:
|
||||
try:
|
||||
if uDevice:
|
||||
if self.gDevices[iDevice.fd]:
|
||||
@@ -553,18 +554,18 @@ class driver(inputDriver):
|
||||
m_event = inputData.input_event
|
||||
try:
|
||||
# mute is a list = ['KEY_MIN_INTERESTING', 'KEY_MUTE']
|
||||
m_event["EventName"] = evdev.ecodes.keys[event.code]
|
||||
if isinstance(m_event["EventName"], list):
|
||||
if len(m_event["EventName"]) > 0:
|
||||
m_event["EventName"] = m_event["EventName"][0]
|
||||
if isinstance(m_event["EventName"], list):
|
||||
if len(m_event["EventName"]) > 0:
|
||||
m_event["EventName"] = m_event["EventName"][0]
|
||||
m_event["EventValue"] = event.code
|
||||
m_event["EventSec"] = event.sec
|
||||
m_event["EventUsec"] = event.usec
|
||||
m_event["EventState"] = event.value
|
||||
m_event["EventType"] = event.type
|
||||
m_event["event_name"] = evdev.ecodes.keys[event.code]
|
||||
if isinstance(m_event["event_name"], list):
|
||||
if len(m_event["event_name"]) > 0:
|
||||
m_event["event_name"] = m_event["event_name"][0]
|
||||
if isinstance(m_event["event_name"], list):
|
||||
if len(m_event["event_name"]) > 0:
|
||||
m_event["event_name"] = m_event["event_name"][0]
|
||||
m_event["event_value"] = event.code
|
||||
m_event["event_sec"] = event.sec
|
||||
m_event["event_usec"] = event.usec
|
||||
m_event["event_state"] = event.value
|
||||
m_event["event_type"] = event.type
|
||||
return m_event
|
||||
except Exception as e:
|
||||
return None
|
||||
@@ -622,7 +623,7 @@ class driver(inputDriver):
|
||||
|
||||
def create_u_input_dev(self, fd):
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"keyboard", "grabDevices"
|
||||
"keyboard", "grab_devices"
|
||||
):
|
||||
self.uDevices[fd] = None
|
||||
return
|
||||
@@ -729,7 +730,7 @@ class driver(inputDriver):
|
||||
Only effective if grabDevices setting is enabled.
|
||||
"""
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"keyboard", "grabDevices"
|
||||
"keyboard", "grab_devices"
|
||||
):
|
||||
return True
|
||||
|
||||
@@ -791,7 +792,7 @@ class driver(inputDriver):
|
||||
bool: True if ungrab successful, False otherwise
|
||||
"""
|
||||
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
"keyboard", "grabDevices"
|
||||
"keyboard", "grab_devices"
|
||||
):
|
||||
return True
|
||||
|
||||
|
||||
@@ -48,10 +48,10 @@ class driver(sound_driver):
|
||||
self.env = environment
|
||||
self.soundFileCommand = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting("sound", "genericPlayFileCommand")
|
||||
].get_setting("sound", "generic_play_file_command")
|
||||
self.frequenceCommand = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting("sound", "genericFrequencyCommand")
|
||||
].get_setting("sound", "generic_frequency_command")
|
||||
if self.soundFileCommand == "":
|
||||
self.soundFileCommand = "play -q -v fenrirVolume fenrirSoundFile"
|
||||
if self.frequenceCommand == "":
|
||||
|
||||
@@ -38,26 +38,26 @@ class driver(speech_driver):
|
||||
self.env = environment
|
||||
self.minVolume = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting_as_int("speech", "fenrirMinVolume")
|
||||
].get_setting_as_int("speech", "fenrir_min_volume")
|
||||
self.maxVolume = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting_as_int("speech", "fenrirMaxVolume")
|
||||
].get_setting_as_int("speech", "fenrir_max_volume")
|
||||
self.minPitch = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting_as_int("speech", "fenrirMinPitch")
|
||||
].get_setting_as_int("speech", "fenrir_min_pitch")
|
||||
self.maxPitch = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting_as_int("speech", "fenrirMaxPitch")
|
||||
].get_setting_as_int("speech", "fenrir_max_pitch")
|
||||
self.minRate = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting_as_int("speech", "fenrirMinRate")
|
||||
].get_setting_as_int("speech", "fenrir_min_rate")
|
||||
self.maxRate = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting_as_int("speech", "fenrirMaxRate")
|
||||
].get_setting_as_int("speech", "fenrir_max_rate")
|
||||
|
||||
self.speechCommand = self.env["runtime"][
|
||||
"SettingsManager"
|
||||
].get_setting("speech", "genericSpeechCommand")
|
||||
].get_setting("speech", "generic_speech_command")
|
||||
if self.speechCommand == "":
|
||||
self.speechCommand = 'espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice -- "fenrirText"'
|
||||
if False: # for debugging overwrite here
|
||||
|
||||
Reference in New Issue
Block a user