diff --git a/README.md b/README.md index bd55dd58..46eb6f81 100644 --- a/README.md +++ b/README.md @@ -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 [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 [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 diff --git a/config/settings/settings.conf b/config/settings/settings.conf index 3eb893d3..9e7c5f8a 100644 --- a/config/settings/settings.conf +++ b/config/settings/settings.conf @@ -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. @@ -110,8 +109,10 @@ driver=evdevDriver device=ALL # gives Fenrir exclusive access to the keyboard and lets it control keystrokes. 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 +ignore_shortcuts=False keyboard_layout=desktop # echo chars while typing. # 0 = None @@ -138,6 +139,8 @@ debug_level=2 # debugMode=Print just prints on the screen 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 @@ -247,6 +250,11 @@ enabled=True inactive_timeout_sec=120 # Comma-separated list of text patterns to promote when detected # 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= [menu] diff --git a/src/fenrirscreenreader/commands/commands/forward_keypress.py b/src/fenrirscreenreader/commands/commands/forward_keypress.py index 754fc3b9..e22ff7c5 100644 --- a/src/fenrirscreenreader/commands/commands/forward_keypress.py +++ b/src/fenrirscreenreader/commands/commands/forward_keypress.py @@ -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 ) diff --git a/src/fenrirscreenreader/commands/commands/shut_up.py b/src/fenrirscreenreader/commands/commands/shut_up.py index 7c830e40..3a62961d 100644 --- a/src/fenrirscreenreader/commands/commands/shut_up.py +++ b/src/fenrirscreenreader/commands/commands/shut_up.py @@ -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() diff --git a/src/fenrirscreenreader/commands/onByteInput/10000-shut_up.py b/src/fenrirscreenreader/commands/onByteInput/10000-shut_up.py index be92e007..32fa85a2 100644 --- a/src/fenrirscreenreader/commands/onByteInput/10000-shut_up.py +++ b/src/fenrirscreenreader/commands/onByteInput/10000-shut_up.py @@ -30,8 +30,8 @@ class command: 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 @@ -46,8 +46,8 @@ class command: .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() diff --git a/src/fenrirscreenreader/commands/onCursorChange/15000-char_echo.py b/src/fenrirscreenreader/commands/onCursorChange/15000-char_echo.py index 2dbbd23b..6e04abb2 100644 --- a/src/fenrirscreenreader/commands/onCursorChange/15000-char_echo.py +++ b/src/fenrirscreenreader/commands/onCursorChange/15000-char_echo.py @@ -31,7 +31,7 @@ class command: 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 diff --git a/src/fenrirscreenreader/commands/onKeyInput/10000-shut_up.py b/src/fenrirscreenreader/commands/onKeyInput/10000-shut_up.py index bdf972db..3b763c50 100644 --- a/src/fenrirscreenreader/commands/onKeyInput/10000-shut_up.py +++ b/src/fenrirscreenreader/commands/onKeyInput/10000-shut_up.py @@ -29,8 +29,8 @@ class command: 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 @@ -45,8 +45,8 @@ class command: .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() diff --git a/src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py b/src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py index a2ff07ad..97471e44 100644 --- a/src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py +++ b/src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py @@ -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 diff --git a/src/fenrirscreenreader/commands/onKeyInput/80000-capslock.py b/src/fenrirscreenreader/commands/onKeyInput/80000-capslock.py index 0957607d..2b978b15 100644 --- a/src/fenrirscreenreader/commands/onKeyInput/80000-capslock.py +++ b/src/fenrirscreenreader/commands/onKeyInput/80000-capslock.py @@ -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 ) diff --git a/src/fenrirscreenreader/commands/onKeyInput/80300-scrolllock.py b/src/fenrirscreenreader/commands/onKeyInput/80300-scrolllock.py index ea4584be..7a486d50 100644 --- a/src/fenrirscreenreader/commands/onKeyInput/80300-scrolllock.py +++ b/src/fenrirscreenreader/commands/onKeyInput/80300-scrolllock.py @@ -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 ) diff --git a/src/fenrirscreenreader/commands/onKeyInput/80500-numlock.py b/src/fenrirscreenreader/commands/onKeyInput/80500-numlock.py index 10d2bdd5..d7efe0c6 100644 --- a/src/fenrirscreenreader/commands/onKeyInput/80500-numlock.py +++ b/src/fenrirscreenreader/commands/onKeyInput/80500-numlock.py @@ -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 ) diff --git a/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py b/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py index 2b2bc6d5..f67312be 100644 --- a/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py +++ b/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py @@ -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,14 +305,38 @@ class command: self.env["commandBuffer"]["lastProgressTime"] = current_time 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( - r'^[\s]*[•◦][^\n]*\(\s*(?:\d+m\s+)?\d+s?\s+•\s+esc to interrupt[^)]*\)', + r'[*✢✽✶✻·•◦○●◆]\s+\w+.*?…\s*\(.*esc 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 @@ -331,6 +376,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) diff --git a/src/fenrirscreenreader/commands/onScreenUpdate/75000-incoming_promote.py b/src/fenrirscreenreader/commands/onScreenUpdate/75000-incoming_promote.py index c4de5d95..51585b1f 100644 --- a/src/fenrirscreenreader/commands/onScreenUpdate/75000-incoming_promote.py +++ b/src/fenrirscreenreader/commands/onScreenUpdate/75000-incoming_promote.py @@ -35,7 +35,7 @@ class command: == "" ): return - if int(time.time() - self.env["input"]["lastInputTime"]) < self.env[ + if int(time.time() - self.env["input"]["last_input_time"]) < self.env[ "runtime" ]["SettingsManager"].get_setting_as_int( "promote", "inactive_timeout_sec" @@ -59,7 +59,7 @@ class command: self.env["runtime"]["OutputManager"].play_sound_icon( "PromotedText" ) - self.env["input"]["lastInputTime"] = time.time() + self.env["input"]["last_input_time"] = time.time() return def set_callback(self, callback): diff --git a/src/fenrirscreenreader/core/cursorManager.py b/src/fenrirscreenreader/core/cursorManager.py index 85f6379a..0ca329fa 100644 --- a/src/fenrirscreenreader/core/cursorManager.py +++ b/src/fenrirscreenreader/core/cursorManager.py @@ -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 diff --git a/src/fenrirscreenreader/core/fenrirManager.py b/src/fenrirscreenreader/core/fenrirManager.py index a71a2ea1..719ff042 100644 --- a/src/fenrirscreenreader/core/fenrirManager.py +++ b/src/fenrirscreenreader/core/fenrirManager.py @@ -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 ( diff --git a/src/fenrirscreenreader/core/inputData.py b/src/fenrirscreenreader/core/inputData.py index 68998c22..b4e55c78 100644 --- a/src/fenrirscreenreader/core/inputData.py +++ b/src/fenrirscreenreader/core/inputData.py @@ -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 = [ diff --git a/src/fenrirscreenreader/core/inputDriver.py b/src/fenrirscreenreader/core/inputDriver.py index 9ca961b9..f87d4cdb 100644 --- a/src/fenrirscreenreader/core/inputDriver.py +++ b/src/fenrirscreenreader/core/inputDriver.py @@ -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: diff --git a/src/fenrirscreenreader/core/inputManager.py b/src/fenrirscreenreader/core/inputManager.py index a26f64d4..298a981e 100644 --- a/src/fenrirscreenreader/core/inputManager.py +++ b/src/fenrirscreenreader/core/inputManager.py @@ -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,7 +84,7 @@ 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 @@ -176,36 +176,36 @@ 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", "double_tap_timeout"): @@ -214,37 +214,37 @@ class InputManager: 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( @@ -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( diff --git a/src/fenrirscreenreader/core/settingsManager.py b/src/fenrirscreenreader/core/settingsManager.py index 22629626..63be2a68 100644 --- a/src/fenrirscreenreader/core/settingsManager.py +++ b/src/fenrirscreenreader/core/settingsManager.py @@ -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 = {} diff --git a/src/fenrirscreenreader/fenrirVersion.py b/src/fenrirscreenreader/fenrirVersion.py index a1c2aaaf..5a02a2c6 100644 --- a/src/fenrirscreenreader/fenrirVersion.py +++ b/src/fenrirscreenreader/fenrirVersion.py @@ -4,5 +4,5 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributors. -version = "2025.12.14" +version = "2025.12.19" code_name = "master" diff --git a/src/fenrirscreenreader/inputDriver/debugDriver.py b/src/fenrirscreenreader/inputDriver/debugDriver.py index dfb33cc8..88be858e 100644 --- a/src/fenrirscreenreader/inputDriver/debugDriver.py +++ b/src/fenrirscreenreader/inputDriver/debugDriver.py @@ -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): diff --git a/src/fenrirscreenreader/inputDriver/evdevDriver.py b/src/fenrirscreenreader/inputDriver/evdevDriver.py index e1f24123..299f8950 100644 --- a/src/fenrirscreenreader/inputDriver/evdevDriver.py +++ b/src/fenrirscreenreader/inputDriver/evdevDriver.py @@ -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, @@ -301,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]: @@ -554,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