Merged for wider testing.
This commit is contained in:
@@ -222,7 +222,7 @@ Fenrir supports two main keyboard layouts:
|
|||||||
Configure in `/etc/fenrir/settings/settings.conf`:
|
Configure in `/etc/fenrir/settings/settings.conf`:
|
||||||
```ini
|
```ini
|
||||||
[keyboard]
|
[keyboard]
|
||||||
keyboardLayout=desktop # or 'laptop'
|
keyboard_layout=desktop # or 'laptop'
|
||||||
```
|
```
|
||||||
|
|
||||||
### First Time Setup
|
### First Time Setup
|
||||||
@@ -255,9 +255,9 @@ Enable remote control in `/etc/fenrir/settings/settings.conf`:
|
|||||||
enable=True
|
enable=True
|
||||||
driver=unixDriver # or tcpDriver
|
driver=unixDriver # or tcpDriver
|
||||||
port=22447 # for TCP driver
|
port=22447 # for TCP driver
|
||||||
socketFile= # custom socket path (optional)
|
socket_file= # custom socket path (optional)
|
||||||
enableSettingsRemote=True # allow settings changes
|
enable_settings_remote=True # allow settings changes
|
||||||
enableCommandRemote=True # allow command execution
|
enable_command_remote=True # allow command execution
|
||||||
```
|
```
|
||||||
|
|
||||||
### Remote Drivers
|
### 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
|
echo "setting set speech#volume=0.9" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||||
|
|
||||||
# Change punctuation level (none/some/most/all)
|
# 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
|
||||||
echo "setting set general#punctuationLevel=none" | 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
|
# Voice and TTS engine control
|
||||||
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
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
|
echo "setting set sound#volume=0.5" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||||
|
|
||||||
# Keyboard and input settings
|
# Keyboard and input settings
|
||||||
echo "setting set keyboard#charEchoMode=1" | 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#wordEcho=True" | 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)
|
# 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
|
# 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
|
# Reset all settings to defaults
|
||||||
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
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#voice=voice_name` - Voice selection (e.g., "en-us+f3")
|
||||||
- `speech#module=module_name` - TTS module (e.g., "espeak-ng")
|
- `speech#module=module_name` - TTS module (e.g., "espeak-ng")
|
||||||
- `speech#driver=driver_name` - Speech driver (speechdDriver/genericDriver)
|
- `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 Settings:*
|
||||||
- `sound#enabled=True/False` - Enable/disable sound
|
- `sound#enabled=True/False` - Enable/disable sound
|
||||||
@@ -430,32 +430,32 @@ setting <action> [parameters]
|
|||||||
- `sound#theme=theme_name` - Sound theme
|
- `sound#theme=theme_name` - Sound theme
|
||||||
|
|
||||||
*General Settings:*
|
*General Settings:*
|
||||||
- `general#punctuationLevel=none/some/most/all` - Punctuation verbosity
|
- `general#punctuation_level=none/some/most/all` - Punctuation verbosity
|
||||||
- `general#debugLevel=0-3` - Debug level
|
- `general#debug_level=0-3` - Debug level
|
||||||
- `general#emoticons=True/False` - Enable emoticon replacement
|
- `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 Settings:*
|
||||||
- `focus#cursor=True/False` - Follow text cursor
|
- `focus#cursor=True/False` - Follow text cursor
|
||||||
- `focus#highlight=True/False` - Follow text highlighting
|
- `focus#highlight=True/False` - Follow text highlighting
|
||||||
|
|
||||||
*Keyboard Settings:*
|
*Keyboard Settings:*
|
||||||
- `keyboard#charEchoMode=0-2` - Character echo (0=none, 1=always, 2=capslock only)
|
- `keyboard#char_echo_mode=0-2` - Character echo (0=none, 1=always, 2=capslock only)
|
||||||
- `keyboard#wordEcho=True/False` - Echo complete words
|
- `keyboard#word_echo=True/False` - Echo complete words
|
||||||
- `keyboard#charDeleteEcho=True/False` - Echo deleted characters
|
- `keyboard#char_delete_echo=True/False` - Echo deleted characters
|
||||||
- `keyboard#interruptOnKeyPress=True/False` - Interrupt speech on key press
|
- `keyboard#interrupt_on_key_press=True/False` - Interrupt speech on key press
|
||||||
|
|
||||||
*Screen Settings:*
|
*Screen Settings:*
|
||||||
- `screen#ignoreScreen=1,2,3` - TTY screens to ignore
|
- `screen#ignore_screen=1,2,3` - TTY screens to ignore
|
||||||
- `screen#autodetectIgnoreScreen=True/False` - Auto-detect screens to ignore
|
- `screen#autodetect_ignore_screen=True/False` - Auto-detect screens to ignore
|
||||||
- `screen#screenUpdateDelay=float` - Screen update delay
|
- `screen#screen_update_delay=float` - Screen update delay
|
||||||
|
|
||||||
*Time Settings:*
|
*Time Settings:*
|
||||||
- `time#enabled=True/False` - Enable time announcements
|
- `time#enabled=True/False` - Enable time announcements
|
||||||
- `time#presentTime=True/False` - Announce time
|
- `time#present_time=True/False` - Announce time
|
||||||
- `time#presentDate=True/False` - Announce date changes
|
- `time#present_date=True/False` - Announce date changes
|
||||||
- `time#delaySec=seconds` - Announcement interval
|
- `time#delay_sec=seconds` - Announcement interval
|
||||||
- `time#onMinutes=00,30` - Specific minutes to announce
|
- `time#on_minutes=00,30` - Specific minutes to announce
|
||||||
|
|
||||||
## Table Navigation
|
## Table Navigation
|
||||||
|
|
||||||
@@ -623,7 +623,7 @@ rsync -av source/ destination/ # File synchronization
|
|||||||
### Customization
|
### Customization
|
||||||
|
|
||||||
Progress monitoring can be configured through settings:
|
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)
|
- **Sound integration**: Works with all sound drivers (sox, gstreamer)
|
||||||
- **Remote control**: Enable/disable through remote commands
|
- **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)
|
- TCP driver binds only to localhost (127.0.0.1)
|
||||||
- Socket file permissions are set to write-only (0o222)
|
- Socket file permissions are set to write-only (0o222)
|
||||||
- Commands are processed with Fenrir's privileges
|
- Commands are processed with Fenrir's privileges
|
||||||
- Settings changes can be disabled via `enableSettingsRemote=False`
|
- Settings changes can be disabled via `enable_settings_remote=False`
|
||||||
- Command execution can be disabled via `enableCommandRemote=False`
|
- Command execution can be disabled via `enable_command_remote=False`
|
||||||
|
|
||||||
### Troubleshooting
|
### Troubleshooting
|
||||||
|
|
||||||
@@ -688,7 +688,7 @@ send_fenrir_command("setting set speech#rate=0.9")
|
|||||||
- Ensure remote driver is enabled in settings
|
- Ensure remote driver is enabled in settings
|
||||||
|
|
||||||
**Commands not working:**
|
**Commands not working:**
|
||||||
- Verify `enableCommandRemote=True` in settings
|
- Verify `enable_command_remote=True` in settings
|
||||||
- Check Fenrir debug logs: `/var/log/fenrir.log`
|
- Check Fenrir debug logs: `/var/log/fenrir.log`
|
||||||
- Test with simple command: `echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock`
|
- 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
|
- `-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-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)
|
- `-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.
|
- `-i, -I, --ignore-screen SCREEN` - Ignore specific screen(s). Can be used multiple times. Combines with existing ignore settings.
|
||||||
|
|
||||||
### Examples:
|
### Examples:
|
||||||
@@ -724,7 +724,7 @@ sudo fenrir -e
|
|||||||
# Override settings via command line
|
# Override settings via command line
|
||||||
sudo fenrir -o "speech#rate=0.8;sound#volume=0.5"
|
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
|
sudo fenrir -F
|
||||||
|
|
||||||
# Ignore specific screens
|
# Ignore specific screens
|
||||||
|
|||||||
@@ -3,14 +3,13 @@
|
|||||||
enabled=True
|
enabled=True
|
||||||
|
|
||||||
# Select the driver used to play sounds, choices are genericDriver and gstreamerDriver.
|
# 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.
|
# Gstreamer is the default.
|
||||||
driver=gstreamerDriver
|
driver=gstreamerDriver
|
||||||
#driver=genericDriver
|
#driver=genericDriver
|
||||||
|
|
||||||
# Sound themes. These are the pack of sounds used for sound alerts.
|
# Sound themes. These are the pack of sounds used for sound alerts.
|
||||||
# Sound packs may be located at /usr/share/sounds
|
# Sound packs may be located at /usr/share/sounds
|
||||||
# For system wide availability, or ~/.local/share/fenrirscreenreader/sounds
|
|
||||||
# For the current user.
|
|
||||||
theme=default
|
theme=default
|
||||||
|
|
||||||
# Sound volume controls how loud the sounds for your selected soundpack are.
|
# Sound volume controls how loud the sounds for your selected soundpack are.
|
||||||
@@ -110,8 +109,10 @@ driver=evdevDriver
|
|||||||
device=ALL
|
device=ALL
|
||||||
# gives Fenrir exclusive access to the keyboard and lets it control keystrokes.
|
# gives Fenrir exclusive access to the keyboard and lets it control keystrokes.
|
||||||
grab_devices=True
|
grab_devices=True
|
||||||
ignore_shortcuts=False
|
# 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
|
# the current shortcut layout located in /etc/fenrirscreenreader/keyboard
|
||||||
|
ignore_shortcuts=False
|
||||||
keyboard_layout=desktop
|
keyboard_layout=desktop
|
||||||
# echo chars while typing.
|
# echo chars while typing.
|
||||||
# 0 = None
|
# 0 = None
|
||||||
@@ -138,6 +139,8 @@ debug_level=2
|
|||||||
# debugMode=Print just prints on the screen
|
# debugMode=Print just prints on the screen
|
||||||
debug_mode=File
|
debug_mode=File
|
||||||
debug_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_profile=default
|
||||||
punctuation_level=some
|
punctuation_level=some
|
||||||
respect_punctuation_pause=True
|
respect_punctuation_pause=True
|
||||||
@@ -247,6 +250,11 @@ enabled=True
|
|||||||
inactive_timeout_sec=120
|
inactive_timeout_sec=120
|
||||||
# Comma-separated list of text patterns to promote when detected
|
# Comma-separated list of text patterns to promote when detected
|
||||||
# Leave empty to disable pattern-based promotion
|
# Leave empty to disable pattern-based promotion
|
||||||
|
# Examples:
|
||||||
|
# error,warning,failed - Announce build/command errors
|
||||||
|
# complete,finished,done - Announce task completions
|
||||||
|
# new message,@username - Announce chat notifications
|
||||||
|
# download complete - Announce download completions
|
||||||
list=
|
list=
|
||||||
|
|
||||||
[menu]
|
[menu]
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class command:
|
|||||||
return _("sends the following keypress to the terminal or application")
|
return _("sends the following keypress to the terminal or application")
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.env["input"]["keyForeward"] = 3
|
self.env["input"]["key_forward"] = 3
|
||||||
self.env["runtime"]["OutputManager"].present_text(
|
self.env["runtime"]["OutputManager"].present_text(
|
||||||
_("Forward next keypress"), interrupt=True
|
_("Forward next keypress"), interrupt=True
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ class command:
|
|||||||
return _("Interrupts the current presentation")
|
return _("Interrupts the current presentation")
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if len(self.env["input"]["prevDeepestInput"]) > len(
|
if len(self.env["input"]["prev_deepest_input"]) > len(
|
||||||
self.env["input"]["currInput"]
|
self.env["input"]["curr_input"]
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
self.env["runtime"]["OutputManager"].interrupt_output()
|
self.env["runtime"]["OutputManager"].interrupt_output()
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ class command:
|
|||||||
return
|
return
|
||||||
if self.env["runtime"]["ScreenManager"].is_screen_change():
|
if self.env["runtime"]["ScreenManager"].is_screen_change():
|
||||||
return
|
return
|
||||||
if len(self.env["input"]["currInput"]) <= len(
|
if len(self.env["input"]["curr_input"]) <= len(
|
||||||
self.env["input"]["prevInput"]
|
self.env["input"]["prev_input"]
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
# if the filter is set
|
# if the filter is set
|
||||||
@@ -46,8 +46,8 @@ class command:
|
|||||||
.get_setting("keyboard", "interrupt_on_key_press_filter")
|
.get_setting("keyboard", "interrupt_on_key_press_filter")
|
||||||
.split(",")
|
.split(",")
|
||||||
)
|
)
|
||||||
for currInput in self.env["input"]["currInput"]:
|
for curr_key in self.env["input"]["curr_input"]:
|
||||||
if currInput not in filter_list:
|
if curr_key not in filter_list:
|
||||||
return
|
return
|
||||||
self.env["runtime"]["OutputManager"].interrupt_output()
|
self.env["runtime"]["OutputManager"].interrupt_output()
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class command:
|
|||||||
return
|
return
|
||||||
# 2 = caps only
|
# 2 = caps only
|
||||||
if active == 2:
|
if active == 2:
|
||||||
if not self.env["input"]["newCapsLock"]:
|
if not self.env["input"]["new_caps_lock"]:
|
||||||
return
|
return
|
||||||
# big changes are no char (but the value is bigger than one maybe the
|
# 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
|
# differ needs longer than you can type, so a little strange random
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ class command:
|
|||||||
return
|
return
|
||||||
if self.env["runtime"]["ScreenManager"].is_screen_change():
|
if self.env["runtime"]["ScreenManager"].is_screen_change():
|
||||||
return
|
return
|
||||||
if len(self.env["input"]["currInput"]) <= len(
|
if len(self.env["input"]["curr_input"]) <= len(
|
||||||
self.env["input"]["prevInput"]
|
self.env["input"]["prev_input"]
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
# if the filter is set
|
# if the filter is set
|
||||||
@@ -45,8 +45,8 @@ class command:
|
|||||||
.get_setting("keyboard", "interrupt_on_key_press_filter")
|
.get_setting("keyboard", "interrupt_on_key_press_filter")
|
||||||
.split(",")
|
.split(",")
|
||||||
)
|
)
|
||||||
for currInput in self.env["input"]["currInput"]:
|
for curr_key in self.env["input"]["curr_input"]:
|
||||||
if currInput not in filter_list:
|
if curr_key not in filter_list:
|
||||||
return
|
return
|
||||||
self.env["runtime"]["OutputManager"].interrupt_output()
|
self.env["runtime"]["OutputManager"].interrupt_output()
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class command:
|
|||||||
def run(self):
|
def run(self):
|
||||||
if self.env["runtime"]["InputManager"].no_key_pressed():
|
if self.env["runtime"]["InputManager"].no_key_pressed():
|
||||||
return
|
return
|
||||||
if len(self.env["input"]["prevInput"]) > 0:
|
if len(self.env["input"]["prev_input"]) > 0:
|
||||||
return
|
return
|
||||||
if not self.env["commandBuffer"]["enableSpeechOnKeypress"]:
|
if not self.env["commandBuffer"]["enableSpeechOnKeypress"]:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ class command:
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if (
|
if (
|
||||||
self.env["input"]["oldCapsLock"]
|
self.env["input"]["old_caps_lock"]
|
||||||
== self.env["input"]["newCapsLock"]
|
== self.env["input"]["new_caps_lock"]
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
if self.env["input"]["newCapsLock"]:
|
if self.env["input"]["new_caps_lock"]:
|
||||||
self.env["runtime"]["OutputManager"].present_text(
|
self.env["runtime"]["OutputManager"].present_text(
|
||||||
_("Capslock on"), interrupt=True
|
_("Capslock on"), interrupt=True
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ class command:
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if (
|
if (
|
||||||
self.env["input"]["oldScrollLock"]
|
self.env["input"]["old_scroll_lock"]
|
||||||
== self.env["input"]["newScrollLock"]
|
== self.env["input"]["new_scroll_lock"]
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
if self.env["input"]["newScrollLock"]:
|
if self.env["input"]["new_scroll_lock"]:
|
||||||
self.env["runtime"]["OutputManager"].present_text(
|
self.env["runtime"]["OutputManager"].present_text(
|
||||||
_("Scrolllock on"), interrupt=True
|
_("Scrolllock on"), interrupt=True
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -22,12 +22,12 @@ class command:
|
|||||||
return "No description found"
|
return "No description found"
|
||||||
|
|
||||||
def run(self):
|
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
|
return
|
||||||
|
|
||||||
# Only announce numlock changes if an actual numlock key was pressed
|
# Only announce numlock changes if an actual numlock key was pressed
|
||||||
# AND the LED state actually changed (some numpads send spurious NUMLOCK events)
|
# 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:
|
# Check if this is a genuine numlock key press by verifying:
|
||||||
# 1. KEY_NUMLOCK is in the current input sequence
|
# 1. KEY_NUMLOCK is in the current input sequence
|
||||||
@@ -40,7 +40,7 @@ class command:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if is_genuine_numlock:
|
if is_genuine_numlock:
|
||||||
if self.env["input"]["newNumLock"]:
|
if self.env["input"]["new_num_lock"]:
|
||||||
self.env["runtime"]["OutputManager"].present_text(
|
self.env["runtime"]["OutputManager"].present_text(
|
||||||
_("Numlock on"), interrupt=True
|
_("Numlock on"), interrupt=True
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -40,13 +40,19 @@ class command:
|
|||||||
):
|
):
|
||||||
self.detect_progress(self.env["screen"]["new_delta"])
|
self.detect_progress(self.env["screen"]["new_delta"])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Silently ignore errors to avoid disrupting normal operation
|
# Log errors for debugging instead of silently ignoring
|
||||||
pass
|
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||||
|
"Progress detector error: " + str(e),
|
||||||
|
debug.DebugLevel.ERROR,
|
||||||
|
)
|
||||||
|
|
||||||
def is_real_progress_update(self):
|
def is_real_progress_update(self):
|
||||||
"""Check if this is a real progress update vs screen change/window switch"""
|
"""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 the screen/application changed, it's not a progress update
|
||||||
if self.env["runtime"]["ScreenManager"].is_screen_change():
|
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
|
return False
|
||||||
|
|
||||||
# If there was a large cursor movement, it's likely navigation, not
|
# 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
|
# Large movements suggest navigation, not progress output
|
||||||
if y_move > 2 or x_move > 20:
|
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
|
return False
|
||||||
|
|
||||||
# Check if delta is too large (screen change) vs small incremental
|
# Check if delta is too large (screen change) vs small incremental
|
||||||
@@ -71,16 +81,27 @@ class command:
|
|||||||
if (
|
if (
|
||||||
delta_length > 200
|
delta_length > 200
|
||||||
): # Allow longer progress lines like Claude Code's status
|
): # 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
|
return False
|
||||||
|
|
||||||
# If delta contains newlines and is substantial, let incoming handler
|
# If delta contains newlines and is substantial, let incoming handler
|
||||||
# deal with it to avoid interfering with multi-line text output
|
# deal with it to avoid interfering with multi-line text output
|
||||||
if '\n' in delta_text and delta_length > 50:
|
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
|
return False
|
||||||
|
|
||||||
# Check if current line looks like a prompt - progress unlikely during
|
# Check if current line looks like a prompt - progress unlikely during
|
||||||
# prompts
|
# prompts
|
||||||
if self.is_current_line_prompt():
|
if self.is_current_line_prompt():
|
||||||
|
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||||
|
"Progress filter: prompt detected", debug.DebugLevel.INFO
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -284,14 +305,38 @@ class command:
|
|||||||
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
||||||
return
|
return
|
||||||
|
|
||||||
# Pattern 6: Claude/Codex working indicators (bullets + "esc to interrupt")
|
# Pattern 6: Claude Code working indicators (various symbols + activity text + "esc to interrupt")
|
||||||
|
# Matches any: [symbol] [Task description]… (... esc to interrupt ...)
|
||||||
|
# Symbols include: * ✢ ✽ ✶ ✻ · • ◦ ○ ● ◆ and similar decorative characters
|
||||||
|
# Example: ✽ Reviewing script for issues… (esc to interrupt · ctrl+t to show todos · 1m 25s · ↑ 887 tokens)
|
||||||
claude_progress_match = re.search(
|
claude_progress_match = re.search(
|
||||||
r'^[\s]*[•◦][^\n]*\(\s*(?:\d+m\s+)?\d+s?\s+•\s+esc to interrupt[^)]*\)',
|
r'[*✢✽✶✻·•◦○●◆]\s+\w+.*?…\s*\(.*esc to interrupt.*\)',
|
||||||
text,
|
text,
|
||||||
re.IGNORECASE,
|
re.IGNORECASE,
|
||||||
)
|
)
|
||||||
if claude_progress_match:
|
if claude_progress_match:
|
||||||
if current_time - self.env["commandBuffer"]["lastProgressTime"] >= 1.0:
|
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.play_activity_beep()
|
||||||
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
||||||
return
|
return
|
||||||
@@ -331,6 +376,23 @@ class command:
|
|||||||
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
||||||
return
|
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):
|
def play_progress_tone(self, percentage):
|
||||||
# Map 0-100% to 400-1200Hz frequency range
|
# Map 0-100% to 400-1200Hz frequency range
|
||||||
frequency = 400 + (percentage * 8)
|
frequency = 400 + (percentage * 8)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class command:
|
|||||||
== ""
|
== ""
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
if int(time.time() - self.env["input"]["lastInputTime"]) < self.env[
|
if int(time.time() - self.env["input"]["last_input_time"]) < self.env[
|
||||||
"runtime"
|
"runtime"
|
||||||
]["SettingsManager"].get_setting_as_int(
|
]["SettingsManager"].get_setting_as_int(
|
||||||
"promote", "inactive_timeout_sec"
|
"promote", "inactive_timeout_sec"
|
||||||
@@ -59,7 +59,7 @@ class command:
|
|||||||
self.env["runtime"]["OutputManager"].play_sound_icon(
|
self.env["runtime"]["OutputManager"].play_sound_icon(
|
||||||
"PromotedText"
|
"PromotedText"
|
||||||
)
|
)
|
||||||
self.env["input"]["lastInputTime"] = time.time()
|
self.env["input"]["last_input_time"] = time.time()
|
||||||
return
|
return
|
||||||
|
|
||||||
def set_callback(self, callback):
|
def set_callback(self, callback):
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class CursorManager:
|
|||||||
Return False if numlock is ON (let keys type numbers)
|
Return False if numlock is ON (let keys type numbers)
|
||||||
"""
|
"""
|
||||||
# Return False if numlock is ON
|
# Return False if numlock is ON
|
||||||
return not self.env["input"]["newNumLock"]
|
return not self.env["input"]["new_num_lock"]
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -69,9 +69,9 @@ class FenrirManager:
|
|||||||
].get_input_event()
|
].get_input_event()
|
||||||
|
|
||||||
if event["data"]:
|
if event["data"]:
|
||||||
event["data"]["EventName"] = self.environment["runtime"][
|
event["data"]["event_name"] = self.environment["runtime"][
|
||||||
"InputManager"
|
"InputManager"
|
||||||
].convert_event_name(event["data"]["EventName"])
|
].convert_event_name(event["data"]["event_name"])
|
||||||
self.environment["runtime"]["InputManager"].handle_input_event(
|
self.environment["runtime"]["InputManager"].handle_input_event(
|
||||||
event["data"]
|
event["data"]
|
||||||
)
|
)
|
||||||
@@ -121,8 +121,8 @@ class FenrirManager:
|
|||||||
self.environment["runtime"]["InputManager"].write_event_buffer()
|
self.environment["runtime"]["InputManager"].write_event_buffer()
|
||||||
self.environment["runtime"]["InputManager"].handle_device_grab()
|
self.environment["runtime"]["InputManager"].handle_device_grab()
|
||||||
|
|
||||||
if self.environment["input"]["keyForeward"] > 0:
|
if self.environment["input"]["key_forward"] > 0:
|
||||||
self.environment["input"]["keyForeward"] -= 1
|
self.environment["input"]["key_forward"] -= 1
|
||||||
|
|
||||||
self.environment["runtime"]["CommandManager"].execute_default_trigger(
|
self.environment["runtime"]["CommandManager"].execute_default_trigger(
|
||||||
"onKeyInput"
|
"onKeyInput"
|
||||||
@@ -265,11 +265,11 @@ class FenrirManager:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def detect_shortcut_command(self):
|
def detect_shortcut_command(self):
|
||||||
if self.environment["input"]["keyForeward"] > 0:
|
if self.environment["input"]["key_forward"] > 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
if len(self.environment["input"]["prevInput"]) > len(
|
if len(self.environment["input"]["prev_input"]) > len(
|
||||||
self.environment["input"]["currInput"]
|
self.environment["input"]["curr_input"]
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -283,7 +283,7 @@ class FenrirManager:
|
|||||||
].no_key_pressed():
|
].no_key_pressed():
|
||||||
if self.singleKeyCommand:
|
if self.singleKeyCommand:
|
||||||
self.singleKeyCommand = (
|
self.singleKeyCommand = (
|
||||||
len(self.environment["input"]["currInput"]) == 1
|
len(self.environment["input"]["curr_input"]) == 1
|
||||||
)
|
)
|
||||||
|
|
||||||
if not (
|
if not (
|
||||||
|
|||||||
@@ -9,28 +9,30 @@ import time
|
|||||||
from fenrirscreenreader.core import debug
|
from fenrirscreenreader.core import debug
|
||||||
|
|
||||||
input_data = {
|
input_data = {
|
||||||
"currInput": [],
|
"curr_input": [],
|
||||||
"prevDeepestInput": [],
|
"prev_input": [],
|
||||||
"eventBuffer": [],
|
"prev_deepest_input": [],
|
||||||
|
"event_buffer": [],
|
||||||
"shortcut_repeat": 0,
|
"shortcut_repeat": 0,
|
||||||
"fenrirKey": [],
|
"fenrir_key": [],
|
||||||
"scriptKey": [],
|
"script_key": [],
|
||||||
"keyForeward": 0,
|
"key_forward": 0,
|
||||||
"lastInputTime": time.time(),
|
"last_input_time": time.time(),
|
||||||
"oldNumLock": True,
|
"old_num_lock": True,
|
||||||
"newNumLock": True,
|
"new_num_lock": True,
|
||||||
"oldScrollLock": True,
|
"old_scroll_lock": True,
|
||||||
"newScrollLock": True,
|
"new_scroll_lock": True,
|
||||||
"oldCapsLock": False,
|
"old_caps_lock": False,
|
||||||
"newCapsLock": False,
|
"new_caps_lock": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
input_event = {
|
input_event = {
|
||||||
"EventName": "",
|
"event_name": "",
|
||||||
"EventValue": "",
|
"event_value": "",
|
||||||
"EventSec": 0,
|
"event_sec": 0,
|
||||||
"EventUsec": 0,
|
"event_usec": 0,
|
||||||
"EventState": 0,
|
"event_state": 0,
|
||||||
|
"event_type": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
key_names = [
|
key_names = [
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class InputDriver:
|
|||||||
def clear_event_buffer(self):
|
def clear_event_buffer(self):
|
||||||
if not self._initialized:
|
if not self._initialized:
|
||||||
return
|
return
|
||||||
del self.env["input"]["eventBuffer"][:]
|
del self.env["input"]["event_buffer"][:]
|
||||||
|
|
||||||
def update_input_devices(self, new_devices=None, init=False):
|
def update_input_devices(self, new_devices=None, init=False):
|
||||||
if not self._initialized:
|
if not self._initialized:
|
||||||
|
|||||||
@@ -43,18 +43,18 @@ class InputManager:
|
|||||||
self.update_input_devices()
|
self.update_input_devices()
|
||||||
|
|
||||||
# init LEDs with current state
|
# init LEDs with current state
|
||||||
self.env["input"]["newNumLock"] = self.env["runtime"][
|
self.env["input"]["new_num_lock"] = self.env["runtime"][
|
||||||
"InputDriver"
|
"InputDriver"
|
||||||
].get_led_state()
|
].get_led_state()
|
||||||
self.env["input"]["oldNumLock"] = self.env["input"]["newNumLock"]
|
self.env["input"]["old_num_lock"] = self.env["input"]["new_num_lock"]
|
||||||
self.env["input"]["newCapsLock"] = self.env["runtime"][
|
self.env["input"]["new_caps_lock"] = self.env["runtime"][
|
||||||
"InputDriver"
|
"InputDriver"
|
||||||
].get_led_state(1)
|
].get_led_state(1)
|
||||||
self.env["input"]["oldCapsLock"] = self.env["input"]["newCapsLock"]
|
self.env["input"]["old_caps_lock"] = self.env["input"]["new_caps_lock"]
|
||||||
self.env["input"]["newScrollLock"] = self.env["runtime"][
|
self.env["input"]["new_scroll_lock"] = self.env["runtime"][
|
||||||
"InputDriver"
|
"InputDriver"
|
||||||
].get_led_state(2)
|
].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.lastDeepestInput = []
|
||||||
self.lastEvent = None
|
self.lastEvent = None
|
||||||
self.env["input"]["shortcut_repeat"] = 1
|
self.env["input"]["shortcut_repeat"] = 1
|
||||||
@@ -84,7 +84,7 @@ class InputManager:
|
|||||||
self.set_execute_device_grab()
|
self.set_execute_device_grab()
|
||||||
if not self.executeDeviceGrab:
|
if not self.executeDeviceGrab:
|
||||||
return
|
return
|
||||||
if self.env["input"]["eventBuffer"] != []:
|
if self.env["input"]["event_buffer"] != []:
|
||||||
return
|
return
|
||||||
if not self.no_key_pressed():
|
if not self.no_key_pressed():
|
||||||
return
|
return
|
||||||
@@ -176,36 +176,36 @@ class InputManager:
|
|||||||
return
|
return
|
||||||
self.lastEvent = event_data
|
self.lastEvent = event_data
|
||||||
# a hang apears.. try to fix
|
# a hang apears.. try to fix
|
||||||
if self.env["input"]["eventBuffer"] == []:
|
if self.env["input"]["event_buffer"] == []:
|
||||||
if self.env["input"]["currInput"] != []:
|
if self.env["input"]["curr_input"] != []:
|
||||||
self.env["input"]["currInput"] = []
|
self.env["input"]["curr_input"] = []
|
||||||
self.env["input"]["shortcut_repeat"] = 1
|
self.env["input"]["shortcut_repeat"] = 1
|
||||||
|
|
||||||
self.env["input"]["prevInput"] = self.env["input"]["currInput"].copy()
|
self.env["input"]["prev_input"] = self.env["input"]["curr_input"].copy()
|
||||||
if event_data["EventState"] == 0:
|
if event_data["event_state"] == 0:
|
||||||
if event_data["EventName"] in self.env["input"]["currInput"]:
|
if event_data["event_name"] in self.env["input"]["curr_input"]:
|
||||||
self.env["input"]["currInput"].remove(event_data["EventName"])
|
self.env["input"]["curr_input"].remove(event_data["event_name"])
|
||||||
if len(self.env["input"]["currInput"]) > 1:
|
if len(self.env["input"]["curr_input"]) > 1:
|
||||||
self.env["input"]["currInput"] = sorted(
|
self.env["input"]["curr_input"] = sorted(
|
||||||
self.env["input"]["currInput"]
|
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.env["input"]["shortcut_repeat"] = 1
|
||||||
self.lastInputTime = time.time()
|
self.lastInputTime = time.time()
|
||||||
elif event_data["EventState"] == 1:
|
elif event_data["event_state"] == 1:
|
||||||
if not event_data["EventName"] in self.env["input"]["currInput"]:
|
if not event_data["event_name"] in self.env["input"]["curr_input"]:
|
||||||
self.env["input"]["currInput"].append(event_data["EventName"])
|
self.env["input"]["curr_input"].append(event_data["event_name"])
|
||||||
if len(self.env["input"]["currInput"]) > 1:
|
if len(self.env["input"]["curr_input"]) > 1:
|
||||||
self.env["input"]["currInput"] = sorted(
|
self.env["input"]["curr_input"] = sorted(
|
||||||
self.env["input"]["currInput"]
|
self.env["input"]["curr_input"]
|
||||||
)
|
)
|
||||||
if len(self.lastDeepestInput) < len(
|
if len(self.lastDeepestInput) < len(
|
||||||
self.env["input"]["currInput"]
|
self.env["input"]["curr_input"]
|
||||||
):
|
):
|
||||||
self.set_last_deepest_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"][
|
if time.time() - self.lastInputTime <= self.env["runtime"][
|
||||||
"SettingsManager"
|
"SettingsManager"
|
||||||
].get_setting_as_float("keyboard", "double_tap_timeout"):
|
].get_setting_as_float("keyboard", "double_tap_timeout"):
|
||||||
@@ -214,37 +214,37 @@ class InputManager:
|
|||||||
self.env["input"]["shortcut_repeat"] = 1
|
self.env["input"]["shortcut_repeat"] = 1
|
||||||
self.handle_led_states(event_data)
|
self.handle_led_states(event_data)
|
||||||
self.lastInputTime = time.time()
|
self.lastInputTime = time.time()
|
||||||
elif event_data["EventState"] == 2:
|
elif event_data["event_state"] == 2:
|
||||||
self.lastInputTime = time.time()
|
self.lastInputTime = time.time()
|
||||||
|
|
||||||
self.env["input"]["oldNumLock"] = self.env["input"]["newNumLock"]
|
self.env["input"]["old_num_lock"] = self.env["input"]["new_num_lock"]
|
||||||
self.env["input"]["newNumLock"] = self.env["runtime"][
|
self.env["input"]["new_num_lock"] = self.env["runtime"][
|
||||||
"InputDriver"
|
"InputDriver"
|
||||||
].get_led_state()
|
].get_led_state()
|
||||||
self.env["input"]["oldCapsLock"] = self.env["input"]["newCapsLock"]
|
self.env["input"]["old_caps_lock"] = self.env["input"]["new_caps_lock"]
|
||||||
self.env["input"]["newCapsLock"] = self.env["runtime"][
|
self.env["input"]["new_caps_lock"] = self.env["runtime"][
|
||||||
"InputDriver"
|
"InputDriver"
|
||||||
].get_led_state(1)
|
].get_led_state(1)
|
||||||
self.env["input"]["oldScrollLock"] = self.env["input"]["newScrollLock"]
|
self.env["input"]["old_scroll_lock"] = self.env["input"]["new_scroll_lock"]
|
||||||
self.env["input"]["newScrollLock"] = self.env["runtime"][
|
self.env["input"]["new_scroll_lock"] = self.env["runtime"][
|
||||||
"InputDriver"
|
"InputDriver"
|
||||||
].get_led_state(2)
|
].get_led_state(2)
|
||||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||||
"currInput " + str(self.env["input"]["currInput"]),
|
"curr_input " + str(self.env["input"]["curr_input"]),
|
||||||
debug.DebugLevel.INFO,
|
debug.DebugLevel.INFO,
|
||||||
)
|
)
|
||||||
if self.no_key_pressed():
|
if self.no_key_pressed():
|
||||||
self.env["input"]["prevInput"] = []
|
self.env["input"]["prev_input"] = []
|
||||||
|
|
||||||
def handle_led_states(self, m_event):
|
def handle_led_states(self, m_event):
|
||||||
if self.curr_key_is_modifier():
|
if self.curr_key_is_modifier():
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
if m_event["EventName"] == "KEY_NUMLOCK":
|
if m_event["event_name"] == "KEY_NUMLOCK":
|
||||||
self.env["runtime"]["InputDriver"].toggle_led_state()
|
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)
|
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)
|
self.env["runtime"]["InputDriver"].toggle_led_state(2)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||||
@@ -368,11 +368,11 @@ class InputManager:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def no_key_pressed(self):
|
def no_key_pressed(self):
|
||||||
return self.env["input"]["currInput"] == []
|
return self.env["input"]["curr_input"] == []
|
||||||
|
|
||||||
def is_key_press(self):
|
def is_key_press(self):
|
||||||
return (self.env["input"]["prevInput"] == []) and (
|
return (self.env["input"]["prev_input"] == []) and (
|
||||||
self.env["input"]["currInput"] != []
|
self.env["input"]["curr_input"] != []
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_prev_deepest_shortcut(self):
|
def get_prev_deepest_shortcut(self):
|
||||||
@@ -384,7 +384,7 @@ class InputManager:
|
|||||||
def get_prev_shortcut(self):
|
def get_prev_shortcut(self):
|
||||||
shortcut = []
|
shortcut = []
|
||||||
shortcut.append(self.env["input"]["shortcut_repeat"])
|
shortcut.append(self.env["input"]["shortcut_repeat"])
|
||||||
shortcut.append(self.env["input"]["prevInput"])
|
shortcut.append(self.env["input"]["prev_input"])
|
||||||
return str(shortcut)
|
return str(shortcut)
|
||||||
|
|
||||||
def get_curr_shortcut(self, inputSequence=None):
|
def get_curr_shortcut(self, inputSequence=None):
|
||||||
@@ -430,16 +430,16 @@ class InputManager:
|
|||||||
if not self.env["runtime"][
|
if not self.env["runtime"][
|
||||||
"CursorManager"
|
"CursorManager"
|
||||||
].should_process_numpad_commands():
|
].should_process_numpad_commands():
|
||||||
for key in self.env["input"]["currInput"]:
|
for key in self.env["input"]["curr_input"]:
|
||||||
if key in numpad_keys:
|
if key in numpad_keys:
|
||||||
# Return an empty/invalid shortcut that won't match any
|
# Return an empty/invalid shortcut that won't match any
|
||||||
# command
|
# command
|
||||||
return "[]"
|
return "[]"
|
||||||
|
|
||||||
shortcut.append(self.env["input"]["currInput"])
|
shortcut.append(self.env["input"]["curr_input"])
|
||||||
|
|
||||||
if len(self.env["input"]["prevInput"]) < len(
|
if len(self.env["input"]["prev_input"]) < len(
|
||||||
self.env["input"]["currInput"]
|
self.env["input"]["curr_input"]
|
||||||
):
|
):
|
||||||
if self.env["input"][
|
if self.env["input"][
|
||||||
"shortcut_repeat"
|
"shortcut_repeat"
|
||||||
@@ -447,7 +447,7 @@ class InputManager:
|
|||||||
shortcut = []
|
shortcut = []
|
||||||
self.env["input"]["shortcut_repeat"] = 1
|
self.env["input"]["shortcut_repeat"] = 1
|
||||||
shortcut.append(self.env["input"]["shortcut_repeat"])
|
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(
|
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||||
"curr_shortcut " + str(shortcut), debug.DebugLevel.INFO
|
"curr_shortcut " + str(shortcut), debug.DebugLevel.INFO
|
||||||
)
|
)
|
||||||
@@ -456,15 +456,15 @@ class InputManager:
|
|||||||
def curr_key_is_modifier(self):
|
def curr_key_is_modifier(self):
|
||||||
if len(self.get_last_deepest_input()) != 1:
|
if len(self.get_last_deepest_input()) != 1:
|
||||||
return False
|
return False
|
||||||
return (self.env["input"]["currInput"][0] == "KEY_FENRIR") or (
|
return (self.env["input"]["curr_input"][0] == "KEY_FENRIR") or (
|
||||||
self.env["input"]["currInput"][0] == "KEY_SCRIPT"
|
self.env["input"]["curr_input"][0] == "KEY_SCRIPT"
|
||||||
)
|
)
|
||||||
|
|
||||||
def is_fenrir_key(self, event_name):
|
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):
|
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):
|
def get_command_for_shortcut(self, shortcut):
|
||||||
if not self.shortcut_exists(shortcut):
|
if not self.shortcut_exists(shortcut):
|
||||||
@@ -477,8 +477,8 @@ class InputManager:
|
|||||||
if not event_data:
|
if not event_data:
|
||||||
return
|
return
|
||||||
key_name = ""
|
key_name = ""
|
||||||
if event_data["EventState"] == 1:
|
if event_data["event_state"] == 1:
|
||||||
key_name = event_data["EventName"].lower()
|
key_name = event_data["event_name"].lower()
|
||||||
if key_name.startswith("key_"):
|
if key_name.startswith("key_"):
|
||||||
key_name = key_name[4:]
|
key_name = key_name[4:]
|
||||||
self.env["runtime"]["OutputManager"].present_text(
|
self.env["runtime"]["OutputManager"].present_text(
|
||||||
|
|||||||
@@ -282,15 +282,15 @@ class SettingsManager:
|
|||||||
keys = keys.upper()
|
keys = keys.upper()
|
||||||
key_list = keys.split(",")
|
key_list = keys.split(",")
|
||||||
for key in key_list:
|
for key in key_list:
|
||||||
if key not in self.env["input"]["fenrirKey"]:
|
if key not in self.env["input"]["fenrir_key"]:
|
||||||
self.env["input"]["fenrirKey"].append(key)
|
self.env["input"]["fenrir_key"].append(key)
|
||||||
|
|
||||||
def set_script_keys(self, keys):
|
def set_script_keys(self, keys):
|
||||||
keys = keys.upper()
|
keys = keys.upper()
|
||||||
key_list = keys.split(",")
|
key_list = keys.split(",")
|
||||||
for key in key_list:
|
for key in key_list:
|
||||||
if key not in self.env["input"]["scriptKey"]:
|
if key not in self.env["input"]["script_key"]:
|
||||||
self.env["input"]["scriptKey"].append(key)
|
self.env["input"]["script_key"].append(key)
|
||||||
|
|
||||||
def reset_setting_arg_dict(self):
|
def reset_setting_arg_dict(self):
|
||||||
self.settingArgDict = {}
|
self.settingArgDict = {}
|
||||||
|
|||||||
@@ -4,5 +4,5 @@
|
|||||||
# Fenrir TTY screen reader
|
# Fenrir TTY screen reader
|
||||||
# By Chrys, Storm Dragon, and contributors.
|
# By Chrys, Storm Dragon, and contributors.
|
||||||
|
|
||||||
version = "2025.12.14"
|
version = "2025.12.19"
|
||||||
code_name = "master"
|
code_name = "master"
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class driver(inputDriver):
|
|||||||
def clear_event_buffer(self):
|
def clear_event_buffer(self):
|
||||||
if not self._initialized:
|
if not self._initialized:
|
||||||
return
|
return
|
||||||
del self.env["input"]["eventBuffer"][:]
|
del self.env["input"]["event_buffer"][:]
|
||||||
print("Input Debug Driver: clear_event_buffer")
|
print("Input Debug Driver: clear_event_buffer")
|
||||||
|
|
||||||
def update_input_devices(self, new_devices=None, init=False):
|
def update_input_devices(self, new_devices=None, init=False):
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ class driver(inputDriver):
|
|||||||
"input_watchdog: EVENT:" + str(event),
|
"input_watchdog: EVENT:" + str(event),
|
||||||
debug.DebugLevel.INFO,
|
debug.DebugLevel.INFO,
|
||||||
)
|
)
|
||||||
self.env["input"]["eventBuffer"].append(
|
self.env["input"]["event_buffer"].append(
|
||||||
[device, udevice, event]
|
[device, udevice, event]
|
||||||
)
|
)
|
||||||
if event.type == evdev.events.EV_KEY:
|
if event.type == evdev.events.EV_KEY:
|
||||||
@@ -271,11 +271,11 @@ class driver(inputDriver):
|
|||||||
event = device.read_one()
|
event = device.read_one()
|
||||||
continue
|
continue
|
||||||
if not isinstance(
|
if not isinstance(
|
||||||
curr_map_event["EventName"], str
|
curr_map_event["event_name"], str
|
||||||
):
|
):
|
||||||
event = device.read_one()
|
event = device.read_one()
|
||||||
continue
|
continue
|
||||||
if curr_map_event["EventState"] in [0, 1, 2]:
|
if curr_map_event["event_state"] in [0, 1, 2]:
|
||||||
event_queue.put(
|
event_queue.put(
|
||||||
{
|
{
|
||||||
"Type": FenrirEventType.keyboard_input,
|
"Type": FenrirEventType.keyboard_input,
|
||||||
@@ -301,7 +301,7 @@ class driver(inputDriver):
|
|||||||
def write_event_buffer(self):
|
def write_event_buffer(self):
|
||||||
if not self._initialized:
|
if not self._initialized:
|
||||||
return
|
return
|
||||||
for iDevice, uDevice, event in self.env["input"]["eventBuffer"]:
|
for iDevice, uDevice, event in self.env["input"]["event_buffer"]:
|
||||||
try:
|
try:
|
||||||
if uDevice:
|
if uDevice:
|
||||||
if self.gDevices[iDevice.fd]:
|
if self.gDevices[iDevice.fd]:
|
||||||
@@ -554,18 +554,18 @@ class driver(inputDriver):
|
|||||||
m_event = inputData.input_event
|
m_event = inputData.input_event
|
||||||
try:
|
try:
|
||||||
# mute is a list = ['KEY_MIN_INTERESTING', 'KEY_MUTE']
|
# mute is a list = ['KEY_MIN_INTERESTING', 'KEY_MUTE']
|
||||||
m_event["EventName"] = evdev.ecodes.keys[event.code]
|
m_event["event_name"] = evdev.ecodes.keys[event.code]
|
||||||
if isinstance(m_event["EventName"], list):
|
if isinstance(m_event["event_name"], list):
|
||||||
if len(m_event["EventName"]) > 0:
|
if len(m_event["event_name"]) > 0:
|
||||||
m_event["EventName"] = m_event["EventName"][0]
|
m_event["event_name"] = m_event["event_name"][0]
|
||||||
if isinstance(m_event["EventName"], list):
|
if isinstance(m_event["event_name"], list):
|
||||||
if len(m_event["EventName"]) > 0:
|
if len(m_event["event_name"]) > 0:
|
||||||
m_event["EventName"] = m_event["EventName"][0]
|
m_event["event_name"] = m_event["event_name"][0]
|
||||||
m_event["EventValue"] = event.code
|
m_event["event_value"] = event.code
|
||||||
m_event["EventSec"] = event.sec
|
m_event["event_sec"] = event.sec
|
||||||
m_event["EventUsec"] = event.usec
|
m_event["event_usec"] = event.usec
|
||||||
m_event["EventState"] = event.value
|
m_event["event_state"] = event.value
|
||||||
m_event["EventType"] = event.type
|
m_event["event_type"] = event.type
|
||||||
return m_event
|
return m_event
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return None
|
return None
|
||||||
|
|||||||
Reference in New Issue
Block a user