From 74089511520ed649b0eda75cd1995020aca5b460 Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Tue, 1 Jul 2025 22:23:50 -0400 Subject: [PATCH] To make Fenrir easier to approach for new developer, start code migration to be pep8 compliant. --- .../commands/command_template.py | 10 +- .../commands/commands/00_init_commands.py | 15 +- .../commands/add_word_to_spell_check.py | 51 +- .../commands/commands/adjustment_base.py | 58 +- .../commands/announce_fenrir_version.py | 20 +- .../commands/commands/apply_tested_voice.py | 65 +- .../commands/commands/attribute_cursor.py | 26 +- .../commands/commands/bookmark_1.py | 3 + .../commands/commands/bookmark_10.py | 3 + .../commands/commands/bookmark_2.py | 3 + .../commands/commands/bookmark_3.py | 3 + .../commands/commands/bookmark_4.py | 3 + .../commands/commands/bookmark_5.py | 3 + .../commands/commands/bookmark_6.py | 3 + .../commands/commands/bookmark_7.py | 3 + .../commands/commands/bookmark_8.py | 3 + .../commands/commands/bookmark_9.py | 3 + .../commands/commands/bookmark_base.py | 112 ++-- .../commands/commands/clear_bookmark_1.py | 3 + .../commands/commands/clear_bookmark_10.py | 3 + .../commands/commands/clear_bookmark_2.py | 3 + .../commands/commands/clear_bookmark_3.py | 3 + .../commands/commands/clear_bookmark_4.py | 3 + .../commands/commands/clear_bookmark_5.py | 3 + .../commands/commands/clear_bookmark_6.py | 3 + .../commands/commands/clear_bookmark_7.py | 3 + .../commands/commands/clear_bookmark_8.py | 3 + .../commands/commands/clear_bookmark_9.py | 3 + .../commands/commands/clear_clipboard.py | 19 +- .../commands/clear_window_application.py | 22 +- .../commands/copy_last_echo_to_clipboard.py | 18 +- .../commands/copy_marked_to_clipboard.py | 53 +- .../commands/commands/curr_clipboard.py | 26 +- .../commands/commands/curr_screen.py | 20 +- .../commands/curr_screen_after_cursor.py | 19 +- .../commands/curr_screen_before_cursor.py | 22 +- .../commands/current_quick_menu_entry.py | 13 +- .../commands/current_quick_menu_value.py | 10 +- .../commands/commands/cursor_column.py | 17 +- .../commands/commands/cursor_lineno.py | 17 +- .../commands/commands/cursor_position.py | 19 +- .../commands/cursor_read_line_to_cursor.py | 27 +- .../commands/cursor_read_to_end_of_line.py | 27 +- .../commands/cycle_keyboard_layout.py | 54 +- .../commands/commands/date.py | 24 +- .../commands/commands/dec_alsa_volume.py | 3 + .../commands/commands/dec_sound_volume.py | 3 + .../commands/commands/dec_speech_pitch.py | 3 + .../commands/commands/dec_speech_rate.py | 3 + .../commands/commands/dec_speech_volume.py | 3 + .../commands/commands/exit_review.py | 22 +- .../commands/export_clipboard_to_file.py | 45 +- .../commands/export_clipboard_to_x.py | 50 +- .../commands/commands/first_clipboard.py | 28 +- .../commands/commands/forward_keypress.py | 15 +- .../commands/import_clipboard_from_file.py | 39 +- .../commands/import_clipboard_from_x.py | 41 +- .../commands/commands/inc_alsa_volume.py | 3 + .../commands/commands/inc_sound_volume.py | 3 + .../commands/commands/inc_speech_pitch.py | 3 + .../commands/commands/inc_speech_rate.py | 3 + .../commands/commands/inc_speech_volume.py | 3 + .../commands/commands/indent_curr_line.py | 24 +- .../commands/commands/last_clipboard.py | 28 +- .../commands/commands/marked_text.py | 33 +- .../commands/commands/next_clipboard.py | 46 +- .../commands/next_quick_menu_entry.py | 16 +- .../commands/next_quick_menu_value.py | 13 +- .../commands/commands/paste_clipboard.py | 34 +- .../commands/commands/present_first_line.py | 34 +- .../commands/commands/present_last_line.py | 34 +- .../commands/commands/prev_clipboard.py | 42 +- .../commands/prev_quick_menu_entry.py | 16 +- .../commands/prev_quick_menu_value.py | 13 +- .../commands/commands/progress_bar_monitor.py | 134 ++-- .../commands/commands/quit_fenrir.py | 15 +- .../commands/commands/remove_marks.py | 15 +- .../commands/remove_word_from_spell_check.py | 54 +- .../commands/commands/review_bottom.py | 14 +- .../commands/commands/review_curr_char.py | 40 +- .../commands/review_curr_char_phonetic.py | 26 +- .../commands/commands/review_curr_line.py | 26 +- .../commands/commands/review_curr_word.py | 35 +- .../commands/review_curr_word_phonetic.py | 39 +- .../commands/commands/review_down.py | 28 +- .../commands/commands/review_line_begin.py | 32 +- .../commands/commands/review_line_end.py | 31 +- .../commands/review_line_first_char.py | 36 +- .../commands/review_line_last_char.py | 27 +- .../commands/commands/review_next_char.py | 49 +- .../commands/review_next_char_phonetic.py | 34 +- .../commands/commands/review_next_line.py | 31 +- .../commands/commands/review_next_word.py | 39 +- .../commands/review_next_word_phonetic.py | 39 +- .../commands/commands/review_prev_char.py | 51 +- .../commands/review_prev_char_phonetic.py | 34 +- .../commands/commands/review_prev_line.py | 28 +- .../commands/commands/review_prev_word.py | 35 +- .../commands/review_prev_word_phonetic.py | 39 +- .../commands/review_screen_first_char.py | 26 +- .../commands/review_screen_last_char.py | 27 +- .../commands/commands/review_top.py | 15 +- .../commands/commands/review_up.py | 36 +- .../commands/commands/save_settings.py | 11 +- .../commands/commands/set_bookmark_1.py | 3 + .../commands/commands/set_bookmark_10.py | 3 + .../commands/commands/set_bookmark_2.py | 3 + .../commands/commands/set_bookmark_3.py | 3 + .../commands/commands/set_bookmark_4.py | 3 + .../commands/commands/set_bookmark_5.py | 3 + .../commands/commands/set_bookmark_6.py | 3 + .../commands/commands/set_bookmark_7.py | 3 + .../commands/commands/set_bookmark_8.py | 3 + .../commands/commands/set_bookmark_9.py | 3 + .../commands/commands/set_mark.py | 22 +- .../commands/set_window_application.py | 21 +- .../commands/commands/shut_up.py | 18 +- .../commands/commands/silence_until_prompt.py | 102 +-- .../commands/commands/spell_check.py | 55 +- .../commands/commands/subprocess.py | 46 +- .../commands/commands/temp_disable_speech.py | 14 +- .../commands/commands/time.py | 22 +- .../commands/commands/toggle_auto_indent.py | 28 +- .../commands/commands/toggle_auto_read.py | 28 +- .../commands/toggle_auto_spell_check.py | 30 +- .../commands/commands/toggle_auto_time.py | 27 +- .../commands/commands/toggle_barrier.py | 28 +- .../commands/commands/toggle_emoticons.py | 28 +- .../commands/commands/toggle_has_attribute.py | 28 +- .../commands/toggle_highlight_tracking.py | 38 +- .../commands/commands/toggle_output.py | 39 +- .../commands/toggle_punctuation_level.py | 19 +- .../commands/commands/toggle_sound.py | 29 +- .../commands/commands/toggle_speech.py | 27 +- .../commands/commands/toggle_tutorial_mode.py | 17 +- .../commands/commands/toggle_vmenu_mode.py | 16 +- .../commands/commands/voice_browser.py | 145 +++-- .../commands/commands/voice_browser_apply.py | 15 +- .../commands/commands/voice_browser_exit.py | 15 +- .../commands/voice_browser_next_module.py | 15 +- .../commands/voice_browser_next_voice.py | 15 +- .../commands/voice_browser_prev_module.py | 15 +- .../commands/voice_browser_prev_voice.py | 15 +- .../commands/commands/voice_browser_safe.py | 116 ++-- .../commands/commands/voice_browser_test.py | 15 +- .../commands/help/curr_help.py | 14 +- .../commands/help/next_help.py | 14 +- .../commands/help/prev_help.py | 14 +- .../commands/onByteInput/10000-shut_up.py | 29 +- .../onByteInput/15000-enable_temp_speech.py | 21 +- .../onCursorChange/15000-char_echo.py | 41 +- .../onCursorChange/25000-word_echo_type.py | 49 +- .../onCursorChange/35000-spell_check.py | 123 ++-- .../onCursorChange/45000-char_delete_echo.py | 28 +- ...resent_char_if_cursor_change_horizontal.py | 62 +- .../onCursorChange/55000-tab_completion.py | 27 +- .../60000-word_echo_navigation.py | 42 +- ...-present_line_if_cursor_change_vertical.py | 62 +- .../68000-auto_identation_horizontal.py | 36 +- .../onCursorChange/85000-has_attribute.py | 31 +- .../onCursorChange/95000-exit_review_mode.py | 19 +- .../onHeartBeat/2000-GetSessionInfo.py | 15 +- .../commands/onHeartBeat/76000-time.py | 42 +- .../commands/onKeyInput/10000-shut_up.py | 29 +- .../onKeyInput/15000-enable_temp_speech.py | 25 +- .../commands/onKeyInput/80000-capslock.py | 17 +- .../commands/onKeyInput/80300-scrolllock.py | 17 +- .../commands/onKeyInput/80500-numlock.py | 17 +- .../commands/onKeyInput/81000-key_echo.py | 7 + .../onPlugInputDevice/50000-plugSound.py | 16 +- .../commands/onScreenChanged/10000-shut_up.py | 10 +- .../20000-reset_last_cursor_attribute.py | 8 +- .../21000-reset_barrier_change.py | 8 +- .../onScreenChanged/70000-barrier_detect.py | 17 +- .../80000-screen_change_announcement.py | 19 +- .../onScreenChanged/85000-reset_marks.py | 9 +- .../89000-leave_review_mode.py | 12 +- .../56000-highlight_tracking.py | 19 +- .../commands/onScreenUpdate/60000-history.py | 52 +- .../onScreenUpdate/65000-progress_detector.py | 219 ++++--- .../onScreenUpdate/66000-prompt_detector.py | 107 ++-- .../commands/onScreenUpdate/70000-incoming.py | 31 +- .../onScreenUpdate/75000-incoming_promote.py | 34 +- .../onScreenUpdate/80000-barrier_detect.py | 17 +- .../onSwitchApplicationProfile/__init__.py | 1 - .../onSwitchApplicationProfile/default.py | 21 +- .../quickMenu/current_quick_menu_entry.py | 13 +- .../quickMenu/current_quick_menu_value.py | 10 +- .../quickMenu/next_quick_menu_entry.py | 16 +- .../quickMenu/next_quick_menu_value.py | 13 +- .../quickMenu/prev_quick_menu_entry.py | 16 +- .../quickMenu/prev_quick_menu_value.py | 13 +- .../commands/switchTrigger_template.py | 11 +- .../vmenu-navigation/curr_vmenu_entry.py | 10 +- .../vmenu-navigation/dec_level_vmenu.py | 10 +- .../vmenu-navigation/exec_vmenu_entry.py | 10 +- .../vmenu-navigation/inc_level_vmenu.py | 10 +- .../vmenu-navigation/next_vmenu_entry.py | 10 +- .../vmenu-navigation/page_down_vmenu.py | 12 +- .../vmenu-navigation/page_up_vmenu.py | 12 +- .../vmenu-navigation/prev_vmenu_entry.py | 10 +- .../commands/vmenu-navigation/search_a.py | 7 +- .../commands/vmenu-navigation/search_b.py | 7 +- .../commands/vmenu-navigation/search_c.py | 7 +- .../commands/vmenu-navigation/search_d.py | 7 +- .../commands/vmenu-navigation/search_e.py | 7 +- .../commands/vmenu-navigation/search_f.py | 7 +- .../commands/vmenu-navigation/search_g.py | 7 +- .../commands/vmenu-navigation/search_h.py | 7 +- .../commands/vmenu-navigation/search_i.py | 7 +- .../commands/vmenu-navigation/search_j.py | 7 +- .../commands/vmenu-navigation/search_k.py | 7 +- .../commands/vmenu-navigation/search_l.py | 7 +- .../commands/vmenu-navigation/search_m.py | 7 +- .../commands/vmenu-navigation/search_n.py | 7 +- .../commands/vmenu-navigation/search_o.py | 7 +- .../commands/vmenu-navigation/search_p.py | 7 +- .../commands/vmenu-navigation/search_q.py | 7 +- .../commands/vmenu-navigation/search_r.py | 7 +- .../commands/vmenu-navigation/search_s.py | 7 +- .../commands/vmenu-navigation/search_t.py | 7 +- .../commands/vmenu-navigation/search_u.py | 7 +- .../commands/vmenu-navigation/search_v.py | 7 +- .../commands/vmenu-navigation/search_w.py | 7 +- .../commands/vmenu-navigation/search_x.py | 7 +- .../commands/vmenu-navigation/search_y.py | 7 +- .../commands/vmenu-navigation/search_z.py | 7 +- .../vmenu-navigation/vmenu_search_base.py | 25 +- .../vmenu-profiles/KEY/fenrir/__init__.py | 2 +- .../vmenu-profiles/KEY/fenrir/config_base.py | 74 ++- .../fenrir/general/set_punctuation_level.py | 19 +- .../KEY/fenrir/general/toggle_debug.py | 18 +- .../KEY/fenrir/keyboard/select_layout.py | 41 +- .../KEY/fenrir/keyboard/set_char_echo.py | 19 +- .../fenrir/keyboard/toggle_grab_devices.py | 20 +- .../KEY/fenrir/keyboard/toggle_word_echo.py | 14 +- .../KEY/fenrir/management/backup_config.py | 17 +- .../KEY/fenrir/management/reload_config.py | 13 +- .../KEY/fenrir/management/reset_defaults.py | 92 ++- .../KEY/fenrir/management/revert_to_saved.py | 50 +- .../KEY/fenrir/management/save_config.py | 17 +- .../management/save_session_settings.py | 36 +- .../fenrir/management/show_unsaved_changes.py | 66 +- .../KEY/fenrir/screen/select_driver.py | 25 +- .../KEY/fenrir/screen/set_encoding.py | 20 +- .../KEY/fenrir/sound/adjust_volume.py | 26 +- .../KEY/fenrir/sound/select_driver.py | 23 +- .../KEY/fenrir/sound/select_theme.py | 35 +- .../KEY/fenrir/sound/toggle_enabled.py | 11 +- .../KEY/fenrir/speech/adjust_pitch.py | 36 +- .../KEY/fenrir/speech/adjust_rate.py | 36 +- .../KEY/fenrir/speech/adjust_speech_rate.py | 40 +- .../KEY/fenrir/speech/adjust_volume.py | 36 +- .../fenrir/speech/show_current_settings.py | 85 ++- .../vmenu-profiles/KEY/mc/file/open.py | 13 +- .../vmenu-profiles/KEY/mc/file/save.py | 13 +- .../vmenu-profiles/KEY/mc/search/replace.py | 13 +- .../vmenu-profiles/KEY/mc/search/search.py | 13 +- .../vmenu-profiles/KEY/mc/search/test.py | 24 +- .../vmenu-profiles/KEY/mutt/file/issue.py | 16 +- .../vmenu-profiles/KEY/mutt/file/open.py | 20 +- .../vmenu-profiles/KEY/mutt/file/save.py | 13 +- .../vmenu-profiles/KEY/mutt/search/replace.py | 13 +- .../vmenu-profiles/KEY/mutt/search/search.py | 13 +- .../vmenu-profiles/KEY/mutt/search/test.py | 24 +- .../KEY/nano/Help/about_nano.py | 3 + .../vmenu-profiles/KEY/nano/file/open.py | 13 +- .../vmenu-profiles/KEY/nano/file/save.py | 3 + .../vmenu-profiles/KEY/nano/search/replace.py | 13 +- .../vmenu-profiles/KEY/nano/search/search.py | 13 +- .../vmenu-profiles/KEY/nano/search/test.py | 24 +- .../vmenu-profiles/KEY/vim/file/open.py | 13 +- .../vmenu-profiles/KEY/vim/file/save.py | 13 +- .../vmenu-profiles/KEY/vim/search/replace.py | 13 +- .../vmenu-profiles/KEY/vim/search/search.py | 13 +- .../vmenu-profiles/KEY/vim/search/test.py | 24 +- .../commands/vmenu-profiles/template.py | 10 +- .../core/applicationManager.py | 12 +- .../core/attributeManager.py | 219 ++++--- src/fenrirscreenreader/core/barrierManager.py | 65 +- src/fenrirscreenreader/core/byteManager.py | 114 ++-- src/fenrirscreenreader/core/commandData.py | 14 +- src/fenrirscreenreader/core/commandManager.py | 282 +++++--- src/fenrirscreenreader/core/cursorManager.py | 75 ++- src/fenrirscreenreader/core/debug.py | 3 + src/fenrirscreenreader/core/debugManager.py | 49 +- .../core/dynamicVoiceMenu.py | 199 +++--- src/fenrirscreenreader/core/environment.py | 24 +- src/fenrirscreenreader/core/eventData.py | 3 + src/fenrirscreenreader/core/eventManager.py | 50 +- src/fenrirscreenreader/core/fenrirManager.py | 131 ++-- src/fenrirscreenreader/core/generalData.py | 41 +- src/fenrirscreenreader/core/helpManager.py | 75 ++- src/fenrirscreenreader/core/i18n.py | 7 +- src/fenrirscreenreader/core/inputData.py | 606 +++++++++++++++++- src/fenrirscreenreader/core/inputDriver.py | 26 +- src/fenrirscreenreader/core/inputManager.py | 296 ++++++--- src/fenrirscreenreader/core/memoryManager.py | 109 ++-- src/fenrirscreenreader/core/outputData.py | 8 +- src/fenrirscreenreader/core/outputManager.py | 233 +++++-- src/fenrirscreenreader/core/processManager.py | 122 +++- .../core/punctuationData.py | 20 +- .../core/punctuationManager.py | 129 ++-- .../core/quickMenuManager.py | 70 +- src/fenrirscreenreader/core/remoteDriver.py | 3 + src/fenrirscreenreader/core/remoteManager.py | 157 +++-- src/fenrirscreenreader/core/runtimeData.py | 20 +- src/fenrirscreenreader/core/sayAllManager.py | 12 +- src/fenrirscreenreader/core/screenData.py | 52 +- src/fenrirscreenreader/core/screenDriver.py | 40 +- src/fenrirscreenreader/core/screenManager.py | 252 +++++--- src/fenrirscreenreader/core/settingsData.py | 228 +++---- .../core/settingsManager.py | 472 ++++++++++---- src/fenrirscreenreader/core/soundDriver.py | 10 +- src/fenrirscreenreader/core/speechDriver.py | 20 +- src/fenrirscreenreader/core/tableManager.py | 27 +- src/fenrirscreenreader/core/textManager.py | 52 +- src/fenrirscreenreader/core/vmenuManager.py | 164 +++-- src/fenrirscreenreader/fenrirVersion.py | 2 +- .../inputDriver/debugDriver.py | 29 +- .../inputDriver/dummyDriver.py | 1 + .../inputDriver/evdevDriver.py | 350 ++++++---- .../inputDriver/ptyDriver.py | 2 + .../remoteDriver/dummyDriver.py | 1 + .../remoteDriver/tcpDriver.py | 34 +- .../remoteDriver/unixDriver.py | 51 +- .../screenDriver/dummyDriver.py | 1 + .../screenDriver/ptyDriver.py | 157 +++-- .../screenDriver/vcsaDriver.py | 345 ++++++---- .../soundDriver/debugDriver.py | 33 +- .../soundDriver/dummyDriver.py | 1 + .../soundDriver/genericDriver.py | 38 +- .../soundDriver/gstreamerDriver.py | 33 +- .../speechDriver/debugDriver.py | 12 +- .../speechDriver/dummyDriver.py | 1 + .../speechDriver/genericDriver.py | 130 ++-- .../speechDriver/speechdDriver.py | 52 +- src/fenrirscreenreader/utils/char_utils.py | 90 +-- src/fenrirscreenreader/utils/fenrir-config.py | 5 +- src/fenrirscreenreader/utils/line_utils.py | 13 +- src/fenrirscreenreader/utils/mark_utils.py | 37 +- src/fenrirscreenreader/utils/module_utils.py | 12 +- src/fenrirscreenreader/utils/review_utils.py | 1 - src/fenrirscreenreader/utils/screen_utils.py | 49 +- src/fenrirscreenreader/utils/word_utils.py | 53 +- 345 files changed, 8688 insertions(+), 3852 deletions(-) diff --git a/src/fenrirscreenreader/commands/command_template.py b/src/fenrirscreenreader/commands/command_template.py index 4063c950..ae45dc50 100644 --- a/src/fenrirscreenreader/commands/command_template.py +++ b/src/fenrirscreenreader/commands/command_template.py @@ -5,16 +5,24 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): pass + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/00_init_commands.py b/src/fenrirscreenreader/commands/commands/00_init_commands.py index 6457a1cc..a851b7b1 100644 --- a/src/fenrirscreenreader/commands/commands/00_init_commands.py +++ b/src/fenrirscreenreader/commands/commands/00_init_commands.py @@ -8,18 +8,29 @@ # this command is just to initialize stuff. # like init index lists in memoryManager # it is not useful to execute it + +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment # clipboard - self.env['runtime']['memoryManager'].addIndexList('clipboardHistory', self.env['runtime']['settingsManager'].getSettingAsInt('general', 'numberOfClipboards')) + self.env['runtime']['memoryManager'].addIndexList( + 'clipboardHistory', self.env['runtime']['settingsManager'].getSettingAsInt( + 'general', 'numberOfClipboards')) + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): pass + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/add_word_to_spell_check.py b/src/fenrirscreenreader/commands/commands/add_word_to_spell_check.py index 4f62a3d0..c94ef936 100644 --- a/src/fenrirscreenreader/commands/commands/add_word_to_spell_check.py +++ b/src/fenrirscreenreader/commands/commands/add_word_to_spell_check.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import word_utils import string initialized = False @@ -12,42 +14,59 @@ try: initialized = True except Exception as e: pass - + + class command(): def __init__(self): self.language = '' self.spellChecker = None + def initialize(self, environment): self.env = environment self.updateSpellLanguage() + def shutdown(self): - pass + pass + def getDescription(self): - return _('adds the current word to the exceptions dictionary') - def updateSpellLanguage(self): - self.spellChecker = enchant.Dict(self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage')) - self.language = self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') - + return _('adds the current word to the exceptions dictionary') + + def updateSpellLanguage(self): + self.spellChecker = enchant.Dict( + self.env['runtime']['settingsManager'].getSetting( + 'general', 'spellCheckLanguage')) + self.language = self.env['runtime']['settingsManager'].getSetting( + 'general', 'spellCheckLanguage') + def run(self): if not initialized: - return - if self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') != self.language: + return + if self.env['runtime']['settingsManager'].getSetting( + 'general', 'spellCheckLanguage') != self.language: try: self.updateSpellLanguage() except Exception as e: - return + return cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() # get the word - newContent = self.env['screen']['newContentText'].split('\n')[cursorPos['y']] - x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord(cursorPos['x'], 0, newContent) - currWord = currWord.strip(string.whitespace + r'!"#$%&\()*+,-./:;<=Â?@[\\]^_{|}~') + newContent = self.env['screen']['newContentText'].split('\n')[ + cursorPos['y']] + x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord( + cursorPos['x'], 0, newContent) + currWord = currWord.strip( + string.whitespace + + r'!"#$%&\()*+,-./:;<=Â?@[\\]^_{|}~') if currWord != '': if self.spellChecker.is_added(currWord): - self.env['runtime']['outputManager'].presentText(_('{0} is already in dictionary').format(currWord,), soundIcon='Cancel', interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('{0} is already in dictionary').format( + currWord,), soundIcon='Cancel', interrupt=True) else: - self.spellChecker.add(currWord) - self.env['runtime']['outputManager'].presentText(_('{0} added to dictionary').format(currWord,), soundIcon='Accept', interrupt=True) + self.spellChecker.add(currWord) + self.env['runtime']['outputManager'].presentText( + _('{0} added to dictionary').format( + currWord,), soundIcon='Accept', interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/adjustment_base.py b/src/fenrirscreenreader/commands/commands/adjustment_base.py index 575c0abd..7c013689 100644 --- a/src/fenrirscreenreader/commands/commands/adjustment_base.py +++ b/src/fenrirscreenreader/commands/commands/adjustment_base.py @@ -4,29 +4,33 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import math + class AdjustmentCommand(): """Base class for speech and sound adjustment commands""" + def __init__(self, section, setting, direction, step=0.1): self.section = section # 'speech' or 'sound' self.setting = setting # 'rate', 'pitch', 'volume' self.direction = direction # 'inc' or 'dec' self.step = step - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): action = "Increase" if self.direction == 'inc' else "Decrease" if self.section == 'speech': return _(f'{action} the speech {self.setting}') else: return _(f'{action} the {self.section} {self.setting}') - + def run(self): if self.section == 'sound' and self.setting == 'volume': # Sound volume uses different method @@ -34,11 +38,12 @@ class AdjustmentCommand(): else: # Speech rate, pitch, volume use standard method self._adjust_speech_setting() - + def _adjust_speech_setting(self): """Adjust speech settings (rate, pitch, volume)""" - value = self.env['runtime']['settingsManager'].getSettingAsFloat(self.section, self.setting) - + value = self.env['runtime']['settingsManager'].getSettingAsFloat( + self.section, self.setting) + # Apply adjustment with rounding if self.direction == 'inc': value = round((math.ceil(10 * value) / 10) + self.step, 2) @@ -48,23 +53,28 @@ class AdjustmentCommand(): value = round((math.ceil(10 * value) / 10) - self.step, 2) if value < 0.0: value = 0.0 - + # Set the new value - self.env['runtime']['settingsManager'].setSetting(self.section, self.setting, str(value)) - + self.env['runtime']['settingsManager'].setSetting( + self.section, self.setting, str(value)) + # Present feedback percentage = int(value * 100) if self.section == 'speech': - feedback = _("{0} percent speech {1}").format(percentage, self.setting) + feedback = _("{0} percent speech {1}").format( + percentage, self.setting) else: - feedback = _("{0} percent {1} {2}").format(percentage, self.section, self.setting) - - self.env['runtime']['outputManager'].presentText(feedback, soundIcon='', interrupt=True) - + feedback = _("{0} percent {1} {2}").format( + percentage, self.section, self.setting) + + self.env['runtime']['outputManager'].presentText( + feedback, soundIcon='', interrupt=True) + def _adjust_sound_volume(self): """Adjust sound volume using same logic as speech""" - value = self.env['runtime']['settingsManager'].getSettingAsFloat(self.section, self.setting) - + value = self.env['runtime']['settingsManager'].getSettingAsFloat( + self.section, self.setting) + # Sound volume uses same math as speech settings if self.direction == 'inc': value = round((math.ceil(10 * value) / 10) + self.step, 2) @@ -74,15 +84,17 @@ class AdjustmentCommand(): value = round((math.ceil(10 * value) / 10) - self.step, 2) if value < 0.0: value = 0.0 - + # Set the new value - self.env['runtime']['settingsManager'].setSetting(self.section, self.setting, str(value)) - + self.env['runtime']['settingsManager'].setSetting( + self.section, self.setting, str(value)) + # Present feedback with appropriate sound icon percentage = int(value * 100) sound_icon = 'SoundOn' if self.direction == 'inc' else 'SoundOff' feedback = _("{0} percent sound volume").format(percentage) - self.env['runtime']['outputManager'].presentText(feedback, soundIcon=sound_icon, interrupt=True) - + self.env['runtime']['outputManager'].presentText( + feedback, soundIcon=sound_icon, interrupt=True) + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/commands/announce_fenrir_version.py b/src/fenrirscreenreader/commands/commands/announce_fenrir_version.py index 6adc18f7..ba3d888f 100644 --- a/src/fenrirscreenreader/commands/commands/announce_fenrir_version.py +++ b/src/fenrirscreenreader/commands/commands/announce_fenrir_version.py @@ -4,23 +4,33 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader import fenrirVersion + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): return _('Present the version of Fenrir currrrently in use.') - + def run(self): try: - self.env['runtime']['outputManager'].presentText(f'Fenrir screen reader version {fenrirVersion.version}-{fenrirVersion.codeName}', interrupt=True) - except exception as e: - self.env['runtime']['outputManager'].presentText(_('Version information is unavailable.'), interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f'Fenrir screen reader version { + fenrirVersion.version}-{ + fenrirVersion.codeName}', interrupt=True) + except Exception as e: + self.env['runtime']['outputManager'].presentText( + _('Version information is unavailable.'), interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/apply_tested_voice.py b/src/fenrirscreenreader/commands/commands/apply_tested_voice.py index 91cbc047..548ce411 100644 --- a/src/fenrirscreenreader/commands/commands/apply_tested_voice.py +++ b/src/fenrirscreenreader/commands/commands/apply_tested_voice.py @@ -1,71 +1,82 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Apply the last tested voice from safe voice browser" - + def run(self): try: # Check if we have a tested voice - if ('commandBuffer' not in self.env or + if ('commandBuffer' not in self.env or 'lastTestedModule' not in self.env['commandBuffer'] or - 'lastTestedVoice' not in self.env['commandBuffer']): - self.env['runtime']['outputManager'].presentText("No voice has been tested yet", interrupt=True) - self.env['runtime']['outputManager'].presentText("Use voice browser first", interrupt=True) + 'lastTestedVoice' not in self.env['commandBuffer']): + self.env['runtime']['outputManager'].presentText( + "No voice has been tested yet", interrupt=True) + self.env['runtime']['outputManager'].presentText( + "Use voice browser first", interrupt=True) return - + module = self.env['commandBuffer']['lastTestedModule'] voice = self.env['commandBuffer']['lastTestedVoice'] - - self.env['runtime']['outputManager'].presentText(f"Applying {voice} from {module}", interrupt=True) - + + self.env['runtime']['outputManager'].presentText( + f"Applying {voice} from {module}", interrupt=True) + # Apply to runtime settings only (temporary until saved) settingsManager = self.env['runtime']['settingsManager'] - + # Store old values for safety oldDriver = settingsManager.getSetting('speech', 'driver') oldModule = settingsManager.getSetting('speech', 'module') oldVoice = settingsManager.getSetting('speech', 'voice') - + try: - # Apply new settings to runtime only (use setSetting to update settingArgDict) + # Apply new settings to runtime only (use setSetting to update + # settingArgDict) settingsManager.setSetting('speech', 'driver', 'speechdDriver') settingsManager.setSetting('speech', 'module', module) settingsManager.setSetting('speech', 'voice', voice) - + # Apply to speech driver instance directly if 'speechDriver' in self.env['runtime']: speechDriver = self.env['runtime']['speechDriver'] - + # Set the module and voice on the driver instance speechDriver.setModule(module) speechDriver.setVoice(voice) - - self.env['runtime']['outputManager'].presentText("Voice applied successfully!", interrupt=True) - self.env['runtime']['outputManager'].presentText("Use save settings to make permanent", interrupt=True) + + self.env['runtime']['outputManager'].presentText( + "Voice applied successfully!", interrupt=True) + self.env['runtime']['outputManager'].presentText( + "Use save settings to make permanent", interrupt=True) self.env['runtime']['outputManager'].playSound('Accept') - + except Exception as e: # Revert on failure settingsManager.setSetting('speech', 'driver', oldDriver) settingsManager.setSetting('speech', 'module', oldModule) settingsManager.setSetting('speech', 'voice', oldVoice) - - self.env['runtime']['outputManager'].presentText(f"Failed to apply voice, reverted: {str(e)}", interrupt=True) + + self.env['runtime']['outputManager'].presentText( + f"Failed to apply voice, reverted: {str(e)}", interrupt=True) self.env['runtime']['outputManager'].playSound('Error') - + except Exception as e: - self.env['runtime']['outputManager'].presentText(f"Apply voice error: {str(e)}", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Apply voice error: {str(e)}", interrupt=True) self.env['runtime']['outputManager'].playSound('Error') - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/commands/attribute_cursor.py b/src/fenrirscreenreader/commands/commands/attribute_cursor.py index ec8010e1..b8bc48c4 100644 --- a/src/fenrirscreenreader/commands/commands/attribute_cursor.py +++ b/src/fenrirscreenreader/commands/commands/attribute_cursor.py @@ -4,26 +4,38 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import screen_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return _('Reads attributes of current cursor position') + return _('Reads attributes of current cursor position') + def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() try: - attributes = self.env['runtime']['attributeManager'].getAttributeByXY( cursorPos['x'], cursorPos['y']) + attributes = self.env['runtime']['attributeManager'].getAttributeByXY( + cursorPos['x'], cursorPos['y']) except Exception as e: - print(e) - attributeFormatString = self.env['runtime']['settingsManager'].getSetting('general', 'attributeFormatString') - attributeFormatString = self.env['runtime']['attributeManager'].formatAttributes(attributes, attributeFormatString) - - self.env['runtime']['outputManager'].presentText(attributeFormatString, soundIcon='', interrupt=True) + print(e) + attributeFormatString = self.env['runtime']['settingsManager'].getSetting( + 'general', 'attributeFormatString') + attributeFormatString = self.env['runtime']['attributeManager'].formatAttributes( + attributes, attributeFormatString) + + self.env['runtime']['outputManager'].presentText( + attributeFormatString, soundIcon='', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/bookmark_1.py b/src/fenrirscreenreader/commands/commands/bookmark_1.py index 13e6f54a..ecff295d 100644 --- a/src/fenrirscreenreader/commands/commands/bookmark_1.py +++ b/src/fenrirscreenreader/commands/commands/bookmark_1.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(1, 'read') diff --git a/src/fenrirscreenreader/commands/commands/bookmark_10.py b/src/fenrirscreenreader/commands/commands/bookmark_10.py index 1ea9c79f..f1087fb8 100644 --- a/src/fenrirscreenreader/commands/commands/bookmark_10.py +++ b/src/fenrirscreenreader/commands/commands/bookmark_10.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(10, 'read') diff --git a/src/fenrirscreenreader/commands/commands/bookmark_2.py b/src/fenrirscreenreader/commands/commands/bookmark_2.py index 8e93d4e1..4cde7da6 100644 --- a/src/fenrirscreenreader/commands/commands/bookmark_2.py +++ b/src/fenrirscreenreader/commands/commands/bookmark_2.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(2, 'read') diff --git a/src/fenrirscreenreader/commands/commands/bookmark_3.py b/src/fenrirscreenreader/commands/commands/bookmark_3.py index 168224af..a2663955 100644 --- a/src/fenrirscreenreader/commands/commands/bookmark_3.py +++ b/src/fenrirscreenreader/commands/commands/bookmark_3.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(3, 'read') diff --git a/src/fenrirscreenreader/commands/commands/bookmark_4.py b/src/fenrirscreenreader/commands/commands/bookmark_4.py index 913c31e4..993ce59d 100644 --- a/src/fenrirscreenreader/commands/commands/bookmark_4.py +++ b/src/fenrirscreenreader/commands/commands/bookmark_4.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(4, 'read') diff --git a/src/fenrirscreenreader/commands/commands/bookmark_5.py b/src/fenrirscreenreader/commands/commands/bookmark_5.py index f5556fa7..1fbeb328 100644 --- a/src/fenrirscreenreader/commands/commands/bookmark_5.py +++ b/src/fenrirscreenreader/commands/commands/bookmark_5.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(5, 'read') diff --git a/src/fenrirscreenreader/commands/commands/bookmark_6.py b/src/fenrirscreenreader/commands/commands/bookmark_6.py index 729fe1f3..07085d78 100644 --- a/src/fenrirscreenreader/commands/commands/bookmark_6.py +++ b/src/fenrirscreenreader/commands/commands/bookmark_6.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(6, 'read') diff --git a/src/fenrirscreenreader/commands/commands/bookmark_7.py b/src/fenrirscreenreader/commands/commands/bookmark_7.py index 8387c77a..4e617723 100644 --- a/src/fenrirscreenreader/commands/commands/bookmark_7.py +++ b/src/fenrirscreenreader/commands/commands/bookmark_7.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(7, 'read') diff --git a/src/fenrirscreenreader/commands/commands/bookmark_8.py b/src/fenrirscreenreader/commands/commands/bookmark_8.py index f1e4c799..dca2f81a 100644 --- a/src/fenrirscreenreader/commands/commands/bookmark_8.py +++ b/src/fenrirscreenreader/commands/commands/bookmark_8.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(8, 'read') diff --git a/src/fenrirscreenreader/commands/commands/bookmark_9.py b/src/fenrirscreenreader/commands/commands/bookmark_9.py index 04da752b..50b122ab 100644 --- a/src/fenrirscreenreader/commands/commands/bookmark_9.py +++ b/src/fenrirscreenreader/commands/commands/bookmark_9.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(9, 'read') diff --git a/src/fenrirscreenreader/commands/commands/bookmark_base.py b/src/fenrirscreenreader/commands/commands/bookmark_base.py index 4bb4930f..755deeef 100644 --- a/src/fenrirscreenreader/commands/commands/bookmark_base.py +++ b/src/fenrirscreenreader/commands/commands/bookmark_base.py @@ -4,27 +4,30 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.utils import line_utils +from fenrirscreenreader.utils import mark_utils +from fenrirscreenreader.core.i18n import _ + import gettext _ = gettext.gettext -from fenrirscreenreader.utils import mark_utils -from fenrirscreenreader.utils import line_utils class BookmarkCommand(): """Base class for bookmark operations - read, set, clear""" + def __init__(self, bookmark_id, action='read'): self.ID = str(bookmark_id) self.action = action - + def initialize(self, environment): self.env = environment # Always initialize bookmark structure - all commands need this if self.ID not in self.env['commandBuffer']['bookMarks']: self.env['commandBuffer']['bookMarks'][self.ID] = {} - + def shutdown(self): pass - + def getDescription(self): if self.action == 'read': return _('read Bookmark {0}').format(self.ID) @@ -33,7 +36,7 @@ class BookmarkCommand(): elif self.action == 'clear': return _('remove Bookmark {0}').format(self.ID) return f'{self.action} Bookmark {self.ID}' - + def run(self): if self.action == 'read': self._read_bookmark() @@ -41,92 +44,114 @@ class BookmarkCommand(): self._set_bookmark() elif self.action == 'clear': self._clear_bookmark() - + def _read_bookmark(self): currApp = self.env['runtime']['applicationManager'].getCurrentApplication() - + if not self.env['commandBuffer']['bookMarks'][self.ID]: - self.env['runtime']['outputManager'].presentText('Bookmark {0} not set'.format(self.ID), interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'Bookmark {0} not set'.format(self.ID), interrupt=True) return - + if currApp not in self.env['commandBuffer']['bookMarks'][self.ID]: - self.env['runtime']['outputManager'].presentText('Bookmark for application {0} not set'.format(currApp), interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'Bookmark for application {0} not set'.format(currApp), interrupt=True) return - - if not self.env['commandBuffer']['bookMarks'][self.ID][currApp].get('1'): - self.env['runtime']['outputManager'].presentText('Bookmark for application {0} not set'.format(currApp), interrupt=True) + + if not self.env['commandBuffer']['bookMarks'][self.ID][currApp].get( + '1'): + self.env['runtime']['outputManager'].presentText( + 'Bookmark for application {0} not set'.format(currApp), interrupt=True) return # Get bookmarked text marked = '' - startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy() - + startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy( + ) + if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']: - endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy() - marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText']) + endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy( + ) + marked = mark_utils.getTextBetweenMarks( + startMark, endMark, self.env['screen']['newContentText']) else: - x, y, marked = line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText']) - + x, y, marked = line_utils.getCurrentLine( + startMark['x'], startMark['y'], self.env['screen']['newContentText']) + if marked.isspace(): - self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('blank'), soundIcon='EmptyLine', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(marked, interrupt=True) - + self.env['runtime']['outputManager'].presentText( + marked, interrupt=True) + def _set_bookmark(self): if not self.env['commandBuffer']['Marks']['1']: - self.env['runtime']['outputManager'].presentText(_("No mark found"), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _("No mark found"), interrupt=True) return - + currApp = self.env['runtime']['applicationManager'].getCurrentApplication() self.env['commandBuffer']['bookMarks'][self.ID][currApp] = {} - + self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'] = self.env['commandBuffer']['Marks']['1'].copy() - + if self.env['commandBuffer']['Marks']['2']: self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'] = self.env['commandBuffer']['Marks']['2'].copy() else: self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'] = None - - self.env['runtime']['outputManager'].presentText(_('Bookmark {0} set for application {1}').format(self.ID, currApp), interrupt=True) - + + self.env['runtime']['outputManager'].presentText( + _('Bookmark {0} set for application {1}').format( + self.ID, currApp), interrupt=True) + # Clear marks after setting bookmark self.env['commandBuffer']['Marks']['1'] = None self.env['commandBuffer']['Marks']['2'] = None - + def _clear_bookmark(self): currApp = self.env['runtime']['applicationManager'].getCurrentApplication() - + if self.ID in self.env['commandBuffer']['bookMarks'] and currApp in self.env['commandBuffer']['bookMarks'][self.ID]: del self.env['commandBuffer']['bookMarks'][self.ID][currApp] - self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('Bookmark {0} removed for application {1}').format( + self.ID, currApp), interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set for application {1}').format(self.ID, currApp), interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _('Bookmark {0} not set for application {1}').format( + self.ID, currApp), interrupt=True) + def setCallback(self, callback): pass # Factory function to create bookmark command instances + + def create_bookmark_commands(): """Create all bookmark command instances""" commands = {} - + # Create read bookmark commands (bookmark_1 through bookmark_10) for i in range(1, 11): commands[f'bookmark_{i}'] = lambda i=i: BookmarkCommand(i, 'read') - + # Create set bookmark commands (set_bookmark_1 through set_bookmark_10) for i in range(1, 11): commands[f'set_bookmark_{i}'] = lambda i=i: BookmarkCommand(i, 'set') - - # Create clear bookmark commands (clear_bookmark_1 through clear_bookmark_10) + + # Create clear bookmark commands (clear_bookmark_1 through + # clear_bookmark_10) for i in range(1, 11): - commands[f'clear_bookmark_{i}'] = lambda i=i: BookmarkCommand(i, 'clear') - + commands[f'clear_bookmark_{i}'] = lambda i=i: BookmarkCommand( + i, 'clear') + return commands # For backwards compatibility, provide individual command classes # This allows the existing command loading system to work unchanged + def _make_command_class(bookmark_id, action): """Create a command class for a specific bookmark and action""" class command(BookmarkCommand): @@ -137,14 +162,15 @@ def _make_command_class(bookmark_id, action): # Generate individual command classes for each bookmark operation # These will be used by the existing command loading system + # Read bookmarks (bookmark_1.py style) for i in range(1, 11): globals()[f'bookmark_{i}_command'] = _make_command_class(i, 'read') -# Set bookmarks (set_bookmark_1.py style) +# Set bookmarks (set_bookmark_1.py style) for i in range(1, 11): globals()[f'set_bookmark_{i}_command'] = _make_command_class(i, 'set') # Clear bookmarks (clear_bookmark_1.py style) for i in range(1, 11): - globals()[f'clear_bookmark_{i}_command'] = _make_command_class(i, 'clear') \ No newline at end of file + globals()[f'clear_bookmark_{i}_command'] = _make_command_class(i, 'clear') diff --git a/src/fenrirscreenreader/commands/commands/clear_bookmark_1.py b/src/fenrirscreenreader/commands/commands/clear_bookmark_1.py index 4bbd2977..393a90d6 100644 --- a/src/fenrirscreenreader/commands/commands/clear_bookmark_1.py +++ b/src/fenrirscreenreader/commands/commands/clear_bookmark_1.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(1, 'clear') diff --git a/src/fenrirscreenreader/commands/commands/clear_bookmark_10.py b/src/fenrirscreenreader/commands/commands/clear_bookmark_10.py index 56642bec..40a4a733 100644 --- a/src/fenrirscreenreader/commands/commands/clear_bookmark_10.py +++ b/src/fenrirscreenreader/commands/commands/clear_bookmark_10.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(10, 'clear') diff --git a/src/fenrirscreenreader/commands/commands/clear_bookmark_2.py b/src/fenrirscreenreader/commands/commands/clear_bookmark_2.py index 11d4d4ac..4dd93e4b 100644 --- a/src/fenrirscreenreader/commands/commands/clear_bookmark_2.py +++ b/src/fenrirscreenreader/commands/commands/clear_bookmark_2.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(2, 'clear') diff --git a/src/fenrirscreenreader/commands/commands/clear_bookmark_3.py b/src/fenrirscreenreader/commands/commands/clear_bookmark_3.py index 5b94bf72..9225de52 100644 --- a/src/fenrirscreenreader/commands/commands/clear_bookmark_3.py +++ b/src/fenrirscreenreader/commands/commands/clear_bookmark_3.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(3, 'clear') diff --git a/src/fenrirscreenreader/commands/commands/clear_bookmark_4.py b/src/fenrirscreenreader/commands/commands/clear_bookmark_4.py index 6b970a83..53d78c29 100644 --- a/src/fenrirscreenreader/commands/commands/clear_bookmark_4.py +++ b/src/fenrirscreenreader/commands/commands/clear_bookmark_4.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(4, 'clear') diff --git a/src/fenrirscreenreader/commands/commands/clear_bookmark_5.py b/src/fenrirscreenreader/commands/commands/clear_bookmark_5.py index 2a6ad9c7..6dfc9319 100644 --- a/src/fenrirscreenreader/commands/commands/clear_bookmark_5.py +++ b/src/fenrirscreenreader/commands/commands/clear_bookmark_5.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(5, 'clear') diff --git a/src/fenrirscreenreader/commands/commands/clear_bookmark_6.py b/src/fenrirscreenreader/commands/commands/clear_bookmark_6.py index 15521a9d..5de61273 100644 --- a/src/fenrirscreenreader/commands/commands/clear_bookmark_6.py +++ b/src/fenrirscreenreader/commands/commands/clear_bookmark_6.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(6, 'clear') diff --git a/src/fenrirscreenreader/commands/commands/clear_bookmark_7.py b/src/fenrirscreenreader/commands/commands/clear_bookmark_7.py index d318ab79..1efda24d 100644 --- a/src/fenrirscreenreader/commands/commands/clear_bookmark_7.py +++ b/src/fenrirscreenreader/commands/commands/clear_bookmark_7.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(7, 'clear') diff --git a/src/fenrirscreenreader/commands/commands/clear_bookmark_8.py b/src/fenrirscreenreader/commands/commands/clear_bookmark_8.py index 867c337b..ab1e0adb 100644 --- a/src/fenrirscreenreader/commands/commands/clear_bookmark_8.py +++ b/src/fenrirscreenreader/commands/commands/clear_bookmark_8.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(8, 'clear') diff --git a/src/fenrirscreenreader/commands/commands/clear_bookmark_9.py b/src/fenrirscreenreader/commands/commands/clear_bookmark_9.py index b579d0cc..a1f88b65 100644 --- a/src/fenrirscreenreader/commands/commands/clear_bookmark_9.py +++ b/src/fenrirscreenreader/commands/commands/clear_bookmark_9.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(9, 'clear') diff --git a/src/fenrirscreenreader/commands/commands/clear_clipboard.py b/src/fenrirscreenreader/commands/commands/clear_clipboard.py index a8d6126f..17140fd8 100644 --- a/src/fenrirscreenreader/commands/commands/clear_clipboard.py +++ b/src/fenrirscreenreader/commands/commands/clear_clipboard.py @@ -5,19 +5,28 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('clears the currently selected clipboard') + return _('clears the currently selected clipboard') def run(self): - self.env['runtime']['memoryManager'].clearCurrentIndexList('clipboardHistory') - self.env['runtime']['outputManager'].presentText(_('clipboard cleared'), interrupt=True) - return + self.env['runtime']['memoryManager'].clearCurrentIndexList( + 'clipboardHistory') + self.env['runtime']['outputManager'].presentText( + _('clipboard cleared'), interrupt=True) + return + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/clear_window_application.py b/src/fenrirscreenreader/commands/commands/clear_window_application.py index 31e436eb..0c31cefd 100644 --- a/src/fenrirscreenreader/commands/commands/clear_window_application.py +++ b/src/fenrirscreenreader/commands/commands/clear_window_application.py @@ -5,22 +5,32 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('Turn off window mode for application') - + def run(self): if self.env['runtime']['cursorManager'].clearWindowForApplication(): - currApp = self.env['runtime']['applicationManager'].getCurrentApplication() - self.env['runtime']['outputManager'].presentText(_('Window Mode off for application {0}').format(currApp,), interrupt=True) + currApp = self.env['runtime']['applicationManager'].getCurrentApplication( + ) + self.env['runtime']['outputManager'].presentText( + _('Window Mode off for application {0}').format( + currApp,), interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_("Not in window Mode"), interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("Not in window Mode"), interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/copy_last_echo_to_clipboard.py b/src/fenrirscreenreader/commands/commands/copy_last_echo_to_clipboard.py index f8b56722..a63f0563 100644 --- a/src/fenrirscreenreader/commands/commands/copy_last_echo_to_clipboard.py +++ b/src/fenrirscreenreader/commands/commands/copy_last_echo_to_clipboard.py @@ -4,24 +4,32 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import mark_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('copies last presented text to the clipboard') - + return _('copies last presented text to the clipboard') + def run(self): lastEcho = self.env['runtime']['outputManager'].getLastEcho() if lastEcho.rstrip() != "": lastEcho = lastEcho.rstrip() - self.env['runtime']['memoryManager'].addValueToFirstIndex('clipboardHistory', lastEcho) - self.env['runtime']['outputManager'].presentText(lastEcho, soundIcon='CopyToClipboard', interrupt=True) + self.env['runtime']['memoryManager'].addValueToFirstIndex( + 'clipboardHistory', lastEcho) + self.env['runtime']['outputManager'].presentText( + lastEcho, soundIcon='CopyToClipboard', interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/copy_marked_to_clipboard.py b/src/fenrirscreenreader/commands/commands/copy_marked_to_clipboard.py index 806aac3e..134210d6 100644 --- a/src/fenrirscreenreader/commands/commands/copy_marked_to_clipboard.py +++ b/src/fenrirscreenreader/commands/commands/copy_marked_to_clipboard.py @@ -2,72 +2,79 @@ # -*- coding: utf-8 -*- +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import mark_utils + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): - pass - + pass + def getDescription(self): - return _('copies marked text to the currently selected clipboard') - + return _('copies marked text to the currently selected clipboard') + def getTextFromScreen(self, startMark, endMark): screenContent = self.env['screen']['newContentText'] screenLines = screenContent.split('\n') - + startY = min(startMark['y'], len(screenLines) - 1) endY = min(endMark['y'], len(screenLines) - 1) - + # If marks are on the same line if startY == endY: line = screenLines[startY] startX = min(startMark['x'], len(line)) endX = min(endMark['x'], len(line)) + 1 return line[startX:endX] - + # Handle multi-line selection result = [] - + # First line (from start mark to end of line) firstLine = screenLines[startY] startX = min(startMark['x'], len(firstLine)) result.append(firstLine[startX:].rstrip()) - + # Middle lines (complete lines) for lineNum in range(startY + 1, endY): result.append(screenLines[lineNum].rstrip()) - + # Last line (from start to end mark) if endY > startY: lastLine = screenLines[endY] endX = min(endMark['x'], len(lastLine)) + 1 result.append(lastLine[:endX].rstrip()) - + return '\n'.join(result) - + def run(self): if not self.env['commandBuffer']['Marks']['1']: - self.env['runtime']['outputManager'].presentText(_("One or two marks are needed"), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _("One or two marks are needed"), interrupt=True) return if not self.env['commandBuffer']['Marks']['2']: self.env['runtime']['cursorManager'].setMark() - + # use the last first and the last setted mark as range startMark = self.env['commandBuffer']['Marks']['1'].copy() - endMark = self.env['commandBuffer']['Marks']['2'].copy() - + endMark = self.env['commandBuffer']['Marks']['2'].copy() + # Replace mark_utils.getTextBetweenMarks with our new method marked = self.getTextFromScreen(startMark, endMark) - - self.env['runtime']['memoryManager'].addValueToFirstIndex('clipboardHistory', marked) + + self.env['runtime']['memoryManager'].addValueToFirstIndex( + 'clipboardHistory', marked) # reset marks - self.env['runtime']['cursorManager'].clearMarks() - self.env['runtime']['outputManager'].presentText(marked, soundIcon='CopyToClipboard', interrupt=True) - + self.env['runtime']['cursorManager'].clearMarks() + self.env['runtime']['outputManager'].presentText( + marked, soundIcon='CopyToClipboard', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/curr_clipboard.py b/src/fenrirscreenreader/commands/commands/curr_clipboard.py index 0031f835..c2e11e17 100644 --- a/src/fenrirscreenreader/commands/commands/curr_clipboard.py +++ b/src/fenrirscreenreader/commands/commands/curr_clipboard.py @@ -5,22 +5,32 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('speaks the contents of the currently selected clipboard') + return _('speaks the contents of the currently selected clipboard') def run(self): - if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'): - self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True) - return - clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory') - self.env['runtime']['outputManager'].presentText(clipboard , interrupt=True) - + if self.env['runtime']['memoryManager'].isIndexListEmpty( + 'clipboardHistory'): + self.env['runtime']['outputManager'].presentText( + _('clipboard empty'), interrupt=True) + return + clipboard = self.env['runtime']['memoryManager'].getIndexListElement( + 'clipboardHistory') + self.env['runtime']['outputManager'].presentText( + clipboard, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/curr_screen.py b/src/fenrirscreenreader/commands/commands/curr_screen.py index de87910b..c34ea2d7 100644 --- a/src/fenrirscreenreader/commands/commands/curr_screen.py +++ b/src/fenrirscreenreader/commands/commands/curr_screen.py @@ -5,21 +5,29 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('reads the contents of the current screen') + return _('reads the contents of the current screen') def run(self): if self.env['screen']['newContentText'].isspace(): - self.env['runtime']['outputManager'].presentText(_("screen is empty"), soundIcon='EmptyLine', interrupt=True) - else: - self.env['runtime']['outputManager'].presentText(self.env['screen']['newContentText'],interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("screen is empty"), soundIcon='EmptyLine', interrupt=True) + else: + self.env['runtime']['outputManager'].presentText( + self.env['screen']['newContentText'], interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/curr_screen_after_cursor.py b/src/fenrirscreenreader/commands/commands/curr_screen_after_cursor.py index 6269458a..9d274070 100644 --- a/src/fenrirscreenreader/commands/commands/curr_screen_after_cursor.py +++ b/src/fenrirscreenreader/commands/commands/curr_screen_after_cursor.py @@ -4,28 +4,37 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import mark_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('reads from the cursor to the bottom of the screen') + return _('reads from the cursor to the bottom of the screen') def run(self): # Prefer review cursor over text cursor cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - textAfterCursor = mark_utils.getTextAfterMark(cursorPos, self.env['screen']['newContentText']) + textAfterCursor = mark_utils.getTextAfterMark( + cursorPos, self.env['screen']['newContentText']) if textAfterCursor.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True) + self.env['runtime']['outputManager'].presentText( + _("blank"), soundIcon='EmptyLine', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(textAfterCursor, interrupt=True) + self.env['runtime']['outputManager'].presentText( + textAfterCursor, interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/curr_screen_before_cursor.py b/src/fenrirscreenreader/commands/commands/curr_screen_before_cursor.py index 7d0afbfc..b8c3f25c 100644 --- a/src/fenrirscreenreader/commands/commands/curr_screen_before_cursor.py +++ b/src/fenrirscreenreader/commands/commands/curr_screen_before_cursor.py @@ -4,17 +4,23 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import mark_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('Reads from the top of the screen to the cursor position') + return _('Reads from the top of the screen to the cursor position') def run(self): # Prefer review cursor over text cursor @@ -23,13 +29,15 @@ class command(): else: cursorPos = self.env['screen']['newCursor'].copy() - textBeforeCursor = mark_utils.getTextBeforeMark(cursorPos, self.env['screen']['newContentText']) + textBeforeCursor = mark_utils.getTextBeforeMark( + cursorPos, self.env['screen']['newContentText']) if textBeforeCursor.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True) + self.env['runtime']['outputManager'].presentText( + _("blank"), soundIcon='EmptyLine', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(textBeforeCursor, interrupt=True) - + self.env['runtime']['outputManager'].presentText( + textBeforeCursor, interrupt=True) + def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/commands/current_quick_menu_entry.py b/src/fenrirscreenreader/commands/commands/current_quick_menu_entry.py index a89ce3ee..f0232482 100644 --- a/src/fenrirscreenreader/commands/commands/current_quick_menu_entry.py +++ b/src/fenrirscreenreader/commands/commands/current_quick_menu_entry.py @@ -5,21 +5,30 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get current quick menu entry') + def run(self): menu = '' value = '' menu = self.env['runtime']['quickMenuManager'].getCurrentEntry() if menu != '': value = self.env['runtime']['quickMenuManager'].getCurrentValue() - self.env['runtime']['outputManager'].presentText(menu + ' ' + value, interrupt=True) + self.env['runtime']['outputManager'].presentText( + menu + ' ' + value, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/current_quick_menu_value.py b/src/fenrirscreenreader/commands/commands/current_quick_menu_value.py index 6522e080..23a3a75c 100644 --- a/src/fenrirscreenreader/commands/commands/current_quick_menu_value.py +++ b/src/fenrirscreenreader/commands/commands/current_quick_menu_value.py @@ -5,17 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get current quick menu value') + def run(self): value = self.env['runtime']['quickMenuManager'].getCurrentValue() self.env['runtime']['outputManager'].presentText(value, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/cursor_column.py b/src/fenrirscreenreader/commands/commands/cursor_column.py index f6a9bb82..ce79c300 100644 --- a/src/fenrirscreenreader/commands/commands/cursor_column.py +++ b/src/fenrirscreenreader/commands/commands/cursor_column.py @@ -5,20 +5,29 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return _('Column number for cursor') + return _('Column number for cursor') + def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - self.env['runtime']['outputManager'].presentText(str(cursorPos['x'] + 1) , interrupt=True) + self.env['runtime']['outputManager'].presentText( + str(cursorPos['x'] + 1), interrupt=True) self.env['runtime']['outputManager'].announceActiveCursor() - self.env['runtime']['outputManager'].presentText(' column number' , interrupt=False) - + self.env['runtime']['outputManager'].presentText( + ' column number', interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/cursor_lineno.py b/src/fenrirscreenreader/commands/commands/cursor_lineno.py index 938c1356..9a1669d7 100644 --- a/src/fenrirscreenreader/commands/commands/cursor_lineno.py +++ b/src/fenrirscreenreader/commands/commands/cursor_lineno.py @@ -5,20 +5,29 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return _('Line number for cursor') + return _('Line number for cursor') + def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - self.env['runtime']['outputManager'].presentText(str(cursorPos['y'] + 1), interrupt=True) + self.env['runtime']['outputManager'].presentText( + str(cursorPos['y'] + 1), interrupt=True) self.env['runtime']['outputManager'].announceActiveCursor() - self.env['runtime']['outputManager'].presentText(' line number' , interrupt=False) - + self.env['runtime']['outputManager'].presentText( + ' line number', interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/cursor_position.py b/src/fenrirscreenreader/commands/commands/cursor_position.py index c00cf38d..8700193f 100644 --- a/src/fenrirscreenreader/commands/commands/cursor_position.py +++ b/src/fenrirscreenreader/commands/commands/cursor_position.py @@ -5,21 +5,32 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('displays the position of the review cursor') + return _('displays the position of the review cursor') def run(self): # Prefer review cursor over text cursor cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - self.env['runtime']['outputManager'].presentText(_("line {0}, column {1}, Terminal {2}").format(cursorPos['y']+1, cursorPos['x']+1, self.env['screen']['newTTY']), interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("line {0}, column {1}, Terminal {2}").format( + cursorPos['y'] + 1, + cursorPos['x'] + 1, + self.env['screen']['newTTY']), + interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/cursor_read_line_to_cursor.py b/src/fenrirscreenreader/commands/commands/cursor_read_line_to_cursor.py index 80fd8d86..c10f0df3 100644 --- a/src/fenrirscreenreader/commands/commands/cursor_read_line_to_cursor.py +++ b/src/fenrirscreenreader/commands/commands/cursor_read_line_to_cursor.py @@ -4,29 +4,38 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import line_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('read line to cursor pos, use review cursor if you are in review mode, otherwhise use text cursor') - + return _( + 'read line to cursor pos, use review cursor if you are in review mode, otherwhise use text cursor') + def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - x, y, currLine = \ - line_utils.getCurrentLine(cursorPos['x'], cursorPos['y'], self.env['screen']['newContentText']) - + x, y, currLine = line_utils.getCurrentLine( + cursorPos['x'], cursorPos['y'], self.env['screen']['newContentText']) + if currLine.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True) + self.env['runtime']['outputManager'].presentText( + _("blank"), soundIcon='EmptyLine', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(currLine[:cursorPos['x']], interrupt=True) + self.env['runtime']['outputManager'].presentText( + currLine[:cursorPos['x']], interrupt=True) self.env['runtime']['outputManager'].announceActiveCursor() + def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/commands/cursor_read_to_end_of_line.py b/src/fenrirscreenreader/commands/commands/cursor_read_to_end_of_line.py index 5f8b32f6..4f6e905c 100644 --- a/src/fenrirscreenreader/commands/commands/cursor_read_to_end_of_line.py +++ b/src/fenrirscreenreader/commands/commands/cursor_read_to_end_of_line.py @@ -4,29 +4,38 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import line_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('read to end of line, use review cursor if you are in review mode, otherwhise use text cursor') - + return _( + 'read to end of line, use review cursor if you are in review mode, otherwhise use text cursor') + def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - x, y, currLine = \ - line_utils.getCurrentLine(cursorPos['x'], cursorPos['y'], self.env['screen']['newContentText']) - + x, y, currLine = line_utils.getCurrentLine( + cursorPos['x'], cursorPos['y'], self.env['screen']['newContentText']) + if currLine.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True) + self.env['runtime']['outputManager'].presentText( + _("blank"), soundIcon='EmptyLine', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(currLine[cursorPos['x']:], interrupt=True) + self.env['runtime']['outputManager'].presentText( + currLine[cursorPos['x']:], interrupt=True) self.env['runtime']['outputManager'].announceActiveCursor() + def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/commands/cycle_keyboard_layout.py b/src/fenrirscreenreader/commands/commands/cycle_keyboard_layout.py index 7f7f977b..6e7b341d 100644 --- a/src/fenrirscreenreader/commands/commands/cycle_keyboard_layout.py +++ b/src/fenrirscreenreader/commands/commands/cycle_keyboard_layout.py @@ -4,23 +4,29 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.core import debug import os + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('cycles between available keyboard layouts') - + def getAvailableLayouts(self): """Get list of available keyboard layout files""" layouts = [] - + # Check standard locations for keyboard layouts settingsRoot = '/etc/fenrirscreenreader/' if not os.path.exists(settingsRoot): @@ -28,34 +34,37 @@ class command(): import fenrirscreenreader fenrirPath = os.path.dirname(fenrirscreenreader.__file__) settingsRoot = fenrirPath + '/../../config/' - + keyboardPath = settingsRoot + 'keyboard/' - + if os.path.exists(keyboardPath): for file in os.listdir(keyboardPath): - if file.endswith('.conf') and not file.startswith('__') and not file.lower().startswith('pty'): + if file.endswith('.conf') and not file.startswith( + '__') and not file.lower().startswith('pty'): layout_name = file.replace('.conf', '') if layout_name not in layouts: layouts.append(layout_name) - + # Ensure we have at least basic layouts if not layouts: layouts = ['desktop', 'laptop'] else: layouts.sort() - + return layouts - + def run(self): - current_layout = self.env['runtime']['settingsManager'].getSetting('keyboard', 'keyboardLayout') - + current_layout = self.env['runtime']['settingsManager'].getSetting( + 'keyboard', 'keyboardLayout') + # Extract layout name from full path if needed if '/' in current_layout: - current_layout = os.path.basename(current_layout).replace('.conf', '') - + current_layout = os.path.basename( + current_layout).replace('.conf', '') + # Get available layouts available_layouts = self.getAvailableLayouts() - + # Find next layout in cycle try: current_index = available_layouts.index(current_layout) @@ -63,28 +72,29 @@ class command(): except ValueError: # If current layout not found, start from beginning next_index = 0 - + next_layout = available_layouts[next_index] - + # Update setting and reload shortcuts - self.env['runtime']['settingsManager'].setSetting('keyboard', 'keyboardLayout', next_layout) - + self.env['runtime']['settingsManager'].setSetting( + 'keyboard', 'keyboardLayout', next_layout) + # Reload shortcuts with new layout try: self.env['runtime']['inputManager'].reloadShortcuts() self.env['runtime']['outputManager'].presentText( - _('Switched to {} keyboard layout').format(next_layout), + _('Switched to {} keyboard layout').format(next_layout), interrupt=True ) except Exception as e: self.env['runtime']['debug'].writeDebugOut( - "Error reloading shortcuts: " + str(e), + "Error reloading shortcuts: " + str(e), debug.debugLevel.ERROR ) self.env['runtime']['outputManager'].presentText( - _('Error switching keyboard layout'), + _('Error switching keyboard layout'), interrupt=True ) def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/commands/date.py b/src/fenrirscreenreader/commands/commands/date.py index 7a95ca1c..78f10e28 100644 --- a/src/fenrirscreenreader/commands/commands/date.py +++ b/src/fenrirscreenreader/commands/commands/date.py @@ -4,26 +4,36 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import datetime + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('presents the date') - + return _('presents the date') + def run(self): - dateFormat = self.env['runtime']['settingsManager'].getSetting('general', 'dateFormat') + dateFormat = self.env['runtime']['settingsManager'].getSetting( + 'general', 'dateFormat') # get the time formatted - dateString = datetime.datetime.strftime(datetime.datetime.now(), dateFormat) + dateString = datetime.datetime.strftime( + datetime.datetime.now(), dateFormat) - # present the time via speak and braile, there is no soundicon, interrupt the current speech - self.env['runtime']['outputManager'].presentText(dateString , soundIcon='', interrupt=True) + # present the time via speak and braile, there is no soundicon, + # interrupt the current speech + self.env['runtime']['outputManager'].presentText( + dateString, soundIcon='', interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/dec_alsa_volume.py b/src/fenrirscreenreader/commands/commands/dec_alsa_volume.py index 59cf13fe..1e3ef43e 100644 --- a/src/fenrirscreenreader/commands/commands/dec_alsa_volume.py +++ b/src/fenrirscreenreader/commands/commands/dec_alsa_volume.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'adjustment_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) AdjustmentCommand = _module.AdjustmentCommand + class command(AdjustmentCommand): def __init__(self): super().__init__('alsa', 'volume', 'dec') diff --git a/src/fenrirscreenreader/commands/commands/dec_sound_volume.py b/src/fenrirscreenreader/commands/commands/dec_sound_volume.py index 4b36bf11..8f23afdc 100644 --- a/src/fenrirscreenreader/commands/commands/dec_sound_volume.py +++ b/src/fenrirscreenreader/commands/commands/dec_sound_volume.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'adjustment_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) AdjustmentCommand = _module.AdjustmentCommand + class command(AdjustmentCommand): def __init__(self): super().__init__('sound', 'volume', 'dec') diff --git a/src/fenrirscreenreader/commands/commands/dec_speech_pitch.py b/src/fenrirscreenreader/commands/commands/dec_speech_pitch.py index 02cf36e8..44db62d8 100644 --- a/src/fenrirscreenreader/commands/commands/dec_speech_pitch.py +++ b/src/fenrirscreenreader/commands/commands/dec_speech_pitch.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'adjustment_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) AdjustmentCommand = _module.AdjustmentCommand + class command(AdjustmentCommand): def __init__(self): super().__init__('speech', 'pitch', 'dec') diff --git a/src/fenrirscreenreader/commands/commands/dec_speech_rate.py b/src/fenrirscreenreader/commands/commands/dec_speech_rate.py index 82b54982..11b5c982 100644 --- a/src/fenrirscreenreader/commands/commands/dec_speech_rate.py +++ b/src/fenrirscreenreader/commands/commands/dec_speech_rate.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'adjustment_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) AdjustmentCommand = _module.AdjustmentCommand + class command(AdjustmentCommand): def __init__(self): super().__init__('speech', 'rate', 'dec') diff --git a/src/fenrirscreenreader/commands/commands/dec_speech_volume.py b/src/fenrirscreenreader/commands/commands/dec_speech_volume.py index f3d48afc..47253000 100644 --- a/src/fenrirscreenreader/commands/commands/dec_speech_volume.py +++ b/src/fenrirscreenreader/commands/commands/dec_speech_volume.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'adjustment_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) AdjustmentCommand = _module.AdjustmentCommand + class command(AdjustmentCommand): def __init__(self): super().__init__('speech', 'volume', 'dec') diff --git a/src/fenrirscreenreader/commands/commands/exit_review.py b/src/fenrirscreenreader/commands/commands/exit_review.py index 86ddf87d..9a73a0f2 100644 --- a/src/fenrirscreenreader/commands/commands/exit_review.py +++ b/src/fenrirscreenreader/commands/commands/exit_review.py @@ -5,23 +5,31 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('exits review mode') - + return _('exits review mode') + def run(self): if not self.env['runtime']['cursorManager'].isReviewMode(): - self.env['runtime']['outputManager'].presentText(_("Not in Review Mode"), interrupt=True) - return + self.env['runtime']['outputManager'].presentText( + _("Not in Review Mode"), interrupt=True) + return self.env['runtime']['cursorManager'].clearReviewCursor() - self.env['runtime']['outputManager'].presentText(_("Exiting Review Mode"), interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("Exiting Review Mode"), interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/export_clipboard_to_file.py b/src/fenrirscreenreader/commands/commands/export_clipboard_to_file.py index a818acd2..7ffc278c 100644 --- a/src/fenrirscreenreader/commands/commands/export_clipboard_to_file.py +++ b/src/fenrirscreenreader/commands/commands/export_clipboard_to_file.py @@ -4,36 +4,55 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.core import debug import os + class command(): def __init__(self): pass + def initialize(self, environment, scriptPath=''): self.env = environment def shutdown(self): pass + def getDescription(self): return _('export the current fenrir clipboard to a file') - def run(self): - clipboardFilePath = self.env['runtime']['settingsManager'].getSetting('general', 'clipboardExportPath') - clipboardFilePath = clipboardFilePath.replace('$user',self.env['general']['currUser']) - clipboardFilePath = clipboardFilePath.replace('$USER',self.env['general']['currUser']) - clipboardFilePath = clipboardFilePath.replace('$User',self.env['general']['currUser']) - clipboardFile = open(clipboardFilePath,'w') + + def run(self): + clipboardFilePath = self.env['runtime']['settingsManager'].getSetting( + 'general', 'clipboardExportPath') + clipboardFilePath = clipboardFilePath.replace( + '$user', self.env['general']['currUser']) + clipboardFilePath = clipboardFilePath.replace( + '$USER', self.env['general']['currUser']) + clipboardFilePath = clipboardFilePath.replace( + '$User', self.env['general']['currUser']) + clipboardFile = open(clipboardFilePath, 'w') try: - if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'): - self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True) - return - clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory') + if self.env['runtime']['memoryManager'].isIndexListEmpty( + 'clipboardHistory'): + self.env['runtime']['outputManager'].presentText( + _('clipboard empty'), interrupt=True) + return + clipboard = self.env['runtime']['memoryManager'].getIndexListElement( + 'clipboardHistory') clipboardFile.write(clipboard) clipboardFile.close() os.chmod(clipboardFilePath, 0o644) - self.env['runtime']['outputManager'].presentText(_('clipboard exported to file'), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('clipboard exported to file'), interrupt=True) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('export_clipboard_to_file:run: Filepath:'+ clipboardFile +' trace:' + str(e),debug.debugLevel.ERROR) - + self.env['runtime']['debug'].writeDebugOut( + 'export_clipboard_to_file:run: Filepath:' + + clipboardFile + + ' trace:' + + str(e), + debug.debugLevel.ERROR) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/export_clipboard_to_x.py b/src/fenrirscreenreader/commands/commands/export_clipboard_to_x.py index 6d460d5c..5fb21fb3 100644 --- a/src/fenrirscreenreader/commands/commands/export_clipboard_to_x.py +++ b/src/fenrirscreenreader/commands/commands/export_clipboard_to_x.py @@ -4,37 +4,48 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib import _thread import pyperclip + class command(): def __init__(self): pass + def initialize(self, environment, scriptPath=''): self.env = environment self.scriptPath = scriptPath + def shutdown(self): pass + def getDescription(self): return _('Export current fenrir clipboard to X or GUI clipboard') - def run(self): - _thread.start_new_thread(self._threadRun , ()) + + def run(self): + _thread.start_new_thread(self._threadRun, ()) + def _threadRun(self): try: # Check if clipboard is empty - if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'): - self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True) + if self.env['runtime']['memoryManager'].isIndexListEmpty( + 'clipboardHistory'): + self.env['runtime']['outputManager'].presentText( + _('clipboard empty'), interrupt=True) return - + # Get current clipboard content - clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory') - + clipboard = self.env['runtime']['memoryManager'].getIndexListElement( + 'clipboardHistory') + # Remember original display environment variable if it exists originalDisplay = os.environ.get('DISPLAY', '') success = False - + # Try different display options for i in range(10): display = f":{i}" @@ -42,29 +53,34 @@ class command(): # Set display environment variable os.environ['DISPLAY'] = display # Attempt to set clipboard content - importlib.reload(pyperclip) # Weird workaround for some distros + # Weird workaround for some distros + importlib.reload(pyperclip) pyperclip.copy(clipboard) - # If we get here without exception, we found a working display + # If we get here without exception, we found a working + # display success = True break except Exception: # Failed for this display, try next one continue - + # Restore original display setting if originalDisplay: os.environ['DISPLAY'] = originalDisplay else: os.environ.pop('DISPLAY', None) - + # Notify the user of the result if success: - self.env['runtime']['outputManager'].presentText(_('exported to the X session.'), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('exported to the X session.'), interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_('failed to export to X clipboard. No available display found.'), interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _('failed to export to X clipboard. No available display found.'), interrupt=True) + except Exception as e: - self.env['runtime']['outputManager'].presentText(str(e), soundIcon='', interrupt=False) - + self.env['runtime']['outputManager'].presentText( + str(e), soundIcon='', interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/first_clipboard.py b/src/fenrirscreenreader/commands/commands/first_clipboard.py index c2bc287a..1822fffc 100644 --- a/src/fenrirscreenreader/commands/commands/first_clipboard.py +++ b/src/fenrirscreenreader/commands/commands/first_clipboard.py @@ -5,23 +5,33 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('selects the first clipboard') - + return _('selects the first clipboard') + def run(self): - if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'): - self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True) + if self.env['runtime']['memoryManager'].isIndexListEmpty( + 'clipboardHistory'): + self.env['runtime']['outputManager'].presentText( + _('clipboard empty'), interrupt=True) return - self.env['runtime']['memoryManager'].setFirstIndex('clipboardHistory') - clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory') - self.env['runtime']['outputManager'].presentText(clipboard, interrupt=True) - + self.env['runtime']['memoryManager'].setFirstIndex('clipboardHistory') + clipboard = self.env['runtime']['memoryManager'].getIndexListElement( + 'clipboardHistory') + self.env['runtime']['outputManager'].presentText( + clipboard, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/forward_keypress.py b/src/fenrirscreenreader/commands/commands/forward_keypress.py index 4c50bc61..f933c352 100644 --- a/src/fenrirscreenreader/commands/commands/forward_keypress.py +++ b/src/fenrirscreenreader/commands/commands/forward_keypress.py @@ -5,19 +5,26 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('sends the following keypress to the terminal or application') - + return _('sends the following keypress to the terminal or application') + def run(self): self.env['input']['keyForeward'] = 3 - self.env['runtime']['outputManager'].presentText(_('Forward next keypress'), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('Forward next keypress'), interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/import_clipboard_from_file.py b/src/fenrirscreenreader/commands/commands/import_clipboard_from_file.py index 0446cb4b..1f41776d 100644 --- a/src/fenrirscreenreader/commands/commands/import_clipboard_from_file.py +++ b/src/fenrirscreenreader/commands/commands/import_clipboard_from_file.py @@ -4,35 +4,48 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import mark_utils import os + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('imports text from clipboard file to the clipboard') - + return _('imports text from clipboard file to the clipboard') + def run(self): - clipboardFilePath = self.env['runtime']['settingsManager'].getSetting('general', 'clipboardExportPath') - clipboardFilePath = clipboardFilePath.replace('$user',self.env['general']['currUser']) - clipboardFilePath = clipboardFilePath.replace('$USER',self.env['general']['currUser']) - clipboardFilePath = clipboardFilePath.replace('$User',self.env['general']['currUser']) + clipboardFilePath = self.env['runtime']['settingsManager'].getSetting( + 'general', 'clipboardExportPath') + clipboardFilePath = clipboardFilePath.replace( + '$user', self.env['general']['currUser']) + clipboardFilePath = clipboardFilePath.replace( + '$USER', self.env['general']['currUser']) + clipboardFilePath = clipboardFilePath.replace( + '$User', self.env['general']['currUser']) if not os.path.exists(clipboardFilePath): - self.env['runtime']['outputManager'].presentText(_('File does not exist'), soundIcon='', interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('File does not exist'), soundIcon='', interrupt=True) return - clipboardFile = open(clipboardFilePath,'r') + clipboardFile = open(clipboardFilePath, 'r') imported = clipboardFile.read() clipboardFile.close() - self.env['runtime']['memoryManager'].addValueToFirstIndex('clipboardHistory', imported) + self.env['runtime']['memoryManager'].addValueToFirstIndex( + 'clipboardHistory', imported) - self.env['runtime']['outputManager'].presentText('Import to Clipboard', soundIcon='CopyToClipboard', interrupt=True) - self.env['runtime']['outputManager'].presentText(imported, soundIcon='', interrupt=False) - + self.env['runtime']['outputManager'].presentText( + 'Import to Clipboard', soundIcon='CopyToClipboard', interrupt=True) + self.env['runtime']['outputManager'].presentText( + imported, soundIcon='', interrupt=False) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/import_clipboard_from_x.py b/src/fenrirscreenreader/commands/commands/import_clipboard_from_x.py index b5ea5222..ad67e372 100644 --- a/src/fenrirscreenreader/commands/commands/import_clipboard_from_x.py +++ b/src/fenrirscreenreader/commands/commands/import_clipboard_from_x.py @@ -4,29 +4,37 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib import _thread import pyperclip import os + class command(): def __init__(self): pass + def initialize(self, environment, scriptPath=''): self.env = environment self.scriptPath = scriptPath + def shutdown(self): pass + def getDescription(self): return _("imports the graphical clipboard to Fenrir's clipboard") - def run(self): - _thread.start_new_thread(self._threadRun , ()) + + def run(self): + _thread.start_new_thread(self._threadRun, ()) + def _threadRun(self): try: # Remember original display environment variable if it exists originalDisplay = os.environ.get('DISPLAY', '') clipboardContent = None - + # Try different display options for i in range(10): display = f":{i}" @@ -34,30 +42,37 @@ class command(): # Set display environment variable os.environ['DISPLAY'] = display # Attempt to get clipboard content - importlib.reload(pyperclip) # Weird workaround for some distros + # Weird workaround for some distros + importlib.reload(pyperclip) clipboardContent = pyperclip.paste() - # If we get here without exception, we found a working display + # If we get here without exception, we found a working + # display if clipboardContent: break except Exception: # Failed for this display, try next one continue - + # Restore original display setting if originalDisplay: os.environ['DISPLAY'] = originalDisplay else: os.environ.pop('DISPLAY', None) - + # Process the clipboard content if we found any if clipboardContent and isinstance(clipboardContent, str): - self.env['runtime']['memoryManager'].addValueToFirstIndex('clipboardHistory', clipboardContent) - self.env['runtime']['outputManager'].presentText('Import to Clipboard', soundIcon='CopyToClipboard', interrupt=True) - self.env['runtime']['outputManager'].presentText(clipboardContent, soundIcon='', interrupt=False) + self.env['runtime']['memoryManager'].addValueToFirstIndex( + 'clipboardHistory', clipboardContent) + self.env['runtime']['outputManager'].presentText( + 'Import to Clipboard', soundIcon='CopyToClipboard', interrupt=True) + self.env['runtime']['outputManager'].presentText( + clipboardContent, soundIcon='', interrupt=False) else: - self.env['runtime']['outputManager'].presentText('No text found in clipboard or no accessible display', interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'No text found in clipboard or no accessible display', interrupt=True) except Exception as e: - self.env['runtime']['outputManager'].presentText(str(e), soundIcon='', interrupt=False) - + self.env['runtime']['outputManager'].presentText( + str(e), soundIcon='', interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/inc_alsa_volume.py b/src/fenrirscreenreader/commands/commands/inc_alsa_volume.py index ba3f4086..d391b1d9 100644 --- a/src/fenrirscreenreader/commands/commands/inc_alsa_volume.py +++ b/src/fenrirscreenreader/commands/commands/inc_alsa_volume.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'adjustment_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) AdjustmentCommand = _module.AdjustmentCommand + class command(AdjustmentCommand): def __init__(self): super().__init__('alsa', 'volume', 'inc') diff --git a/src/fenrirscreenreader/commands/commands/inc_sound_volume.py b/src/fenrirscreenreader/commands/commands/inc_sound_volume.py index 67bd8d55..b5fab2df 100644 --- a/src/fenrirscreenreader/commands/commands/inc_sound_volume.py +++ b/src/fenrirscreenreader/commands/commands/inc_sound_volume.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'adjustment_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) AdjustmentCommand = _module.AdjustmentCommand + class command(AdjustmentCommand): def __init__(self): super().__init__('sound', 'volume', 'inc') diff --git a/src/fenrirscreenreader/commands/commands/inc_speech_pitch.py b/src/fenrirscreenreader/commands/commands/inc_speech_pitch.py index a4d9c09f..0a830d0d 100644 --- a/src/fenrirscreenreader/commands/commands/inc_speech_pitch.py +++ b/src/fenrirscreenreader/commands/commands/inc_speech_pitch.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'adjustment_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) AdjustmentCommand = _module.AdjustmentCommand + class command(AdjustmentCommand): def __init__(self): super().__init__('speech', 'pitch', 'inc') diff --git a/src/fenrirscreenreader/commands/commands/inc_speech_rate.py b/src/fenrirscreenreader/commands/commands/inc_speech_rate.py index b91fd1cd..9d0d8537 100644 --- a/src/fenrirscreenreader/commands/commands/inc_speech_rate.py +++ b/src/fenrirscreenreader/commands/commands/inc_speech_rate.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'adjustment_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) AdjustmentCommand = _module.AdjustmentCommand + class command(AdjustmentCommand): def __init__(self): super().__init__('speech', 'rate', 'inc') diff --git a/src/fenrirscreenreader/commands/commands/inc_speech_volume.py b/src/fenrirscreenreader/commands/commands/inc_speech_volume.py index bb88059d..ca6ae3d8 100644 --- a/src/fenrirscreenreader/commands/commands/inc_speech_volume.py +++ b/src/fenrirscreenreader/commands/commands/inc_speech_volume.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'adjustment_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) AdjustmentCommand = _module.AdjustmentCommand + class command(AdjustmentCommand): def __init__(self): super().__init__('speech', 'volume', 'inc') diff --git a/src/fenrirscreenreader/commands/commands/indent_curr_line.py b/src/fenrirscreenreader/commands/commands/indent_curr_line.py index 68c12760..aa80f4ba 100644 --- a/src/fenrirscreenreader/commands/commands/indent_curr_line.py +++ b/src/fenrirscreenreader/commands/commands/indent_curr_line.py @@ -4,17 +4,23 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import line_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('Presents the indentation level for the current line') + return _('Presents the indentation level for the current line') def run(self): # Prefer review cursor over text cursor @@ -23,13 +29,15 @@ class command(): cursorPos = self.env['screen']['newCursorReview'].copy() else: cursorPos = self.env['screen']['newCursor'].copy() - x, y, currLine = \ - line_utils.getCurrentLine(cursorPos['x'], cursorPos['y'], self.env['screen']['newContentText']) - + x, y, currLine = line_utils.getCurrentLine( + cursorPos['x'], cursorPos['y'], self.env['screen']['newContentText']) + if currLine.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True) - else: - self.env['runtime']['outputManager'].presentText(_("indent {0}").format(len(currLine) - len(currLine.lstrip())), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _("blank"), soundIcon='EmptyLine', interrupt=True) + else: + self.env['runtime']['outputManager'].presentText(_("indent {0}").format( + len(currLine) - len(currLine.lstrip())), interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/last_clipboard.py b/src/fenrirscreenreader/commands/commands/last_clipboard.py index e09d7fe8..5fc4a856 100644 --- a/src/fenrirscreenreader/commands/commands/last_clipboard.py +++ b/src/fenrirscreenreader/commands/commands/last_clipboard.py @@ -5,23 +5,33 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('selects the last clipboard') - + return _('selects the last clipboard') + def run(self): - if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'): - self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True) + if self.env['runtime']['memoryManager'].isIndexListEmpty( + 'clipboardHistory'): + self.env['runtime']['outputManager'].presentText( + _('clipboard empty'), interrupt=True) return - self.env['runtime']['memoryManager'].setLastIndex('clipboardHistory') - clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory') - self.env['runtime']['outputManager'].presentText(clipboard, interrupt=True) - + self.env['runtime']['memoryManager'].setLastIndex('clipboardHistory') + clipboard = self.env['runtime']['memoryManager'].getIndexListElement( + 'clipboardHistory') + self.env['runtime']['outputManager'].presentText( + clipboard, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/marked_text.py b/src/fenrirscreenreader/commands/commands/marked_text.py index 3bf3f094..1d521e98 100644 --- a/src/fenrirscreenreader/commands/commands/marked_text.py +++ b/src/fenrirscreenreader/commands/commands/marked_text.py @@ -4,34 +4,45 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import mark_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('Presents the currently selected text that will be copied to the clipboard') - + return _( + 'Presents the currently selected text that will be copied to the clipboard') + def run(self): - if not (self.env['commandBuffer']['Marks']['1'] and \ - self.env['commandBuffer']['Marks']['2']): - self.env['runtime']['outputManager'].presentText(_("please set begin and endmark"), interrupt=True) + if not (self.env['commandBuffer']['Marks']['1'] and + self.env['commandBuffer']['Marks']['2']): + self.env['runtime']['outputManager'].presentText( + _("please set begin and endmark"), interrupt=True) return # use the last first and the last setted mark as range startMark = self.env['commandBuffer']['Marks']['1'].copy() - endMark = self.env['commandBuffer']['Marks']['2'].copy() + endMark = self.env['commandBuffer']['Marks']['2'].copy() - marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText']) + marked = mark_utils.getTextBetweenMarks( + startMark, endMark, self.env['screen']['newContentText']) if marked.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True) + self.env['runtime']['outputManager'].presentText( + _("blank"), soundIcon='EmptyLine', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(marked, interrupt=True) - + self.env['runtime']['outputManager'].presentText( + marked, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/next_clipboard.py b/src/fenrirscreenreader/commands/commands/next_clipboard.py index 7364f62d..2900d547 100644 --- a/src/fenrirscreenreader/commands/commands/next_clipboard.py +++ b/src/fenrirscreenreader/commands/commands/next_clipboard.py @@ -5,31 +5,45 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('selects the next clipboard') - + return _('selects the next clipboard') + def run(self): - if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'): - self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True) - return - self.env['runtime']['memoryManager'].getNextIndex('clipboardHistory') - isFirst = self.env['runtime']['memoryManager'].isFirstIndex('clipboardHistory') - isLast = self.env['runtime']['memoryManager'].isLastIndex('clipboardHistory') - clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory') + if self.env['runtime']['memoryManager'].isIndexListEmpty( + 'clipboardHistory'): + self.env['runtime']['outputManager'].presentText( + _('clipboard empty'), interrupt=True) + return + self.env['runtime']['memoryManager'].getNextIndex('clipboardHistory') + isFirst = self.env['runtime']['memoryManager'].isFirstIndex( + 'clipboardHistory') + isLast = self.env['runtime']['memoryManager'].isLastIndex( + 'clipboardHistory') + clipboard = self.env['runtime']['memoryManager'].getIndexListElement( + 'clipboardHistory') if isFirst: - self.env['runtime']['outputManager'].presentText(_('First clipboard '), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('First clipboard '), interrupt=True) if isLast: - self.env['runtime']['outputManager'].presentText(_('Last clipboard '), interrupt=True) - - speechInterrupt = not(isLast or isFirst) - self.env['runtime']['outputManager'].presentText(clipboard, interrupt = speechInterrupt) - + self.env['runtime']['outputManager'].presentText( + _('Last clipboard '), interrupt=True) + + speechInterrupt = not (isLast or isFirst) + self.env['runtime']['outputManager'].presentText( + clipboard, interrupt=speechInterrupt) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/next_quick_menu_entry.py b/src/fenrirscreenreader/commands/commands/next_quick_menu_entry.py index 1d2a5fb1..13b52c43 100644 --- a/src/fenrirscreenreader/commands/commands/next_quick_menu_entry.py +++ b/src/fenrirscreenreader/commands/commands/next_quick_menu_entry.py @@ -5,15 +5,22 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get next quick menu entry') + def run(self): menu = '' value = '' @@ -21,8 +28,11 @@ class command(): menu = self.env['runtime']['quickMenuManager'].getCurrentEntry() if menu != '': value = self.env['runtime']['quickMenuManager'].getCurrentValue() - self.env['runtime']['outputManager'].presentText(menu + ' ' + value, interrupt=True) + self.env['runtime']['outputManager'].presentText( + menu + ' ' + value, interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_('Quick menu not available'), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('Quick menu not available'), interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/next_quick_menu_value.py b/src/fenrirscreenreader/commands/commands/next_quick_menu_value.py index 78a0f9ad..d52adad9 100644 --- a/src/fenrirscreenreader/commands/commands/next_quick_menu_value.py +++ b/src/fenrirscreenreader/commands/commands/next_quick_menu_value.py @@ -5,18 +5,27 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get next quick menu value') + def run(self): if self.env['runtime']['quickMenuManager'].nextValue(): value = self.env['runtime']['quickMenuManager'].getCurrentValue() - self.env['runtime']['outputManager'].presentText(value, interrupt=True) + self.env['runtime']['outputManager'].presentText( + value, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/paste_clipboard.py b/src/fenrirscreenreader/commands/commands/paste_clipboard.py index 565ffc25..337a20ba 100644 --- a/src/fenrirscreenreader/commands/commands/paste_clipboard.py +++ b/src/fenrirscreenreader/commands/commands/paste_clipboard.py @@ -4,26 +4,38 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import time + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment - self.env['runtime']['memoryManager'].addIndexList('clipboardHistory', self.env['runtime']['settingsManager'].getSettingAsInt('general', 'numberOfClipboards')) + self.env['runtime']['memoryManager'].addIndexList( + 'clipboardHistory', self.env['runtime']['settingsManager'].getSettingAsInt( + 'general', 'numberOfClipboards')) + def shutdown(self): - pass + pass + def getDescription(self): - return _('pastes the text from the currently selected clipboard') - - def run(self): - if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'): - self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True) - return - self.env['runtime']['outputManager'].presentText('paste clipboard', soundIcon='PasteClipboardOnScreen', interrupt=True) - clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory') + return _('pastes the text from the currently selected clipboard') + + def run(self): + if self.env['runtime']['memoryManager'].isIndexListEmpty( + 'clipboardHistory'): + self.env['runtime']['outputManager'].presentText( + _('clipboard empty'), interrupt=True) + return + self.env['runtime']['outputManager'].presentText( + 'paste clipboard', soundIcon='PasteClipboardOnScreen', interrupt=True) + clipboard = self.env['runtime']['memoryManager'].getIndexListElement( + 'clipboardHistory') self.env['runtime']['screenManager'].injectTextToScreen(clipboard) - + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/present_first_line.py b/src/fenrirscreenreader/commands/commands/present_first_line.py index 3a901204..3cec3868 100644 --- a/src/fenrirscreenreader/commands/commands/present_first_line.py +++ b/src/fenrirscreenreader/commands/commands/present_first_line.py @@ -4,26 +4,34 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import line_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass - def getDescription(self): - return _('present first line') - - def run(self): - x, y, firstLine = \ - line_utils.getCurrentLine(0, 0, self.env['screen']['newContentText']) - - if firstLine.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True) - else: - self.env['runtime']['outputManager'].presentText(firstLine, interrupt=True) - def setCallback(self, callback): pass + def getDescription(self): + return _('present first line') + + def run(self): + x, y, firstLine = line_utils.getCurrentLine( + 0, 0, self.env['screen']['newContentText']) + + if firstLine.isspace(): + self.env['runtime']['outputManager'].presentText( + _("blank"), soundIcon='EmptyLine', interrupt=True) + else: + self.env['runtime']['outputManager'].presentText( + firstLine, interrupt=True) + + def setCallback(self, callback): + pass diff --git a/src/fenrirscreenreader/commands/commands/present_last_line.py b/src/fenrirscreenreader/commands/commands/present_last_line.py index 274eb721..0e2f3dfd 100644 --- a/src/fenrirscreenreader/commands/commands/present_last_line.py +++ b/src/fenrirscreenreader/commands/commands/present_last_line.py @@ -4,26 +4,34 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import line_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment - def shutdown(self): - pass - def getDescription(self): - return _('current line') - - def run(self): - x, y, lastLine = \ - line_utils.getCurrentLine(0, self.env['screen']['lines'] -1, self.env['screen']['newContentText']) - if lastLine.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True) - else: - self.env['runtime']['outputManager'].presentText(lastLine, interrupt=True) - def setCallback(self, callback): + def shutdown(self): pass + def getDescription(self): + return _('current line') + + def run(self): + x, y, lastLine = line_utils.getCurrentLine( + 0, self.env['screen']['lines'] - 1, self.env['screen']['newContentText']) + + if lastLine.isspace(): + self.env['runtime']['outputManager'].presentText( + _("blank"), soundIcon='EmptyLine', interrupt=True) + else: + self.env['runtime']['outputManager'].presentText( + lastLine, interrupt=True) + + def setCallback(self, callback): + pass diff --git a/src/fenrirscreenreader/commands/commands/prev_clipboard.py b/src/fenrirscreenreader/commands/commands/prev_clipboard.py index 95bca467..e36dc80c 100644 --- a/src/fenrirscreenreader/commands/commands/prev_clipboard.py +++ b/src/fenrirscreenreader/commands/commands/prev_clipboard.py @@ -5,30 +5,44 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('selects the previous clipboard') + return _('selects the previous clipboard') def run(self): - if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'): - self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True) - return - self.env['runtime']['memoryManager'].setPrefIndex('clipboardHistory') - isFirst = self.env['runtime']['memoryManager'].isFirstIndex('clipboardHistory') - isLast = self.env['runtime']['memoryManager'].isLastIndex('clipboardHistory') - clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory') + if self.env['runtime']['memoryManager'].isIndexListEmpty( + 'clipboardHistory'): + self.env['runtime']['outputManager'].presentText( + _('clipboard empty'), interrupt=True) + return + self.env['runtime']['memoryManager'].setPrefIndex('clipboardHistory') + isFirst = self.env['runtime']['memoryManager'].isFirstIndex( + 'clipboardHistory') + isLast = self.env['runtime']['memoryManager'].isLastIndex( + 'clipboardHistory') + clipboard = self.env['runtime']['memoryManager'].getIndexListElement( + 'clipboardHistory') if isFirst: - self.env['runtime']['outputManager'].presentText(_('First clipboard '), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('First clipboard '), interrupt=True) if isLast: - self.env['runtime']['outputManager'].presentText(_('Last clipboard '), interrupt=True) - speechInterrupt = not(isLast or isFirst) - self.env['runtime']['outputManager'].presentText(clipboard, interrupt = speechInterrupt) - + self.env['runtime']['outputManager'].presentText( + _('Last clipboard '), interrupt=True) + speechInterrupt = not (isLast or isFirst) + self.env['runtime']['outputManager'].presentText( + clipboard, interrupt=speechInterrupt) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/prev_quick_menu_entry.py b/src/fenrirscreenreader/commands/commands/prev_quick_menu_entry.py index 87aef5df..b6910ea2 100644 --- a/src/fenrirscreenreader/commands/commands/prev_quick_menu_entry.py +++ b/src/fenrirscreenreader/commands/commands/prev_quick_menu_entry.py @@ -5,15 +5,22 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get previous quick menu entry') + def run(self): menu = '' value = '' @@ -21,8 +28,11 @@ class command(): menu = self.env['runtime']['quickMenuManager'].getCurrentEntry() if menu != '': value = self.env['runtime']['quickMenuManager'].getCurrentValue() - self.env['runtime']['outputManager'].presentText(menu + ' ' + value, interrupt=True) + self.env['runtime']['outputManager'].presentText( + menu + ' ' + value, interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_('Quick menu not available'), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('Quick menu not available'), interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/prev_quick_menu_value.py b/src/fenrirscreenreader/commands/commands/prev_quick_menu_value.py index bfa7e8cb..3ba6840b 100644 --- a/src/fenrirscreenreader/commands/commands/prev_quick_menu_value.py +++ b/src/fenrirscreenreader/commands/commands/prev_quick_menu_value.py @@ -5,18 +5,27 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get previous quick menu value') + def run(self): if self.env['runtime']['quickMenuManager'].prevValue(): value = self.env['runtime']['quickMenuManager'].getCurrentValue() - self.env['runtime']['outputManager'].presentText(value, interrupt=True) + self.env['runtime']['outputManager'].presentText( + value, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/progress_bar_monitor.py b/src/fenrirscreenreader/commands/commands/progress_bar_monitor.py index d9583c24..e6d8bf86 100644 --- a/src/fenrirscreenreader/commands/commands/progress_bar_monitor.py +++ b/src/fenrirscreenreader/commands/commands/progress_bar_monitor.py @@ -4,68 +4,75 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import re import time import threading + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment # Use commandBuffer like other commands if 'progressMonitoring' not in self.env['commandBuffer']: - # Check if progress monitoring should be enabled by default from settings + # Check if progress monitoring should be enabled by default from + # settings try: - defaultEnabled = self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'progressMonitoring') + defaultEnabled = self.env['runtime']['settingsManager'].getSettingAsBool( + 'sound', 'progressMonitoring') except Exception as e: # If setting doesn't exist, default to False defaultEnabled = False self.env['commandBuffer']['progressMonitoring'] = defaultEnabled self.env['commandBuffer']['lastProgressTime'] = 0 self.env['commandBuffer']['lastProgressValue'] = -1 - + def shutdown(self): self.stopProgressMonitoring() - + def getDescription(self): return _('Toggle progress bar monitoring with ascending tones') - + def run(self): # Check if commandBuffer exists if 'progressMonitoring' not in self.env['commandBuffer']: self.env['commandBuffer']['progressMonitoring'] = False self.env['commandBuffer']['lastProgressTime'] = 0 self.env['commandBuffer']['lastProgressValue'] = -1 - + if self.env['commandBuffer']['progressMonitoring']: self.stopProgressMonitoring() - self.env['runtime']['outputManager'].presentText(_("Progress monitoring disabled"), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _("Progress monitoring disabled"), interrupt=True) else: self.startProgressMonitoring() - self.env['runtime']['outputManager'].presentText(_("Progress monitoring enabled"), interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("Progress monitoring enabled"), interrupt=True) + def startProgressMonitoring(self): self.env['commandBuffer']['progressMonitoring'] = True self.env['commandBuffer']['lastProgressTime'] = time.time() self.env['commandBuffer']['lastProgressValue'] = -1 # Don't control speech - let user decide with silence_until_prompt - + def stopProgressMonitoring(self): self.env['commandBuffer']['progressMonitoring'] = False # Don't control speech - progress monitor is beep-only - + def detectProgress(self, text): if not self.env['commandBuffer']['progressMonitoring']: return - + # Skip progress detection if current screen looks like a prompt if self.isCurrentLinePrompt(): return - + currentTime = time.time() - + # Pattern 1: Percentage (50%, 25.5%, etc.) percentMatch = re.search(r'(\d+(?:\.\d+)?)\s*%', text) if percentMatch: @@ -75,7 +82,7 @@ class command(): self.env['commandBuffer']['lastProgressValue'] = percentage self.env['commandBuffer']['lastProgressTime'] = currentTime return - + # Pattern 2: Fraction (15/100, 3 of 10, etc.) fractionMatch = re.search(r'(\d+)\s*(?:of|/)\s*(\d+)', text) if fractionMatch: @@ -88,7 +95,7 @@ class command(): self.env['commandBuffer']['lastProgressValue'] = percentage self.env['commandBuffer']['lastProgressTime'] = currentTime return - + # Pattern 3: Progress bars ([#### ], [====> ], etc.) # Improved pattern to avoid matching IRC channels like [#channel] barMatch = re.search(r'\[([#=\-\*]+)([\s\.]*)\]', text) @@ -96,114 +103,133 @@ class command(): filled = len(barMatch.group(1)) unfilled = len(barMatch.group(2)) total = filled + unfilled - # Require at least 2 progress chars total and unfilled portion must be spaces/dots - if total >= 2 and (not barMatch.group(2) or re.match(r'^[\s\.]*$', barMatch.group(2))): + # Require at least 2 progress chars total and unfilled portion must + # be spaces/dots + if total >= 2 and ( + not barMatch.group(2) or re.match( + r'^[\s\.]*$', + barMatch.group(2))): percentage = (filled / total) * 100 if percentage != self.env['commandBuffer']['lastProgressValue']: self.playProgressTone(percentage) self.env['commandBuffer']['lastProgressValue'] = percentage self.env['commandBuffer']['lastProgressTime'] = currentTime return - + # Pattern 4: Generic activity indicators (Loading..., Working..., etc.) - activityPattern = re.search(r'(loading|processing|working|installing|downloading|compiling|building).*\.{2,}', text, re.IGNORECASE) + activityPattern = re.search( + r'(loading|processing|working|installing|downloading|compiling|building).*\.{2,}', + text, + re.IGNORECASE) if activityPattern: # Play a steady beep every 2 seconds for ongoing activity - if currentTime - self.env['commandBuffer']['lastProgressTime'] >= 2.0: + if currentTime - \ + self.env['commandBuffer']['lastProgressTime'] >= 2.0: self.playActivityBeep() self.env['commandBuffer']['lastProgressTime'] = currentTime - + def playProgressTone(self, percentage): # Map 0-100% to 400-1200Hz frequency range frequency = 400 + (percentage * 8) frequency = max(400, min(1200, frequency)) # Clamp to safe range - self.env['runtime']['outputManager'].playFrequence(frequency, 0.15, interrupt=False) - + self.env['runtime']['outputManager'].playFrequence( + frequency, 0.15, interrupt=False) + def playActivityBeep(self): # Single tone for generic activity - self.env['runtime']['outputManager'].playFrequence(800, 0.1, interrupt=False) - + self.env['runtime']['outputManager'].playFrequence( + 800, 0.1, interrupt=False) + def isCurrentLinePrompt(self): """Check if the current line looks like a standalone prompt (not command with progress)""" import re - + try: # Get the current screen content if not self.env['screen']['newContentText']: return False - + lines = self.env['screen']['newContentText'].split('\n') if not lines: return False - - # Check the last line (most common) and current cursor line for prompt patterns + + # Check the last line (most common) and current cursor line for + # prompt patterns linesToCheck = [] - + # Add last line (most common for prompts) if lines: linesToCheck.append(lines[-1]) - + # Add current cursor line if different from last line - if (self.env['screen']['newCursor']['y'] < len(lines) and - self.env['screen']['newCursor']['y'] != len(lines) - 1): - linesToCheck.append(lines[self.env['screen']['newCursor']['y']]) - + if (self.env['screen']['newCursor']['y'] < len(lines) and + self.env['screen']['newCursor']['y'] != len(lines) - 1): + linesToCheck.append( + lines[self.env['screen']['newCursor']['y']]) + # Standalone prompt patterns (no commands mixed in) standalonePromptPatterns = [ r'^\s*\$\s*$', # Just $ (with whitespace) - r'^\s*#\s*$', # Just # (with whitespace) + r'^\s*#\s*$', # Just # (with whitespace) r'^\s*>\s*$', # Just > (with whitespace) r'^\[.*\]\s*[\\\$#>]\s*$', # [path]$ without commands r'^[a-zA-Z0-9._-]+[\\\$#>]\s*$', # bash-5.1$ without commands - + # Interactive prompt patterns (these ARE standalone) r'.*\?\s*\[[YyNn]/[YyNn]\]\s*$', # ? [Y/n] or ? [y/N] style r'.*\?\s*\[[Yy]es/[Nn]o\]\s*$', # ? [Yes/No] style - r'.*continue\?\s*\[[YyNn]/[YyNn]\].*$', # "continue? [Y/n]" style + # "continue? [Y/n]" style + r'.*continue\?\s*\[[YyNn]/[YyNn]\].*$', r'^::.*\?\s*\[[YyNn]/[YyNn]\].*$', # pacman style prompts - + # Authentication prompts (these ARE standalone) r'^\[[Ss]udo\]\s*[Pp]assword\s*for\s+.*:\s*$', # [sudo] password r'^[Pp]assword\s*:\s*$', # Password: r'.*[Pp]assword\s*:\s*$', # general password prompts - + # Continuation prompts (these ARE standalone) r'^[Pp]ress\s+any\s+key\s+to\s+continue.*$', # Press any key r'^[Aa]re\s+you\s+sure\?\s*.*$', # Are you sure? ] - + for line in linesToCheck: line = line.strip() if not line: continue - + # Check if this line contains both a prompt AND other content (like commands) # If so, don't treat it as a standalone prompt - hasPromptMarker = bool(re.search(r'.*@.*[\\\$#>]', line) or re.search(r'^\[.*\]\s*[\\\$#>]', line)) + hasPromptMarker = bool( + re.search( + r'.*@.*[\\\$#>]', + line) or re.search( + r'^\[.*\]\s*[\\\$#>]', + line)) if hasPromptMarker: - # If line has prompt marker but also has significant content after it, + # If line has prompt marker but also has significant content after it, # it's a command line, not a standalone prompt promptEnd = max( - line.rfind('$'), - line.rfind('#'), + line.rfind('$'), + line.rfind('#'), line.rfind('>'), line.rfind('\\') ) - if promptEnd >= 0 and promptEnd < len(line) - 5: # More than just whitespace after prompt + if promptEnd >= 0 and promptEnd < len( + line) - 5: # More than just whitespace after prompt continue # This is a command line, not a standalone prompt - + for pattern in standalonePromptPatterns: try: if re.search(pattern, line): return True except re.error: continue - + return False - + except Exception as e: # If anything fails, assume it's not a prompt to be safe return False - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/commands/quit_fenrir.py b/src/fenrirscreenreader/commands/commands/quit_fenrir.py index 0baf8449..a46d34be 100644 --- a/src/fenrirscreenreader/commands/commands/quit_fenrir.py +++ b/src/fenrirscreenreader/commands/commands/quit_fenrir.py @@ -5,19 +5,24 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('exits Fenrir') - + return _('exits Fenrir') + def run(self): - self.env['runtime']['eventManager'].stopMainEventLoop() + self.env['runtime']['eventManager'].stopMainEventLoop() def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/commands/remove_marks.py b/src/fenrirscreenreader/commands/commands/remove_marks.py index 17a62880..0d1898d0 100644 --- a/src/fenrirscreenreader/commands/commands/remove_marks.py +++ b/src/fenrirscreenreader/commands/commands/remove_marks.py @@ -5,19 +5,26 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('Removes marks from selected text') - + return _('Removes marks from selected text') + def run(self): self.env['runtime']['cursorManager'].clearMarks() - self.env['runtime']['outputManager'].presentText(_('Remove marks'), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('Remove marks'), interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/remove_word_from_spell_check.py b/src/fenrirscreenreader/commands/commands/remove_word_from_spell_check.py index 55f01302..9706a9d4 100644 --- a/src/fenrirscreenreader/commands/commands/remove_word_from_spell_check.py +++ b/src/fenrirscreenreader/commands/commands/remove_word_from_spell_check.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import word_utils import string initialized = False @@ -12,43 +14,61 @@ try: initialized = True except Exception as e: pass - + + class command(): def __init__(self): self.language = '' self.spellChecker = None + def initialize(self, environment): self.env = environment self.updateSpellLanguage() + def shutdown(self): pass + def getDescription(self): - return _('removes the current word from the exceptions dictionary') - def updateSpellLanguage(self): - self.spellChecker = enchant.Dict(self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage')) - self.language = self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') - + return _('removes the current word from the exceptions dictionary') + + def updateSpellLanguage(self): + self.spellChecker = enchant.Dict( + self.env['runtime']['settingsManager'].getSetting( + 'general', 'spellCheckLanguage')) + self.language = self.env['runtime']['settingsManager'].getSetting( + 'general', 'spellCheckLanguage') + def run(self): if not initialized: - self.env['runtime']['outputManager'].presentText(_('pyenchant is not installed'), interrupt=True) - return - if self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') != self.language: + self.env['runtime']['outputManager'].presentText( + _('pyenchant is not installed'), interrupt=True) + return + if self.env['runtime']['settingsManager'].getSetting( + 'general', 'spellCheckLanguage') != self.language: try: self.updateSpellLanguage() except Exception as e: - return + return cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - + # get the word - newContent = self.env['screen']['newContentText'].split('\n')[cursorPos['y']] - x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord(cursorPos['x'], 0, newContent) - currWord = currWord.strip(string.whitespace + r'!"#$%&()*+,-./:;<=Â?@[\\]^_{|}~') + newContent = self.env['screen']['newContentText'].split('\n')[ + cursorPos['y']] + x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord( + cursorPos['x'], 0, newContent) + currWord = currWord.strip( + string.whitespace + + r'!"#$%&()*+,-./:;<=Â?@[\\]^_{|}~') if not currWord.isspace(): if self.spellChecker.is_removed(currWord): - self.env['runtime']['outputManager'].presentText(_('{0} is not in the dictionary').format(currWord,), soundIcon='Cancel', interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('{0} is not in the dictionary').format( + currWord,), soundIcon='Cancel', interrupt=True) else: - self.spellChecker.remove(currWord) - self.env['runtime']['outputManager'].presentText(_('{0} removed').format(currWord,), soundIcon='Accept', interrupt=True) + self.spellChecker.remove(currWord) + self.env['runtime']['outputManager'].presentText( + _('{0} removed').format(currWord,), soundIcon='Accept', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_bottom.py b/src/fenrirscreenreader/commands/commands/review_bottom.py index cc529e2b..98083db0 100644 --- a/src/fenrirscreenreader/commands/commands/review_bottom.py +++ b/src/fenrirscreenreader/commands/commands/review_bottom.py @@ -5,19 +5,27 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('Move review to the bottom of the screen') def run(self): - self.env['screen']['newCursorReview'] = { 'x': 0, 'y':self.env['screen']['lines'] -1} - self.env['runtime']['outputManager'].presentText(_("Bottom"), interrupt=True, flush=False) + self.env['screen']['newCursorReview'] = { + 'x': 0, 'y': self.env['screen']['lines'] - 1} + self.env['runtime']['outputManager'].presentText( + _("Bottom"), interrupt=True, flush=False) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_curr_char.py b/src/fenrirscreenreader/commands/commands/review_curr_char.py index 6ce99926..43740ba4 100644 --- a/src/fenrirscreenreader/commands/commands/review_curr_char.py +++ b/src/fenrirscreenreader/commands/commands/review_curr_char.py @@ -4,32 +4,46 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('presents the current character.') - + return _('presents the current character.') + def run(self): self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currChar = \ - char_utils.getCurrentChar(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - - char_utils.presentCharForReview(self.env, currChar, interrupt=True, announceCapital=True, flush=False) - # is has attribute it enabled? - if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'hasAttributes'): + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currChar = char_utils.getCurrentChar( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + + char_utils.presentCharForReview( + self.env, + currChar, + interrupt=True, + announceCapital=True, + flush=False) + # is has attribute it enabled? + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'hasAttributes'): cursorPos = self.env['screen']['newCursorReview'] - - if not self.env['runtime']['attributeManager'].hasAttributes(cursorPos): + + if not self.env['runtime']['attributeManager'].hasAttributes( + cursorPos): return - self.env['runtime']['outputManager'].presentText('has attribute', soundIcon='HasAttributes', interrupt=False) - + self.env['runtime']['outputManager'].presentText( + 'has attribute', soundIcon='HasAttributes', interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_curr_char_phonetic.py b/src/fenrirscreenreader/commands/commands/review_curr_char_phonetic.py index 120045fe..6d7469e6 100644 --- a/src/fenrirscreenreader/commands/commands/review_curr_char_phonetic.py +++ b/src/fenrirscreenreader/commands/commands/review_curr_char_phonetic.py @@ -4,29 +4,37 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('set review and phonetically presents the current character') - + return _('set review and phonetically presents the current character') + def run(self): self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currChar = \ - char_utils.getCurrentChar(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currChar = char_utils.getCurrentChar( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + if currChar.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + _("blank"), interrupt=True, flush=False) else: currChar = char_utils.getPhonetic(currChar) - self.env['runtime']['outputManager'].presentText(currChar ,interrupt=True, announceCapital=True, flush=False) - + self.env['runtime']['outputManager'].presentText( + currChar, interrupt=True, announceCapital=True, flush=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_curr_line.py b/src/fenrirscreenreader/commands/commands/review_curr_line.py index 871cc0b7..35553d76 100644 --- a/src/fenrirscreenreader/commands/commands/review_curr_line.py +++ b/src/fenrirscreenreader/commands/commands/review_curr_line.py @@ -4,28 +4,36 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import line_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('current line') - + return _('current line') + def run(self): self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currLine = \ - line_utils.getCurrentLine(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currLine = line_utils.getCurrentLine( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + if currLine.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + _("blank"), soundIcon='EmptyLine', interrupt=True, flush=False) else: - self.env['runtime']['outputManager'].presentText(currLine, interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + currLine, interrupt=True, flush=False) + def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/commands/review_curr_word.py b/src/fenrirscreenreader/commands/commands/review_curr_word.py index 079eaae1..a77acb30 100644 --- a/src/fenrirscreenreader/commands/commands/review_curr_word.py +++ b/src/fenrirscreenreader/commands/commands/review_curr_word.py @@ -4,33 +4,46 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import word_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('current word.') + return _('current word.') def run(self): self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currWord, endOfScreen, lineBreak = \ - word_utils.getCurrentWord(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currWord, endOfScreen, lineBreak = word_utils.getCurrentWord( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + if currWord.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + _("blank"), interrupt=True, flush=False) else: - self.env['runtime']['outputManager'].presentText(currWord, interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + currWord, interrupt=True, flush=False) if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=True, soundIcon='EndOfScreen') if lineBreak: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'lineBreak'): - self.env['runtime']['outputManager'].presentText(_('line break'), interrupt=False, soundIcon='EndOfLine') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'lineBreak'): + self.env['runtime']['outputManager'].presentText( + _('line break'), interrupt=False, soundIcon='EndOfLine') + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_curr_word_phonetic.py b/src/fenrirscreenreader/commands/commands/review_curr_word_phonetic.py index d0158ef0..7535993c 100644 --- a/src/fenrirscreenreader/commands/commands/review_curr_word_phonetic.py +++ b/src/fenrirscreenreader/commands/commands/review_curr_word_phonetic.py @@ -4,37 +4,50 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import word_utils from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('Phonetically spells the current word') - + return _('Phonetically spells the current word') + def run(self): self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currWord, endOfScreen, lineBreak = \ - word_utils.getCurrentWord(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currWord, endOfScreen, lineBreak = word_utils.getCurrentWord( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + if currWord.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + _("blank"), interrupt=True, flush=False) else: firstSequence = True for c in currWord: - currChar = char_utils.getPhonetic(c) - self.env['runtime']['outputManager'].presentText(currChar, interrupt=firstSequence, announceCapital=True, flush=False) + currChar = char_utils.getPhonetic(c) + self.env['runtime']['outputManager'].presentText( + currChar, interrupt=firstSequence, announceCapital=True, flush=False) firstSequence = False if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=True, soundIcon='EndOfScreen') if lineBreak: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'lineBreak'): - self.env['runtime']['outputManager'].presentText(_('line break'), interrupt=False, soundIcon='EndOfLine') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'lineBreak'): + self.env['runtime']['outputManager'].presentText( + _('line break'), interrupt=False, soundIcon='EndOfLine') + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_down.py b/src/fenrirscreenreader/commands/commands/review_down.py index 8797600a..81dd12eb 100644 --- a/src/fenrirscreenreader/commands/commands/review_down.py +++ b/src/fenrirscreenreader/commands/commands/review_down.py @@ -4,25 +4,39 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('Move review to the character below the current position') + return _('Move review to the character below the current position') def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], downChar, endOfScreen = \ - char_utils.getDownChar(self.env['screen']['newCursorReview']['x'],self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - self.env['runtime']['outputManager'].presentText(downChar ,interrupt=True, ignorePunctuation=True, announceCapital=True, flush=False) + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], downChar, endOfScreen = char_utils.getDownChar( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + self.env['runtime']['outputManager'].presentText( + downChar, + interrupt=True, + ignorePunctuation=True, + announceCapital=True, + flush=False) if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=True, soundIcon='EndOfScreen') + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_line_begin.py b/src/fenrirscreenreader/commands/commands/review_line_begin.py index 5d31a04a..cb117aa1 100644 --- a/src/fenrirscreenreader/commands/commands/review_line_begin.py +++ b/src/fenrirscreenreader/commands/commands/review_line_begin.py @@ -4,29 +4,43 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('set review cursor to begin of current line and display the content') def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - self.env['runtime']['cursorManager'].setReviewCursorPosition(0 ,cursorPos['y']) - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currChar = \ - char_utils.getCurrentChar(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - + self.env['runtime']['cursorManager'].setReviewCursorPosition( + 0, cursorPos['y']) + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currChar = char_utils.getCurrentChar( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + if currChar.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + _("blank"), interrupt=True, flush=False) else: - self.env['runtime']['outputManager'].presentText(currChar ,interrupt=True, ignorePunctuation=True, announceCapital=True, flush=False) - self.env['runtime']['outputManager'].presentText(_("beginning of line"), interrupt=False) - + self.env['runtime']['outputManager'].presentText( + currChar, + interrupt=True, + ignorePunctuation=True, + announceCapital=True, + flush=False) + self.env['runtime']['outputManager'].presentText( + _("beginning of line"), interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_line_end.py b/src/fenrirscreenreader/commands/commands/review_line_end.py index 5cf18dd2..918946de 100644 --- a/src/fenrirscreenreader/commands/commands/review_line_end.py +++ b/src/fenrirscreenreader/commands/commands/review_line_end.py @@ -4,26 +4,39 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('Move Review to the end of current line and display the content') + return _('Move Review to the end of current line and display the content') def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - self.env['runtime']['cursorManager'].setReviewCursorPosition(self.env['screen']['columns']-1 ,cursorPos['y']) - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currChar = \ - char_utils.getCurrentChar(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - - self.env['runtime']['outputManager'].presentText(currChar ,interrupt=True, ignorePunctuation=True, announceCapital=True, flush=False) - self.env['runtime']['outputManager'].presentText(_("end of line"), interrupt=False) - + self.env['runtime']['cursorManager'].setReviewCursorPosition( + self.env['screen']['columns'] - 1, cursorPos['y']) + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currChar = char_utils.getCurrentChar( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + + self.env['runtime']['outputManager'].presentText( + currChar, + interrupt=True, + ignorePunctuation=True, + announceCapital=True, + flush=False) + self.env['runtime']['outputManager'].presentText( + _("end of line"), interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_line_first_char.py b/src/fenrirscreenreader/commands/commands/review_line_first_char.py index 84de0a72..11803533 100644 --- a/src/fenrirscreenreader/commands/commands/review_line_first_char.py +++ b/src/fenrirscreenreader/commands/commands/review_line_first_char.py @@ -4,32 +4,46 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import line_utils from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('Move Review to the first character on the line') def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - x, y, currLine = \ - line_utils.getCurrentLine(cursorPos['x'], cursorPos['y'], self.env['screen']['newContentText']) + x, y, currLine = line_utils.getCurrentLine( + cursorPos['x'], cursorPos['y'], self.env['screen']['newContentText']) if currLine.isspace(): - self.env['runtime']['outputManager'].presentText(_("line is empty"), interrupt=True) - return - self.env['runtime']['cursorManager'].setReviewCursorPosition((len(currLine) - len(currLine.lstrip())), cursorPos['y']) - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currChar = \ - char_utils.getCurrentChar(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + self.env['runtime']['outputManager'].presentText( + _("line is empty"), interrupt=True) + return + self.env['runtime']['cursorManager'].setReviewCursorPosition( + (len(currLine) - len(currLine.lstrip())), cursorPos['y']) + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], currChar = char_utils.getCurrentChar( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + + char_utils.presentCharForReview( + self.env, + currChar, + interrupt=True, + announceCapital=True, + flush=False) + self.env['runtime']['outputManager'].presentText(_("first character in line indent {0}").format( + str(len(currLine) - len(currLine.lstrip()))), interrupt=False) - char_utils.presentCharForReview(self.env, currChar, interrupt=True, announceCapital=True, flush=False) - self.env['runtime']['outputManager'].presentText(_("first character in line indent {0}").format(str(len(currLine) - len(currLine.lstrip()))), interrupt=False) - def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_line_last_char.py b/src/fenrirscreenreader/commands/commands/review_line_last_char.py index 82bcf101..fcc1d7c6 100644 --- a/src/fenrirscreenreader/commands/commands/review_line_last_char.py +++ b/src/fenrirscreenreader/commands/commands/review_line_last_char.py @@ -4,26 +4,39 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('Move Review to the last character on the line') def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - self.env['runtime']['cursorManager'].setReviewCursorPosition(self.env['screen']['columns']-1 ,cursorPos['y']) + self.env['runtime']['cursorManager'].setReviewCursorPosition( + self.env['screen']['columns'] - 1, cursorPos['y']) self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], lastChar = \ - char_utils.getLastCharInLine(self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - - char_utils.presentCharForReview(self.env, lastChar, interrupt=True, announceCapital=True, flush=False) - self.env['runtime']['outputManager'].presentText(_("last character in line"), interrupt=False) - + char_utils.getLastCharInLine(self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + + char_utils.presentCharForReview( + self.env, + lastChar, + interrupt=True, + announceCapital=True, + flush=False) + self.env['runtime']['outputManager'].presentText( + _("last character in line"), interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_next_char.py b/src/fenrirscreenreader/commands/commands/review_next_char.py index 496e2f83..a3779bf6 100644 --- a/src/fenrirscreenreader/commands/commands/review_next_char.py +++ b/src/fenrirscreenreader/commands/commands/review_next_char.py @@ -4,36 +4,55 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('Moves review to the next character ') - + return _('Moves review to the next character ') + def run(self): self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], nextChar, endOfScreen, lineBreak = \ - char_utils.getNextChar(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], nextChar, endOfScreen, lineBreak = char_utils.getNextChar( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - char_utils.presentCharForReview(self.env, nextChar, interrupt=True, announceCapital=True, flush=False) + char_utils.presentCharForReview( + self.env, + nextChar, + interrupt=True, + announceCapital=True, + flush=False) if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=True, soundIcon='EndOfScreen') if lineBreak: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'lineBreak'): - self.env['runtime']['outputManager'].presentText(_('line break'), interrupt=False, soundIcon='EndOfLine') - # is has attribute it enabled? - if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'hasAttributes'): + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'lineBreak'): + self.env['runtime']['outputManager'].presentText( + _('line break'), interrupt=False, soundIcon='EndOfLine') + # is has attribute it enabled? + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'hasAttributes'): cursorPos = self.env['screen']['newCursorReview'] - - if not self.env['runtime']['attributeManager'].hasAttributes(cursorPos): + + if not self.env['runtime']['attributeManager'].hasAttributes( + cursorPos): return - self.env['runtime']['outputManager'].presentText('has attribute', soundIcon='HasAttributes', interrupt=False) + self.env['runtime']['outputManager'].presentText( + 'has attribute', soundIcon='HasAttributes', interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_next_char_phonetic.py b/src/fenrirscreenreader/commands/commands/review_next_char_phonetic.py index 2d3a1fb2..f4a16c47 100644 --- a/src/fenrirscreenreader/commands/commands/review_next_char_phonetic.py +++ b/src/fenrirscreenreader/commands/commands/review_next_char_phonetic.py @@ -4,31 +4,43 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('phonetically presents the next character and set review to it') - + return _('phonetically presents the next character and set review to it') + def run(self): self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], nextChar, endOfScreen, lineBreak = \ - char_utils.getNextChar(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], nextChar, endOfScreen, lineBreak = char_utils.getNextChar( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + nextChar = char_utils.getPhonetic(nextChar) - self.env['runtime']['outputManager'].presentText(nextChar ,interrupt=True, announceCapital=True, flush=False) + self.env['runtime']['outputManager'].presentText( + nextChar, interrupt=True, announceCapital=True, flush=False) if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=True, soundIcon='EndOfScreen') if lineBreak: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'lineBreak'): - self.env['runtime']['outputManager'].presentText(_('line break'), interrupt=False, soundIcon='EndOfLine') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'lineBreak'): + self.env['runtime']['outputManager'].presentText( + _('line break'), interrupt=False, soundIcon='EndOfLine') + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_next_line.py b/src/fenrirscreenreader/commands/commands/review_next_line.py index a2870d7f..7cb109e5 100644 --- a/src/fenrirscreenreader/commands/commands/review_next_line.py +++ b/src/fenrirscreenreader/commands/commands/review_next_line.py @@ -4,32 +4,43 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import line_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('moves review to the next line ') - + return _('moves review to the next line ') + def run(self): self.env['screen']['oldCursorReview'] = self.env['screen']['newCursorReview'] if not self.env['screen']['newCursorReview']: self.env['screen']['newCursorReview'] = self.env['screen']['newCursor'].copy() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], nextLine, endOfScreen = \ - line_utils.getNextLine(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], nextLine, endOfScreen = line_utils.getNextLine( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + if nextLine.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + _("blank"), soundIcon='EmptyLine', interrupt=True, flush=False) else: - self.env['runtime']['outputManager'].presentText(nextLine, interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + nextLine, interrupt=True, flush=False) if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=True, soundIcon='EndOfScreen') + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_next_word.py b/src/fenrirscreenreader/commands/commands/review_next_word.py index 488ddc44..1e0677a5 100644 --- a/src/fenrirscreenreader/commands/commands/review_next_word.py +++ b/src/fenrirscreenreader/commands/commands/review_next_word.py @@ -4,35 +4,48 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import word_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('moves review to the next word ') - + return _('moves review to the next word ') + def run(self): self.env['screen']['oldCursorReview'] = self.env['screen']['newCursorReview'] - if self.env['screen']['newCursorReview'] == None: + if self.env['screen']['newCursorReview'] is None: self.env['screen']['newCursorReview'] = self.env['screen']['newCursor'].copy() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], nextWord, endOfScreen, lineBreak = \ - word_utils.getNextWord(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], nextWord, endOfScreen, lineBreak = word_utils.getNextWord( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + if nextWord.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + _("blank"), interrupt=True, flush=False) else: - self.env['runtime']['outputManager'].presentText(nextWord, interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + nextWord, interrupt=True, flush=False) if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=True, soundIcon='EndOfScreen') if lineBreak: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'lineBreak'): - self.env['runtime']['outputManager'].presentText(_('line break'), interrupt=False, soundIcon='EndOfLine') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'lineBreak'): + self.env['runtime']['outputManager'].presentText( + _('line break'), interrupt=False, soundIcon='EndOfLine') + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_next_word_phonetic.py b/src/fenrirscreenreader/commands/commands/review_next_word_phonetic.py index e15fb014..455c9073 100644 --- a/src/fenrirscreenreader/commands/commands/review_next_word_phonetic.py +++ b/src/fenrirscreenreader/commands/commands/review_next_word_phonetic.py @@ -4,37 +4,50 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import word_utils from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('Phonetically spells the next word and moves review to it') - + return _('Phonetically spells the next word and moves review to it') + def run(self): self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], nextWord, endOfScreen, lineBreak = \ - word_utils.getNextWord(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], nextWord, endOfScreen, lineBreak = word_utils.getNextWord( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + if nextWord.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + _("blank"), interrupt=True, flush=False) else: firstSequence = True for c in nextWord: - currChar = char_utils.getPhonetic(c) - self.env['runtime']['outputManager'].presentText(currChar, interrupt=firstSequence, announceCapital=True, flush=False) + currChar = char_utils.getPhonetic(c) + self.env['runtime']['outputManager'].presentText( + currChar, interrupt=firstSequence, announceCapital=True, flush=False) firstSequence = False if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=True, soundIcon='EndOfScreen') if lineBreak: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'lineBreak'): - self.env['runtime']['outputManager'].presentText(_('line break'), interrupt=False, soundIcon='EndOfLine') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'lineBreak'): + self.env['runtime']['outputManager'].presentText( + _('line break'), interrupt=False, soundIcon='EndOfLine') + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_prev_char.py b/src/fenrirscreenreader/commands/commands/review_prev_char.py index 5c4587b8..da9466e6 100644 --- a/src/fenrirscreenreader/commands/commands/review_prev_char.py +++ b/src/fenrirscreenreader/commands/commands/review_prev_char.py @@ -4,39 +4,58 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('moves review to the previous character ') - + return _('moves review to the previous character ') + def run(self): self.env['screen']['oldCursorReview'] = self.env['screen']['newCursorReview'] if not self.env['screen']['newCursorReview']: self.env['screen']['newCursorReview'] = self.env['screen']['newCursor'].copy() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], prevChar, endOfScreen, lineBreak = \ - char_utils.getPrevChar(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - - char_utils.presentCharForReview(self.env, prevChar, interrupt=True, announceCapital=True, flush=False) + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], prevChar, endOfScreen, lineBreak = char_utils.getPrevChar( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + + char_utils.presentCharForReview( + self.env, + prevChar, + interrupt=True, + announceCapital=True, + flush=False) if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=True, soundIcon='EndOfScreen') if lineBreak: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'lineBreak'): - self.env['runtime']['outputManager'].presentText(_('line break'), interrupt=False, soundIcon='EndOfLine') - # is has attribute it enabled? - if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'hasAttributes'): + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'lineBreak'): + self.env['runtime']['outputManager'].presentText( + _('line break'), interrupt=False, soundIcon='EndOfLine') + # is has attribute it enabled? + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'hasAttributes'): cursorPos = self.env['screen']['newCursorReview'] - - if not self.env['runtime']['attributeManager'].hasAttributes(cursorPos): + + if not self.env['runtime']['attributeManager'].hasAttributes( + cursorPos): return - self.env['runtime']['outputManager'].presentText('has attribute', soundIcon='HasAttributes', interrupt=False) + self.env['runtime']['outputManager'].presentText( + 'has attribute', soundIcon='HasAttributes', interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_prev_char_phonetic.py b/src/fenrirscreenreader/commands/commands/review_prev_char_phonetic.py index 8cf125f9..ea88b91f 100644 --- a/src/fenrirscreenreader/commands/commands/review_prev_char_phonetic.py +++ b/src/fenrirscreenreader/commands/commands/review_prev_char_phonetic.py @@ -4,31 +4,43 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('phonetically presents the previous character and set review to it') - + return _('phonetically presents the previous character and set review to it') + def run(self): self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], prevChar, endOfScreen, lineBreak = \ - char_utils.getPrevChar(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], prevChar, endOfScreen, lineBreak = char_utils.getPrevChar( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + prevChar = char_utils.getPhonetic(prevChar) - self.env['runtime']['outputManager'].presentText(prevChar ,interrupt=True, announceCapital=True, flush=False) + self.env['runtime']['outputManager'].presentText( + prevChar, interrupt=True, announceCapital=True, flush=False) if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=True, soundIcon='EndOfScreen') if lineBreak: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'lineBreak'): - self.env['runtime']['outputManager'].presentText(_('line break'), interrupt=False, soundIcon='EndOfLine') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'lineBreak'): + self.env['runtime']['outputManager'].presentText( + _('line break'), interrupt=False, soundIcon='EndOfLine') + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_prev_line.py b/src/fenrirscreenreader/commands/commands/review_prev_line.py index 600fd171..f49e679c 100644 --- a/src/fenrirscreenreader/commands/commands/review_prev_line.py +++ b/src/fenrirscreenreader/commands/commands/review_prev_line.py @@ -4,31 +4,41 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import line_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('moves review to the previous line ') + return _('moves review to the previous line ') def run(self): self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], prevLine, endOfScreen = \ - line_utils.getPrevLine(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], prevLine, endOfScreen = line_utils.getPrevLine( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + if prevLine.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + _("blank"), soundIcon='EmptyLine', interrupt=True, flush=False) else: - self.env['runtime']['outputManager'].presentText(prevLine, interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + prevLine, interrupt=True, flush=False) if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=True, soundIcon='EndOfScreen') def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_prev_word.py b/src/fenrirscreenreader/commands/commands/review_prev_word.py index a785eb1d..7c74baac 100644 --- a/src/fenrirscreenreader/commands/commands/review_prev_word.py +++ b/src/fenrirscreenreader/commands/commands/review_prev_word.py @@ -4,33 +4,46 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import word_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('moves review focus to the previous word ') + return _('moves review focus to the previous word ') def run(self): self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], prevWord, endOfScreen, lineBreak = \ - word_utils.getPrevWord(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], prevWord, endOfScreen, lineBreak = word_utils.getPrevWord( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + if prevWord.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + _("blank"), interrupt=True, flush=False) else: - self.env['runtime']['outputManager'].presentText(prevWord, interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + prevWord, interrupt=True, flush=False) if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=False, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=False, soundIcon='EndOfScreen') if lineBreak: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'lineBreak'): - self.env['runtime']['outputManager'].presentText(_('line break'), interrupt=False, soundIcon='EndOfLine') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'lineBreak'): + self.env['runtime']['outputManager'].presentText( + _('line break'), interrupt=False, soundIcon='EndOfLine') + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_prev_word_phonetic.py b/src/fenrirscreenreader/commands/commands/review_prev_word_phonetic.py index 96f27f80..ad1e7cf0 100644 --- a/src/fenrirscreenreader/commands/commands/review_prev_word_phonetic.py +++ b/src/fenrirscreenreader/commands/commands/review_prev_word_phonetic.py @@ -4,37 +4,50 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import word_utils from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('Phonetically spells the previous word and moves review to it') - + return _('Phonetically spells the previous word and moves review to it') + def run(self): self.env['runtime']['cursorManager'].enterReviewModeCurrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], prevWord, endOfScreen, lineBreak = \ - word_utils.getPrevWord(self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], prevWord, endOfScreen, lineBreak = word_utils.getPrevWord( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + if prevWord.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + _("blank"), interrupt=True, flush=False) else: firstSequence = True for c in prevWord: - currChar = char_utils.getPhonetic(c) - self.env['runtime']['outputManager'].presentText(currChar, interrupt=firstSequence, announceCapital=True, flush=False) + currChar = char_utils.getPhonetic(c) + self.env['runtime']['outputManager'].presentText( + currChar, interrupt=firstSequence, announceCapital=True, flush=False) firstSequence = False if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=True, soundIcon='EndOfScreen') if lineBreak: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'lineBreak'): - self.env['runtime']['outputManager'].presentText(_('line break'), interrupt=False, soundIcon='EndOfLine') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'lineBreak'): + self.env['runtime']['outputManager'].presentText( + _('line break'), interrupt=False, soundIcon='EndOfLine') + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_screen_first_char.py b/src/fenrirscreenreader/commands/commands/review_screen_first_char.py index 4bbc4554..4c64caea 100644 --- a/src/fenrirscreenreader/commands/commands/review_screen_first_char.py +++ b/src/fenrirscreenreader/commands/commands/review_screen_first_char.py @@ -4,26 +4,38 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('Move Review to the first character on the screen (left top)') def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - self.env['runtime']['cursorManager'].setReviewCursorPosition(0 ,0) + self.env['runtime']['cursorManager'].setReviewCursorPosition(0, 0) self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], lastChar = \ - char_utils.getLastCharInLine(self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - - char_utils.presentCharForReview(self.env, lastChar, interrupt=True, announceCapital=True, flush=False) - self.env['runtime']['outputManager'].presentText(_("first character in screen"), interrupt=False) - + char_utils.getLastCharInLine(self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + + char_utils.presentCharForReview( + self.env, + lastChar, + interrupt=True, + announceCapital=True, + flush=False) + self.env['runtime']['outputManager'].presentText( + _("first character in screen"), interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_screen_last_char.py b/src/fenrirscreenreader/commands/commands/review_screen_last_char.py index afec3477..c6381133 100644 --- a/src/fenrirscreenreader/commands/commands/review_screen_last_char.py +++ b/src/fenrirscreenreader/commands/commands/review_screen_last_char.py @@ -4,26 +4,39 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('Move Review to the last character on the screen (right bottom)') def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - self.env['runtime']['cursorManager'].setReviewCursorPosition(self.env['screen']['columns']-1 ,self.env['screen']['lines']-1) + self.env['runtime']['cursorManager'].setReviewCursorPosition( + self.env['screen']['columns'] - 1, self.env['screen']['lines'] - 1) self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], lastChar = \ - char_utils.getLastCharInLine(self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - - char_utils.presentCharForReview(self.env, lastChar, interrupt=True, announceCapital=True, flush=False) - self.env['runtime']['outputManager'].presentText(_("last character in screen"), interrupt=False) - + char_utils.getLastCharInLine(self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + + char_utils.presentCharForReview( + self.env, + lastChar, + interrupt=True, + announceCapital=True, + flush=False) + self.env['runtime']['outputManager'].presentText( + _("last character in screen"), interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_top.py b/src/fenrirscreenreader/commands/commands/review_top.py index b3778e92..0ed6264c 100644 --- a/src/fenrirscreenreader/commands/commands/review_top.py +++ b/src/fenrirscreenreader/commands/commands/review_top.py @@ -4,21 +4,28 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('move review to top of screen') + return _('move review to top of screen') def run(self): - self.env['screen']['newCursorReview'] = {'x':0,'y':0} - self.env['runtime']['outputManager'].presentText(_("Top"), interrupt=True, flush=False) + self.env['screen']['newCursorReview'] = {'x': 0, 'y': 0} + self.env['runtime']['outputManager'].presentText( + _("Top"), interrupt=True, flush=False) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/review_up.py b/src/fenrirscreenreader/commands/commands/review_up.py index 9788cb09..aa4b6359 100644 --- a/src/fenrirscreenreader/commands/commands/review_up.py +++ b/src/fenrirscreenreader/commands/commands/review_up.py @@ -4,28 +4,46 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('Move review to the character in the line above the current position') + return _( + 'Move review to the character in the line above the current position') def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], upChar, endOfScreen = \ - char_utils.getUpChar(self.env['screen']['newCursorReview']['x'],self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) - self.env['runtime']['outputManager'].presentText(upChar ,interrupt=True, ignorePunctuation=True, announceCapital=True, flush=False) + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], upChar, endOfScreen = char_utils.getUpChar( + self.env['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + lineBreak = False + self.env['runtime']['outputManager'].presentText( + upChar, + interrupt=True, + ignorePunctuation=True, + announceCapital=True, + flush=False) if endOfScreen: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'endOfScreen'): - self.env['runtime']['outputManager'].presentText(_('end of screen'), interrupt=True, soundIcon='EndOfScreen') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'endOfScreen'): + self.env['runtime']['outputManager'].presentText( + _('end of screen'), interrupt=True, soundIcon='EndOfScreen') if lineBreak: - if self.env['runtime']['settingsManager'].getSettingAsBool('review', 'lineBreak'): - self.env['runtime']['outputManager'].presentText(_('line break'), interrupt=False, soundIcon='EndOfLine') + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'lineBreak'): + self.env['runtime']['outputManager'].presentText( + _('line break'), interrupt=False, soundIcon='EndOfLine') + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/save_settings.py b/src/fenrirscreenreader/commands/commands/save_settings.py index 9f6ae177..129e9146 100644 --- a/src/fenrirscreenreader/commands/commands/save_settings.py +++ b/src/fenrirscreenreader/commands/commands/save_settings.py @@ -4,20 +4,29 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.core import settingsManager + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): return _('Saves your current Fenrir settings so they are the default.') + def run(self): settingsFile = self.env['runtime']['settingsManager'].getSettingsFile() self.env['runtime']['settingsManager'].saveSettings(settingsFile) - self.env['runtime']['outputManager'].presentText(_("Settings saved."), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _("Settings saved."), interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/set_bookmark_1.py b/src/fenrirscreenreader/commands/commands/set_bookmark_1.py index 333962b8..8171b007 100644 --- a/src/fenrirscreenreader/commands/commands/set_bookmark_1.py +++ b/src/fenrirscreenreader/commands/commands/set_bookmark_1.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(1, 'set') diff --git a/src/fenrirscreenreader/commands/commands/set_bookmark_10.py b/src/fenrirscreenreader/commands/commands/set_bookmark_10.py index 499c1d4f..2cc74ceb 100644 --- a/src/fenrirscreenreader/commands/commands/set_bookmark_10.py +++ b/src/fenrirscreenreader/commands/commands/set_bookmark_10.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(10, 'set') diff --git a/src/fenrirscreenreader/commands/commands/set_bookmark_2.py b/src/fenrirscreenreader/commands/commands/set_bookmark_2.py index 826a093a..677b7015 100644 --- a/src/fenrirscreenreader/commands/commands/set_bookmark_2.py +++ b/src/fenrirscreenreader/commands/commands/set_bookmark_2.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(2, 'set') diff --git a/src/fenrirscreenreader/commands/commands/set_bookmark_3.py b/src/fenrirscreenreader/commands/commands/set_bookmark_3.py index d87f444e..15df37ff 100644 --- a/src/fenrirscreenreader/commands/commands/set_bookmark_3.py +++ b/src/fenrirscreenreader/commands/commands/set_bookmark_3.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(3, 'set') diff --git a/src/fenrirscreenreader/commands/commands/set_bookmark_4.py b/src/fenrirscreenreader/commands/commands/set_bookmark_4.py index fe2c1f83..814d68e6 100644 --- a/src/fenrirscreenreader/commands/commands/set_bookmark_4.py +++ b/src/fenrirscreenreader/commands/commands/set_bookmark_4.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(4, 'set') diff --git a/src/fenrirscreenreader/commands/commands/set_bookmark_5.py b/src/fenrirscreenreader/commands/commands/set_bookmark_5.py index efa41d0d..cc419132 100644 --- a/src/fenrirscreenreader/commands/commands/set_bookmark_5.py +++ b/src/fenrirscreenreader/commands/commands/set_bookmark_5.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(5, 'set') diff --git a/src/fenrirscreenreader/commands/commands/set_bookmark_6.py b/src/fenrirscreenreader/commands/commands/set_bookmark_6.py index e5998745..f168aecd 100644 --- a/src/fenrirscreenreader/commands/commands/set_bookmark_6.py +++ b/src/fenrirscreenreader/commands/commands/set_bookmark_6.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(6, 'set') diff --git a/src/fenrirscreenreader/commands/commands/set_bookmark_7.py b/src/fenrirscreenreader/commands/commands/set_bookmark_7.py index f31fd689..f0ca618b 100644 --- a/src/fenrirscreenreader/commands/commands/set_bookmark_7.py +++ b/src/fenrirscreenreader/commands/commands/set_bookmark_7.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(7, 'set') diff --git a/src/fenrirscreenreader/commands/commands/set_bookmark_8.py b/src/fenrirscreenreader/commands/commands/set_bookmark_8.py index dcdb9ce9..e6f05408 100644 --- a/src/fenrirscreenreader/commands/commands/set_bookmark_8.py +++ b/src/fenrirscreenreader/commands/commands/set_bookmark_8.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(8, 'set') diff --git a/src/fenrirscreenreader/commands/commands/set_bookmark_9.py b/src/fenrirscreenreader/commands/commands/set_bookmark_9.py index 30b67ed2..7808ecea 100644 --- a/src/fenrirscreenreader/commands/commands/set_bookmark_9.py +++ b/src/fenrirscreenreader/commands/commands/set_bookmark_9.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import importlib.util _base_path = os.path.join(os.path.dirname(__file__), 'bookmark_base.py') @@ -12,6 +14,7 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) BookmarkCommand = _module.BookmarkCommand + class command(BookmarkCommand): def __init__(self): super().__init__(9, 'set') diff --git a/src/fenrirscreenreader/commands/commands/set_mark.py b/src/fenrirscreenreader/commands/commands/set_mark.py index 2d22ae2a..c105a8d7 100644 --- a/src/fenrirscreenreader/commands/commands/set_mark.py +++ b/src/fenrirscreenreader/commands/commands/set_mark.py @@ -5,25 +5,35 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('places marks to select text to copy to the clipboard') - + return _('places marks to select text to copy to the clipboard') + def run(self): if not self.env['runtime']['cursorManager'].isReviewMode(): - self.env['runtime']['outputManager'].presentText(_('no review cursor'), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('no review cursor'), interrupt=True) return currMark = self.env['runtime']['cursorManager'].setMark() if currMark == 1: - self.env['runtime']['outputManager'].presentText(_('set mark'), soundIcon='PlaceStartMark', interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('set mark'), soundIcon='PlaceStartMark', interrupt=True) elif currMark == 2: - self.env['runtime']['outputManager'].presentText(_('set mark'),soundIcon='PlaceEndMark', interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('set mark'), soundIcon='PlaceEndMark', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/set_window_application.py b/src/fenrirscreenreader/commands/commands/set_window_application.py index bcc3f920..d8ce800a 100644 --- a/src/fenrirscreenreader/commands/commands/set_window_application.py +++ b/src/fenrirscreenreader/commands/commands/set_window_application.py @@ -5,23 +5,32 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('set Window Mode, needs 2 marks ') - + def run(self): if self.env['runtime']['cursorManager'].setWindowForApplication(): - currApp = self.env['runtime']['applicationManager'].getCurrentApplication() - self.env['runtime']['outputManager'].presentText(_('Window Mode on for application {0}').format(currApp), interrupt=True) + currApp = self.env['runtime']['applicationManager'].getCurrentApplication( + ) + self.env['runtime']['outputManager'].presentText( + _('Window Mode on for application {0}').format(currApp), interrupt=True) self.env['runtime']['cursorManager'].clearMarks() else: - self.env['runtime']['outputManager'].presentText(_("Set window begin and end marks"), interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("Set window begin and end marks"), interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/shut_up.py b/src/fenrirscreenreader/commands/commands/shut_up.py index 1a5aa4b2..1ccb6b40 100644 --- a/src/fenrirscreenreader/commands/commands/shut_up.py +++ b/src/fenrirscreenreader/commands/commands/shut_up.py @@ -5,18 +5,28 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('Interrupts the current presentation') + return _('Interrupts the current presentation') + def run(self): - if len(self.env['input']['prevDeepestInput']) > len(self.env['input']['currInput']): - return + if len( + self.env['input']['prevDeepestInput']) > len( + self.env['input']['currInput']): + return self.env['runtime']['outputManager'].interruptOutput() + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/silence_until_prompt.py b/src/fenrirscreenreader/commands/commands/silence_until_prompt.py index cca33a3d..42ad5b3b 100644 --- a/src/fenrirscreenreader/commands/commands/silence_until_prompt.py +++ b/src/fenrirscreenreader/commands/commands/silence_until_prompt.py @@ -4,83 +4,102 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.core import debug import re + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment # Use commandBuffer like other commands if 'silenceUntilPrompt' not in self.env['commandBuffer']: self.env['commandBuffer']['silenceUntilPrompt'] = False - + def shutdown(self): pass - + def getDescription(self): return _('Toggle speech silence until shell prompt returns') - + def run(self): if self.env['commandBuffer']['silenceUntilPrompt']: self.disableSilence() else: self.enableSilence() - + def enableSilence(self): self.env['commandBuffer']['silenceUntilPrompt'] = True - self.env['runtime']['outputManager'].presentText(_("Speech silenced until prompt returns"), soundIcon='SpeechOff', interrupt=True) - # Disable speech but don't use the normal temp disable that reactivates on keypress - self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', 'False') - + self.env['runtime']['outputManager'].presentText( + _("Speech silenced until prompt returns"), + soundIcon='SpeechOff', + interrupt=True) + # Disable speech but don't use the normal temp disable that reactivates + # on keypress + self.env['runtime']['settingsManager'].setSetting( + 'speech', 'enabled', 'False') + def disableSilence(self): self.env['commandBuffer']['silenceUntilPrompt'] = False # Re-enable speech - self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', 'True') - self.env['runtime']['outputManager'].presentText(_("Speech restored"), soundIcon='SpeechOn', interrupt=True) - + self.env['runtime']['settingsManager'].setSetting( + 'speech', 'enabled', 'True') + self.env['runtime']['outputManager'].presentText( + _("Speech restored"), soundIcon='SpeechOn', interrupt=True) + def checkForPrompt(self, text): """Check if the current line contains a shell prompt pattern""" if not self.env['commandBuffer']['silenceUntilPrompt']: return False - - # First check for exact matches from settings (with backward compatibility) + + # First check for exact matches from settings (with backward + # compatibility) try: - exactMatches = self.env['runtime']['settingsManager'].getSetting('prompt', 'exactMatches') + exactMatches = self.env['runtime']['settingsManager'].getSetting( + 'prompt', 'exactMatches') if exactMatches: - exactList = [match.strip() for match in exactMatches.split(',') if match.strip()] + exactList = [match.strip() + for match in exactMatches.split(',') if match.strip()] for exactMatch in exactList: if text.strip() == exactMatch: - self.env['runtime']['debug'].writeDebugOut("Found exact prompt match: " + exactMatch, debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "Found exact prompt match: " + exactMatch, debug.debugLevel.INFO) self.disableSilence() return True except Exception as e: - # Prompt section doesn't exist in settings, skip custom exact matches + # Prompt section doesn't exist in settings, skip custom exact + # matches pass - + # Get custom patterns from settings (with backward compatibility) promptPatterns = [] try: - customPatterns = self.env['runtime']['settingsManager'].getSetting('prompt', 'customPatterns') + customPatterns = self.env['runtime']['settingsManager'].getSetting( + 'prompt', 'customPatterns') # Add custom patterns from settings if they exist if customPatterns: - customList = [pattern.strip() for pattern in customPatterns.split(',') if pattern.strip()] + customList = [ + pattern.strip() for pattern in customPatterns.split(',') if pattern.strip()] promptPatterns.extend(customList) except Exception as e: # Prompt section doesn't exist in settings, skip custom patterns pass - + # Add default shell prompt patterns promptPatterns.extend([ r'^\s*\$\s*$', # Just $ (with whitespace) - r'^\s*#\s*$', # Just # (with whitespace) + r'^\s*#\s*$', # Just # (with whitespace) r'^\s*>\s*$', # Just > (with whitespace) - r'.*@.*[\\\$#>]\s*$', # Contains @ and ends with prompt char (user@host style) + r'.*@.*[\\\$#>]\s*$', + # Contains @ and ends with prompt char (user@host style) r'^\[.*\]\s*[\\\$#>]\s*$', # [anything]$ style prompts - r'^[a-zA-Z0-9._-]+[\\\$#>]\s*$', # Simple shell names like bash-5.1$ - + # Simple shell names like bash-5.1$ + r'^[a-zA-Z0-9._-]+[\\\$#>]\s*$', + # Interactive prompt patterns # Package manager confirmation prompts r'.*\?\s*\[[YyNn]/[YyNn]\]\s*$', # ? [Y/n] or ? [y/N] style @@ -89,36 +108,43 @@ class command(): r'.*\?\s*\([Yy]es/[Nn]o\)\s*$', # ? (Yes/No) style r'.*continue\?\s*\[[YyNn]/[YyNn]\].*$', # "continue? [Y/n]" style r'.*ok\s*\[[YyNn]/[YyNn]\].*$', # "Is this ok [y/N]:" style - r'^::.*\?\s*\[[YyNn]/[YyNn]\].*$', # pacman ":: Proceed? [Y/n]" style - + # pacman ":: Proceed? [Y/n]" style + r'^::.*\?\s*\[[YyNn]/[YyNn]\].*$', + # Authentication prompts - r'^\[[Ss]udo\]\s*[Pp]assword\s*for\s+.*:\s*$', # [sudo] password for user: + # [sudo] password for user: + r'^\[[Ss]udo\]\s*[Pp]assword\s*for\s+.*:\s*$', r'^[Pp]assword\s*:\s*$', # Password: r'.*[Pp]assword\s*:\s*$', # general password prompts r".*'s\s*[Pp]assword\s*:\s*$", # user's password: r'^[Ee]nter\s+[Pp]assphrase.*:\s*$', # Enter passphrase: - r'^[Pp]lease\s+enter\s+[Pp]assphrase.*:\s*$', # Please enter passphrase: - + # Please enter passphrase: + r'^[Pp]lease\s+enter\s+[Pp]assphrase.*:\s*$', + # General confirmation and continuation prompts - r'^[Pp]ress\s+any\s+key\s+to\s+continue.*$', # Press any key to continue + # Press any key to continue + r'^[Pp]ress\s+any\s+key\s+to\s+continue.*$', r'^[Aa]re\s+you\s+sure\?\s*.*$', # Are you sure? r'^[Pp]lease\s+confirm.*$', # Please confirm r'.*confirm.*\([YyNn]/[YyNn]\).*$', # confirm (y/n) r'.*\([Yy]/[Nn]\)\s*$', # ends with (Y/n) or (y/N) ]) - + for pattern in promptPatterns: try: if re.search(pattern, text.strip()): - self.env['runtime']['debug'].writeDebugOut("Found prompt pattern: " + pattern, debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "Found prompt pattern: " + pattern, debug.debugLevel.INFO) self.disableSilence() return True except re.error as e: # Invalid regex pattern, skip it and log the error - self.env['runtime']['debug'].writeDebugOut("Invalid prompt pattern: " + pattern + " Error: " + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "Invalid prompt pattern: " + pattern + " Error: " + str(e), + debug.debugLevel.ERROR) continue - + return False - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/commands/spell_check.py b/src/fenrirscreenreader/commands/commands/spell_check.py index 73f1fd03..55a6f3be 100644 --- a/src/fenrirscreenreader/commands/commands/spell_check.py +++ b/src/fenrirscreenreader/commands/commands/spell_check.py @@ -4,6 +4,8 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import word_utils initialized = False try: @@ -11,44 +13,59 @@ try: initialized = True except Exception as e: pass - + + class command(): def __init__(self): self.language = '' self.spellChecker = None + def initialize(self, environment): self.env = environment self.updateSpellLanguage() + def shutdown(self): pass + def getDescription(self): - return _('checks the spelling of the current word') - def updateSpellLanguage(self): - if not initialized: - return - self.spellChecker = enchant.Dict(self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage')) - self.language = self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') - + return _('checks the spelling of the current word') + + def updateSpellLanguage(self): + if not initialized: + return + self.spellChecker = enchant.Dict( + self.env['runtime']['settingsManager'].getSetting( + 'general', 'spellCheckLanguage')) + self.language = self.env['runtime']['settingsManager'].getSetting( + 'general', 'spellCheckLanguage') + def run(self): if not initialized: - self.env['runtime']['outputManager'].presentText(_('pyenchant is not installed'), interrupt=True) - return - if self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') != self.language: + self.env['runtime']['outputManager'].presentText( + _('pyenchant is not installed'), interrupt=True) + return + if self.env['runtime']['settingsManager'].getSetting( + 'general', 'spellCheckLanguage') != self.language: try: self.updateSpellLanguage() except Exception as e: - return - + return + cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() - + # get the word - newContent = self.env['screen']['newContentText'].split('\n')[cursorPos['y']] - x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord(cursorPos['x'], 0, newContent) + newContent = self.env['screen']['newContentText'].split('\n')[ + cursorPos['y']] + x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord( + cursorPos['x'], 0, newContent) if not currWord.isspace(): if not self.spellChecker.check(currWord): - self.env['runtime']['outputManager'].presentText(_('misspelled'),soundIcon='mispell', interrupt=True) - elif not ignore: - self.env['runtime']['outputManager'].presentText(_('correct'),soundIcon='', interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('misspelled'), soundIcon='mispell', interrupt=True) + else: + self.env['runtime']['outputManager'].presentText( + _('correct'), soundIcon='', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/subprocess.py b/src/fenrirscreenreader/commands/commands/subprocess.py index 052923a0..1ef80ca6 100644 --- a/src/fenrirscreenreader/commands/commands/subprocess.py +++ b/src/fenrirscreenreader/commands/commands/subprocess.py @@ -4,46 +4,62 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. -import subprocess, os +from fenrirscreenreader.core.i18n import _ + +import subprocess +import os from subprocess import Popen, PIPE import _thread + class command(): def __init__(self): pass + def initialize(self, environment, scriptPath=''): self.env = environment self.scriptPath = scriptPath + def shutdown(self): pass + def getDescription(self): - return _('script: {0} fullpath: {1}').format(os.path.basename(self.scriptPath), self.scriptPath) + return _('script: {0} fullpath: {1}').format( + os.path.basename(self.scriptPath), self.scriptPath) + def run(self): if not os.path.exists(self.scriptPath): - self.env['runtime']['outputManager'].presentText(_('Script file not found'), soundIcon='', interrupt=False) - return + self.env['runtime']['outputManager'].presentText( + _('Script file not found'), soundIcon='', interrupt=False) + return if not os.path.isfile(self.scriptPath): - self.env['runtime']['outputManager'].presentText(_('Script source is not a valid file'), soundIcon='', interrupt=False) - return + self.env['runtime']['outputManager'].presentText( + _('Script source is not a valid file'), soundIcon='', interrupt=False) + return if not os.access(self.scriptPath, os.X_OK): - self.env['runtime']['outputManager'].presentText(_('Script file is not executable'), soundIcon='', interrupt=False) - return - _thread.start_new_thread(self._threadRun , ()) + self.env['runtime']['outputManager'].presentText( + _('Script file is not executable'), soundIcon='', interrupt=False) + return + _thread.start_new_thread(self._threadRun, ()) def _threadRun(self): try: - callstring = self.scriptPath + ' ' + self.env['general']['currUser'] - p = Popen(callstring , stdout=PIPE, stderr=PIPE, shell=True) + callstring = self.scriptPath + ' ' + \ + self.env['general']['currUser'] + p = Popen(callstring, stdout=PIPE, stderr=PIPE, shell=True) stdout, stderr = p.communicate() stdout = stdout.decode('utf-8') stderr = stderr.decode('utf-8') self.env['runtime']['outputManager'].interruptOutput() if stderr != '': - self.env['runtime']['outputManager'].presentText(str(stderr) , soundIcon='', interrupt=False) + self.env['runtime']['outputManager'].presentText( + str(stderr), soundIcon='', interrupt=False) if stdout != '': - self.env['runtime']['outputManager'].presentText(str(stdout) , soundIcon='', interrupt=False) + self.env['runtime']['outputManager'].presentText( + str(stdout), soundIcon='', interrupt=False) except Exception as e: - self.env['runtime']['outputManager'].presentText(e , soundIcon='', interrupt=False) - + self.env['runtime']['outputManager'].presentText( + e, soundIcon='', interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/temp_disable_speech.py b/src/fenrirscreenreader/commands/commands/temp_disable_speech.py index 6af2e32d..be038bba 100644 --- a/src/fenrirscreenreader/commands/commands/temp_disable_speech.py +++ b/src/fenrirscreenreader/commands/commands/temp_disable_speech.py @@ -5,18 +5,24 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('disables speech until next keypress') - + return _('disables speech until next keypress') + def run(self): self.env['runtime']['outputManager'].tempDisableSpeech() - + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/time.py b/src/fenrirscreenreader/commands/commands/time.py index 96b15b88..e50cc6a9 100644 --- a/src/fenrirscreenreader/commands/commands/time.py +++ b/src/fenrirscreenreader/commands/commands/time.py @@ -4,26 +4,36 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import datetime + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('presents the time') + return _('presents the time') def run(self): - timeFormat = self.env['runtime']['settingsManager'].getSetting('general', 'timeFormat') + timeFormat = self.env['runtime']['settingsManager'].getSetting( + 'general', 'timeFormat') # get the time formatted - timeString = datetime.datetime.strftime(datetime.datetime.now(), timeFormat) + timeString = datetime.datetime.strftime( + datetime.datetime.now(), timeFormat) - # present the time via speak and braile, there is no soundicon, interrupt the current speech - self.env['runtime']['outputManager'].presentText(timeString , soundIcon='', interrupt=True) + # present the time via speak and braile, there is no soundicon, + # interrupt the current speech + self.env['runtime']['outputManager'].presentText( + timeString, soundIcon='', interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_auto_indent.py b/src/fenrirscreenreader/commands/commands/toggle_auto_indent.py index 7d32187c..05a7bb46 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_auto_indent.py +++ b/src/fenrirscreenreader/commands/commands/toggle_auto_indent.py @@ -4,22 +4,34 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('enables or disables automatic reading of indentation level changes') - + return _('enables or disables automatic reading of indentation level changes') + def run(self): - self.env['runtime']['settingsManager'].setSetting('general', 'autoPresentIndent', str(not self.env['runtime']['settingsManager'].getSettingAsBool('general', 'autoPresentIndent'))) - if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'autoPresentIndent'): - self.env['runtime']['outputManager'].presentText(_("autoindent enabled"), soundIcon='', interrupt=True) + self.env['runtime']['settingsManager'].setSetting( + 'general', 'autoPresentIndent', str( + not self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'autoPresentIndent'))) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'autoPresentIndent'): + self.env['runtime']['outputManager'].presentText( + _("autoindent enabled"), soundIcon='', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_("autoindent disabled"), soundIcon='', interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("autoindent disabled"), soundIcon='', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_auto_read.py b/src/fenrirscreenreader/commands/commands/toggle_auto_read.py index b62eda2e..f8ea46cb 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_auto_read.py +++ b/src/fenrirscreenreader/commands/commands/toggle_auto_read.py @@ -4,22 +4,34 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('enables or disables automatic reading of new text as it appears') - + return _('enables or disables automatic reading of new text as it appears') + def run(self): - self.env['runtime']['settingsManager'].setSetting('speech', 'autoReadIncoming', str(not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'autoReadIncoming'))) - if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'autoReadIncoming'): - self.env['runtime']['outputManager'].presentText(_("autoread enabled"), soundIcon='', interrupt=True) + self.env['runtime']['settingsManager'].setSetting( + 'speech', 'autoReadIncoming', str( + not self.env['runtime']['settingsManager'].getSettingAsBool( + 'speech', 'autoReadIncoming'))) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'speech', 'autoReadIncoming'): + self.env['runtime']['outputManager'].presentText( + _("autoread enabled"), soundIcon='', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_("autoread disabled"), soundIcon='', interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("autoread disabled"), soundIcon='', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_auto_spell_check.py b/src/fenrirscreenreader/commands/commands/toggle_auto_spell_check.py index 622874fb..c3248c02 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_auto_spell_check.py +++ b/src/fenrirscreenreader/commands/commands/toggle_auto_spell_check.py @@ -5,22 +5,34 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('enables or disables automatic spell checking') - - def run(self): - self.env['runtime']['settingsManager'].setSetting('general', 'autoSpellCheck', str(not self.env['runtime']['settingsManager'].getSettingAsBool('general', 'autoSpellCheck'))) - if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'autoSpellCheck'): - self.env['runtime']['outputManager'].presentText(_("auto spellcheck enabled"), soundIcon='', interrupt=True) + return _('enables or disables automatic spell checking') + + def run(self): + self.env['runtime']['settingsManager'].setSetting( + 'general', 'autoSpellCheck', str( + not self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'autoSpellCheck'))) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'autoSpellCheck'): + self.env['runtime']['outputManager'].presentText( + _("auto spellcheck enabled"), soundIcon='', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_("auto spellcheck disabled"), soundIcon='', interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("auto spellcheck disabled"), soundIcon='', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_auto_time.py b/src/fenrirscreenreader/commands/commands/toggle_auto_time.py index 01ce0f41..8df0b1a4 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_auto_time.py +++ b/src/fenrirscreenreader/commands/commands/toggle_auto_time.py @@ -4,22 +4,33 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('Enables or disables automatic reading of time after specified intervals') - + return _( + 'Enables or disables automatic reading of time after specified intervals') + def run(self): - self.env['runtime']['settingsManager'].setSetting('time', 'enabled', str(not self.env['runtime']['settingsManager'].getSettingAsBool('time', 'enabled'))) - if self.env['runtime']['settingsManager'].getSettingAsBool('time', 'enabled'): - self.env['runtime']['outputManager'].presentText(_("Automatic time announcement enabled"), soundIcon='', interrupt=True) + self.env['runtime']['settingsManager'].setSetting('time', 'enabled', str( + not self.env['runtime']['settingsManager'].getSettingAsBool('time', 'enabled'))) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'time', 'enabled'): + self.env['runtime']['outputManager'].presentText( + _("Automatic time announcement enabled"), soundIcon='', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_("Automatic time announcement disabled"), soundIcon='', interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("Automatic time announcement disabled"), soundIcon='', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_barrier.py b/src/fenrirscreenreader/commands/commands/toggle_barrier.py index c0f8720a..1960eaf1 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_barrier.py +++ b/src/fenrirscreenreader/commands/commands/toggle_barrier.py @@ -4,22 +4,34 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('enables or disables the barrier mode') - + return _('enables or disables the barrier mode') + def run(self): - self.env['runtime']['settingsManager'].setSetting('barrier', 'enabled', str(not self.env['runtime']['settingsManager'].getSettingAsBool('barrier', 'enabled'))) - if self.env['runtime']['settingsManager'].getSettingAsBool('barrier', 'enabled'): - self.env['runtime']['outputManager'].presentText(_("barrier mode enabled"), soundIcon='', interrupt=True) + self.env['runtime']['settingsManager'].setSetting( + 'barrier', 'enabled', str( + not self.env['runtime']['settingsManager'].getSettingAsBool( + 'barrier', 'enabled'))) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'barrier', 'enabled'): + self.env['runtime']['outputManager'].presentText( + _("barrier mode enabled"), soundIcon='', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_("barrier mode disabled"), soundIcon='', interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("barrier mode disabled"), soundIcon='', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_emoticons.py b/src/fenrirscreenreader/commands/commands/toggle_emoticons.py index 967976cf..cba5d035 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_emoticons.py +++ b/src/fenrirscreenreader/commands/commands/toggle_emoticons.py @@ -4,22 +4,34 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('enables or disables announcement of emoticons instead of chars') - + return _('enables or disables announcement of emoticons instead of chars') + def run(self): - self.env['runtime']['settingsManager'].setSetting('general', 'emoticons', str(not self.env['runtime']['settingsManager'].getSettingAsBool('general', 'emoticons'))) - if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'emoticons'): - self.env['runtime']['outputManager'].presentText(_('emoticons enabled'), soundIcon='', interrupt=True) + self.env['runtime']['settingsManager'].setSetting( + 'general', 'emoticons', str( + not self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'emoticons'))) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'emoticons'): + self.env['runtime']['outputManager'].presentText( + _('emoticons enabled'), soundIcon='', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_('emoticons disabled'), soundIcon='', interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _('emoticons disabled'), soundIcon='', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_has_attribute.py b/src/fenrirscreenreader/commands/commands/toggle_has_attribute.py index b9eb7ea3..1c56fd4a 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_has_attribute.py +++ b/src/fenrirscreenreader/commands/commands/toggle_has_attribute.py @@ -4,22 +4,34 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('enables or disables the announcement of attributes') - + return _('enables or disables the announcement of attributes') + def run(self): - self.env['runtime']['settingsManager'].setSetting('general', 'hasAttributes', str(not self.env['runtime']['settingsManager'].getSettingAsBool('general', 'hasAttributes'))) - if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'hasAttributes'): - self.env['runtime']['outputManager'].presentText(_("announcement of attributes enabled"), soundIcon='', interrupt=True) + self.env['runtime']['settingsManager'].setSetting( + 'general', 'hasAttributes', str( + not self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'hasAttributes'))) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'hasAttributes'): + self.env['runtime']['outputManager'].presentText( + _("announcement of attributes enabled"), soundIcon='', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_("announcement of attributes disabled"), soundIcon='', interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("announcement of attributes disabled"), soundIcon='', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_highlight_tracking.py b/src/fenrirscreenreader/commands/commands/toggle_highlight_tracking.py index e2782c4d..b1e4abe8 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_highlight_tracking.py +++ b/src/fenrirscreenreader/commands/commands/toggle_highlight_tracking.py @@ -4,25 +4,37 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment - def shutdown(self): - pass - def getDescription(self): - return _('enables or disables tracking of highlighted text') - - def run(self): - currMode = self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'highlight') - self.env['runtime']['settingsManager'].setSetting('focus', 'highlight', str(not currMode)) - self.env['runtime']['settingsManager'].setSetting('focus', 'cursor', str(currMode)) - if self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'highlight'): - self.env['runtime']['outputManager'].presentText(_('highlight tracking'), soundIcon='', interrupt=True) + def shutdown(self): + pass + + def getDescription(self): + return _('enables or disables tracking of highlighted text') + + def run(self): + currMode = self.env['runtime']['settingsManager'].getSettingAsBool( + 'focus', 'highlight') + + self.env['runtime']['settingsManager'].setSetting( + 'focus', 'highlight', str(not currMode)) + self.env['runtime']['settingsManager'].setSetting( + 'focus', 'cursor', str(currMode)) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'focus', 'highlight'): + self.env['runtime']['outputManager'].presentText( + _('highlight tracking'), soundIcon='', interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_('cursor tracking'), soundIcon='', interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _('cursor tracking'), soundIcon='', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_output.py b/src/fenrirscreenreader/commands/commands/toggle_output.py index f932fcd2..ccdf9cf8 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_output.py +++ b/src/fenrirscreenreader/commands/commands/toggle_output.py @@ -5,26 +5,41 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('toggles all output settings') - + return _('toggles all output settings') + def run(self): - if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled') or \ - self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled'): - self.env['runtime']['outputManager'].presentText(_('Fenrir muted'), soundIcon='Accept', interrupt=True) - self.env['runtime']['settingsManager'].setSetting('speech', 'enabled','False') - self.env['runtime']['settingsManager'].setSetting('sound', 'enabled','False') - else: - self.env['runtime']['settingsManager'].setSetting('speech', 'enabled','True') - self.env['runtime']['settingsManager'].setSetting('sound', 'enabled','True') - self.env['runtime']['outputManager'].presentText(_('Fenrir unmuted'), soundIcon='Cancel', interrupt=True) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'speech', + 'enabled') or self.env['runtime']['settingsManager'].getSettingAsBool( + 'sound', + 'enabled'): + self.env['runtime']['outputManager'].presentText( + _('Fenrir muted'), soundIcon='Accept', interrupt=True) + self.env['runtime']['settingsManager'].setSetting( + 'speech', 'enabled', 'False') + self.env['runtime']['settingsManager'].setSetting( + 'sound', 'enabled', 'False') + else: + self.env['runtime']['settingsManager'].setSetting( + 'speech', 'enabled', 'True') + self.env['runtime']['settingsManager'].setSetting( + 'sound', 'enabled', 'True') + self.env['runtime']['outputManager'].presentText( + _('Fenrir unmuted'), soundIcon='Cancel', interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_punctuation_level.py b/src/fenrirscreenreader/commands/commands/toggle_punctuation_level.py index 7721e401..7498e9fb 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_punctuation_level.py +++ b/src/fenrirscreenreader/commands/commands/toggle_punctuation_level.py @@ -5,21 +5,30 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return '' - + return '' + def run(self): if self.env['runtime']['punctuationManager'].cyclePunctuation(): - self.env['runtime']['outputManager'].presentText(self.env['runtime']['settingsManager'].getSetting('general', 'punctuationLevel'), interrupt=True, ignorePunctuation=True) + self.env['runtime']['outputManager'].presentText( + self.env['runtime']['settingsManager'].getSetting( + 'general', 'punctuationLevel'), interrupt=True, ignorePunctuation=True) else: - self.env['runtime']['outputManager'].presentText(_('No punctuation found.'), interrupt=True, ignorePunctuation=True) - + self.env['runtime']['outputManager'].presentText( + _('No punctuation found.'), interrupt=True, ignorePunctuation=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_sound.py b/src/fenrirscreenreader/commands/commands/toggle_sound.py index 41097d17..1c7dd966 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_sound.py +++ b/src/fenrirscreenreader/commands/commands/toggle_sound.py @@ -4,22 +4,35 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('enables or disables sound') + return _('enables or disables sound') def run(self): - if self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled'): - self.env['runtime']['outputManager'].presentText(_('sound disabled'), soundIcon='SoundOff', interrupt=True) - self.env['runtime']['settingsManager'].setSetting('sound', 'enabled', str(not self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled'))) - if self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled'): - self.env['runtime']['outputManager'].presentText(_('sound enabled'), soundIcon='SoundOn', interrupt=True) - + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'sound', 'enabled'): + self.env['runtime']['outputManager'].presentText( + _('sound disabled'), soundIcon='SoundOff', interrupt=True) + self.env['runtime']['settingsManager'].setSetting( + 'sound', 'enabled', str( + not self.env['runtime']['settingsManager'].getSettingAsBool( + 'sound', 'enabled'))) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'sound', 'enabled'): + self.env['runtime']['outputManager'].presentText( + _('sound enabled'), soundIcon='SoundOn', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_speech.py b/src/fenrirscreenreader/commands/commands/toggle_speech.py index c58e9d21..6cae3f0d 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_speech.py +++ b/src/fenrirscreenreader/commands/commands/toggle_speech.py @@ -5,23 +5,36 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('enables or disables speech') - + def run(self): - if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled'): + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'speech', 'enabled'): self.env['runtime']['outputManager'].interruptOutput() - self.env['runtime']['outputManager'].presentText(_('speech disabled'), soundIcon='SpeechOff', interrupt=True) - self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', str(not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled'))) - if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled'): - self.env['runtime']['outputManager'].presentText(_('speech enabled'), soundIcon='SpeechOn', interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('speech disabled'), soundIcon='SpeechOff', interrupt=True) + self.env['runtime']['settingsManager'].setSetting( + 'speech', 'enabled', str( + not self.env['runtime']['settingsManager'].getSettingAsBool( + 'speech', 'enabled'))) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'speech', 'enabled'): + self.env['runtime']['outputManager'].presentText( + _('speech enabled'), soundIcon='SpeechOn', interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_tutorial_mode.py b/src/fenrirscreenreader/commands/commands/toggle_tutorial_mode.py index 9c98f4ba..feaa6cc8 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_tutorial_mode.py +++ b/src/fenrirscreenreader/commands/commands/toggle_tutorial_mode.py @@ -5,19 +5,30 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): self.env['runtime']['helpManager'].toggleTutorialMode() - return _('Exiting tutorial mode. To enter tutorial mode again press Fenrir+f1') + return _( + 'Exiting tutorial mode. To enter tutorial mode again press Fenrir+f1') + def run(self): self.env['runtime']['helpManager'].toggleTutorialMode() if self.env['runtime']['helpManager'].isTutorialMode(): - self.env['runtime']['outputManager'].presentText( _('Entering tutorial mode. In this mode commands are described but not executed. You can move through the list of commands with the up and down arrow keys. To Exit tutorial mode press Fenrir+f1.'), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('Entering tutorial mode. In this mode commands are described but not executed. You can move through the list of commands with the up and down arrow keys. To Exit tutorial mode press Fenrir+f1.'), + interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/toggle_vmenu_mode.py b/src/fenrirscreenreader/commands/commands/toggle_vmenu_mode.py index 89cdf81d..2a89bd27 100644 --- a/src/fenrirscreenreader/commands/commands/toggle_vmenu_mode.py +++ b/src/fenrirscreenreader/commands/commands/toggle_vmenu_mode.py @@ -5,21 +5,31 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): self.env['runtime']['vmenuManager'].togglelVMenuMode() return _('Entering or Leaving v menu mode.') + def run(self): self.env['runtime']['vmenuManager'].togglelVMenuMode() if self.env['runtime']['vmenuManager'].getActive(): - self.env['runtime']['outputManager'].presentText( _('Entering v menu.'), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('Entering v menu.'), interrupt=True) else: - self.env['runtime']['outputManager'].presentText( _('Leaving v menu.'), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('Leaving v menu.'), interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/commands/voice_browser.py b/src/fenrirscreenreader/commands/commands/voice_browser.py index 64d7806f..a79ae842 100644 --- a/src/fenrirscreenreader/commands/commands/voice_browser.py +++ b/src/fenrirscreenreader/commands/commands/voice_browser.py @@ -1,12 +1,15 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import subprocess import time + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment self.testMessage = "This is a voice test. The quick brown fox jumps over the lazy dog." @@ -17,100 +20,111 @@ class command(): self.browserActive = False self.originalBindings = {} self.lastAnnounceTime = 0 - + def shutdown(self): pass - + def getDescription(self): return "Interactive voice browser with arrow key navigation" - + def run(self): if self.browserActive: self.exitVoiceBrowser() return - - self.env['runtime']['outputManager'].presentText("Starting voice browser", interrupt=True) - + + self.env['runtime']['outputManager'].presentText( + "Starting voice browser", interrupt=True) + # Load modules self.modules = self.getSpeechdModules() if not self.modules: - self.env['runtime']['outputManager'].presentText("No speech modules found", interrupt=True) + self.env['runtime']['outputManager'].presentText( + "No speech modules found", interrupt=True) self.env['runtime']['outputManager'].playSound('Error') return - + # Set current module - currentModule = self.env['runtime']['settingsManager'].getSetting('speech', 'module') + currentModule = self.env['runtime']['settingsManager'].getSetting( + 'speech', 'module') if currentModule and currentModule in self.modules: self.moduleIndex = self.modules.index(currentModule) - + # Load voices self.loadVoicesForCurrentModule() - + # Set current voice - currentVoice = self.env['runtime']['settingsManager'].getSetting('speech', 'voice') + currentVoice = self.env['runtime']['settingsManager'].getSetting( + 'speech', 'voice') if currentVoice and currentVoice in self.voices: self.voiceIndex = self.voices.index(currentVoice) - + # Enter browser mode self.enterVoiceBrowser() self.announceCurrentSelection() - + def enterVoiceBrowser(self): """Enter voice browser mode with custom key bindings""" self.browserActive = True - + # Store original bindings self.originalBindings = self.env['bindings'].copy() - + # Override navigation keys for voice browsing # Use lambda to capture self and create bound methods self.env['bindings'][str([1, ['KEY_UP']])] = 'VOICE_BROWSER_PREV_VOICE' - self.env['bindings'][str([1, ['KEY_DOWN']])] = 'VOICE_BROWSER_NEXT_VOICE' - self.env['bindings'][str([1, ['KEY_LEFT']])] = 'VOICE_BROWSER_PREV_MODULE' - self.env['bindings'][str([1, ['KEY_RIGHT']])] = 'VOICE_BROWSER_NEXT_MODULE' + self.env['bindings'][str([1, ['KEY_DOWN']]) + ] = 'VOICE_BROWSER_NEXT_VOICE' + self.env['bindings'][str([1, ['KEY_LEFT']]) + ] = 'VOICE_BROWSER_PREV_MODULE' + self.env['bindings'][str([1, ['KEY_RIGHT']]) + ] = 'VOICE_BROWSER_NEXT_MODULE' self.env['bindings'][str([1, ['KEY_ENTER']])] = 'VOICE_BROWSER_TEST' self.env['bindings'][str([1, ['KEY_SPACE']])] = 'VOICE_BROWSER_APPLY' self.env['bindings'][str([1, ['KEY_ESC']])] = 'VOICE_BROWSER_EXIT' - + # Register browser commands self.registerBrowserCommands() - - self.env['runtime']['outputManager'].presentText("Voice browser active", interrupt=True) - self.env['runtime']['outputManager'].presentText("Up/Down=voices, Left/Right=modules, Enter=test, Space=apply, Esc=exit", interrupt=True) - + + self.env['runtime']['outputManager'].presentText( + "Voice browser active", interrupt=True) + self.env['runtime']['outputManager'].presentText( + "Up/Down=voices, Left/Right=modules, Enter=test, Space=apply, Esc=exit", + interrupt=True) + def registerBrowserCommands(self): """Register voice browser commands with the command manager""" # Create command objects for voice browser actions commandManager = self.env['runtime']['commandManager'] - + # This is a hack - we'll store references to our methods in the environment # so the key handlers can call them if 'voiceBrowserInstance' not in self.env['runtime']: self.env['runtime']['voiceBrowserInstance'] = self - + def exitVoiceBrowser(self): """Exit voice browser and restore normal key bindings""" if not self.browserActive: return - + self.browserActive = False - + # Restore original bindings self.env['bindings'] = self.originalBindings - + # Clean up if 'voiceBrowserInstance' in self.env['runtime']: del self.env['runtime']['voiceBrowserInstance'] - - self.env['runtime']['outputManager'].presentText("Voice browser exited", interrupt=True) - + + self.env['runtime']['outputManager'].presentText( + "Voice browser exited", interrupt=True) + def loadVoicesForCurrentModule(self): """Load voices for current module""" if self.moduleIndex < len(self.modules): module = self.modules[self.moduleIndex] self.voices = self.getModuleVoices(module) self.voiceIndex = 0 # Reset to first voice when changing modules - + def announceCurrentSelection(self): """Announce current module and voice""" # Throttle announcements to avoid spam @@ -118,10 +132,10 @@ class command(): if now - self.lastAnnounceTime < 0.3: return self.lastAnnounceTime = now - + if not self.modules or self.moduleIndex >= len(self.modules): return - + module = self.modules[self.moduleIndex] if self.voices and self.voiceIndex < len(self.voices): voice = self.voices[self.voiceIndex] @@ -129,44 +143,47 @@ class command(): f"{module}: {voice} ({self.voiceIndex + 1}/{len(self.voices)})", interrupt=True ) else: - self.env['runtime']['outputManager'].presentText(f"{module}: No voices", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"{module}: No voices", interrupt=True) + def nextVoice(self): """Move to next voice""" if not self.voices: return self.voiceIndex = (self.voiceIndex + 1) % len(self.voices) self.announceCurrentSelection() - + def prevVoice(self): """Move to previous voice""" if not self.voices: return self.voiceIndex = (self.voiceIndex - 1) % len(self.voices) self.announceCurrentSelection() - + def nextModule(self): """Move to next module""" self.moduleIndex = (self.moduleIndex + 1) % len(self.modules) self.loadVoicesForCurrentModule() self.announceCurrentSelection() - + def prevModule(self): """Move to previous module""" self.moduleIndex = (self.moduleIndex - 1) % len(self.modules) self.loadVoicesForCurrentModule() self.announceCurrentSelection() - + def testVoice(self): """Test current voice""" if not self.voices or self.voiceIndex >= len(self.voices): - self.env['runtime']['outputManager'].presentText("No voice selected", interrupt=True) + self.env['runtime']['outputManager'].presentText( + "No voice selected", interrupt=True) return - + module = self.modules[self.moduleIndex] voice = self.voices[self.voiceIndex] - - self.env['runtime']['outputManager'].presentText("Testing...", interrupt=True) + + self.env['runtime']['outputManager'].presentText( + "Testing...", interrupt=True) if self.previewVoice(module, voice): # Store for apply command self.env['commandBuffer']['lastTestedModule'] = module @@ -174,33 +191,35 @@ class command(): self.env['runtime']['outputManager'].playSound('Accept') else: self.env['runtime']['outputManager'].playSound('Error') - + def applyVoice(self): """Apply current voice to Fenrir""" if not self.voices or self.voiceIndex >= len(self.voices): return - + module = self.modules[self.moduleIndex] voice = self.voices[self.voiceIndex] - + try: settingsManager = self.env['runtime']['settingsManager'] settingsManager.settings['speech']['driver'] = 'speechdDriver' settingsManager.settings['speech']['module'] = module settingsManager.settings['speech']['voice'] = voice - + if 'speechDriver' in self.env['runtime']: speechDriver = self.env['runtime']['speechDriver'] speechDriver.shutdown() speechDriver.initialize(self.env) - - self.env['runtime']['outputManager'].presentText("Voice applied!", interrupt=True) + + self.env['runtime']['outputManager'].presentText( + "Voice applied!", interrupt=True) self.env['runtime']['outputManager'].playSound('Accept') - + except Exception as e: - self.env['runtime']['outputManager'].presentText("Apply failed", interrupt=True) + self.env['runtime']['outputManager'].presentText( + "Apply failed", interrupt=True) self.env['runtime']['outputManager'].playSound('Error') - + def previewVoice(self, module, voice): """Test voice with spd-say""" try: @@ -209,22 +228,24 @@ class command(): return result.returncode == 0 except Exception: return False - + def getSpeechdModules(self): """Get available speech modules""" try: - result = subprocess.run(['spd-say', '-O'], capture_output=True, text=True, timeout=10) + result = subprocess.run( + ['spd-say', '-O'], capture_output=True, text=True, timeout=10) if result.returncode == 0: lines = result.stdout.strip().split('\n') return [line.strip() for line in lines[1:] if line.strip()] except Exception: pass return [] - + def getModuleVoices(self, module): """Get voices for module""" try: - result = subprocess.run(['spd-say', '-o', module, '-L'], capture_output=True, text=True, timeout=10) + result = subprocess.run( + ['spd-say', '-o', module, '-L'], capture_output=True, text=True, timeout=10) if result.returncode == 0: lines = result.stdout.strip().split('\n') voices = [] @@ -241,7 +262,7 @@ class command(): except Exception: pass return [] - + def processEspeakVoice(self, voiceLine): """Process espeak voice format""" parts = [p for p in voiceLine.split() if p] @@ -250,6 +271,6 @@ class command(): langCode = parts[-2].lower() variant = parts[-1].lower() return f"{langCode}+{variant}" if variant and variant != 'none' else langCode - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/commands/voice_browser_apply.py b/src/fenrirscreenreader/commands/commands/voice_browser_apply.py index 1f0048d4..a5fdf0e6 100644 --- a/src/fenrirscreenreader/commands/commands/voice_browser_apply.py +++ b/src/fenrirscreenreader/commands/commands/voice_browser_apply.py @@ -1,21 +1,24 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Voice browser: apply current voice" - + def run(self): if 'voiceBrowserInstance' in self.env['runtime']: self.env['runtime']['voiceBrowserInstance'].applyVoice() - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/commands/voice_browser_exit.py b/src/fenrirscreenreader/commands/commands/voice_browser_exit.py index c8d5d17d..8cc6e230 100644 --- a/src/fenrirscreenreader/commands/commands/voice_browser_exit.py +++ b/src/fenrirscreenreader/commands/commands/voice_browser_exit.py @@ -1,21 +1,24 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Voice browser: exit browser mode" - + def run(self): if 'voiceBrowserInstance' in self.env['runtime']: self.env['runtime']['voiceBrowserInstance'].exitVoiceBrowser() - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/commands/voice_browser_next_module.py b/src/fenrirscreenreader/commands/commands/voice_browser_next_module.py index a2dc1d01..1f6768c1 100644 --- a/src/fenrirscreenreader/commands/commands/voice_browser_next_module.py +++ b/src/fenrirscreenreader/commands/commands/voice_browser_next_module.py @@ -1,21 +1,24 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Voice browser: next module" - + def run(self): if 'voiceBrowserInstance' in self.env['runtime']: self.env['runtime']['voiceBrowserInstance'].nextModule() - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/commands/voice_browser_next_voice.py b/src/fenrirscreenreader/commands/commands/voice_browser_next_voice.py index 5e56b42e..6f4434bb 100644 --- a/src/fenrirscreenreader/commands/commands/voice_browser_next_voice.py +++ b/src/fenrirscreenreader/commands/commands/voice_browser_next_voice.py @@ -1,21 +1,24 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Voice browser: next voice" - + def run(self): if 'voiceBrowserInstance' in self.env['runtime']: self.env['runtime']['voiceBrowserInstance'].nextVoice() - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/commands/voice_browser_prev_module.py b/src/fenrirscreenreader/commands/commands/voice_browser_prev_module.py index b7add887..b709c06b 100644 --- a/src/fenrirscreenreader/commands/commands/voice_browser_prev_module.py +++ b/src/fenrirscreenreader/commands/commands/voice_browser_prev_module.py @@ -1,21 +1,24 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Voice browser: previous module" - + def run(self): if 'voiceBrowserInstance' in self.env['runtime']: self.env['runtime']['voiceBrowserInstance'].prevModule() - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/commands/voice_browser_prev_voice.py b/src/fenrirscreenreader/commands/commands/voice_browser_prev_voice.py index 24c858f5..5fa164fd 100644 --- a/src/fenrirscreenreader/commands/commands/voice_browser_prev_voice.py +++ b/src/fenrirscreenreader/commands/commands/voice_browser_prev_voice.py @@ -1,21 +1,24 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Voice browser: previous voice" - + def run(self): if 'voiceBrowserInstance' in self.env['runtime']: self.env['runtime']['voiceBrowserInstance'].prevVoice() - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/commands/voice_browser_safe.py b/src/fenrirscreenreader/commands/commands/voice_browser_safe.py index 2f59aaba..1d1eab3b 100644 --- a/src/fenrirscreenreader/commands/commands/voice_browser_safe.py +++ b/src/fenrirscreenreader/commands/commands/voice_browser_safe.py @@ -1,59 +1,68 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import subprocess import threading import time + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment self.testMessage = "Voice test: The quick brown fox jumps over the lazy dog." - + def shutdown(self): pass - + def getDescription(self): return "Safe voice browser - cycles through voices without hanging" - + def run(self): try: - self.env['runtime']['outputManager'].presentText("Starting safe voice browser", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + "Starting safe voice browser", interrupt=True) + # Get modules with timeout protection modules = self.getSpeechdModulesWithTimeout() if not modules: - self.env['runtime']['outputManager'].presentText("No speech modules found", interrupt=True) + self.env['runtime']['outputManager'].presentText( + "No speech modules found", interrupt=True) return - + # Get current position from commandBuffer or start fresh - moduleIndex = self.env['commandBuffer'].get('safeBrowserModuleIndex', 0) - voiceIndex = self.env['commandBuffer'].get('safeBrowserVoiceIndex', 0) - + moduleIndex = self.env['commandBuffer'].get( + 'safeBrowserModuleIndex', 0) + voiceIndex = self.env['commandBuffer'].get( + 'safeBrowserVoiceIndex', 0) + # Ensure valid module index if moduleIndex >= len(modules): moduleIndex = 0 - + currentModule = modules[moduleIndex] - self.env['runtime']['outputManager'].presentText(f"Loading voices for {currentModule}...", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"Loading voices for {currentModule}...", interrupt=True) + # Get voices with timeout protection voices = self.getModuleVoicesWithTimeout(currentModule) if not voices: - self.env['runtime']['outputManager'].presentText(f"No voices in {currentModule}, trying next module", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"No voices in {currentModule}, trying next module", interrupt=True) moduleIndex = (moduleIndex + 1) % len(modules) self.env['commandBuffer']['safeBrowserModuleIndex'] = moduleIndex self.env['commandBuffer']['safeBrowserVoiceIndex'] = 0 return - + # Ensure valid voice index if voiceIndex >= len(voices): voiceIndex = 0 - + currentVoice = voices[voiceIndex] - + # Announce current selection self.env['runtime']['outputManager'].presentText( f"Module: {currentModule} ({moduleIndex + 1}/{len(modules)})", interrupt=True @@ -61,74 +70,84 @@ class command(): self.env['runtime']['outputManager'].presentText( f"Voice: {currentVoice} ({voiceIndex + 1}/{len(voices)})", interrupt=True ) - + # Test voice in background thread to avoid blocking - self.env['runtime']['outputManager'].presentText("Testing voice...", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + "Testing voice...", interrupt=True) + # Use threading to prevent freezing - testThread = threading.Thread(target=self.testVoiceAsync, args=(currentModule, currentVoice)) + testThread = threading.Thread( + target=self.testVoiceAsync, args=( + currentModule, currentVoice)) testThread.daemon = True testThread.start() - + # Store tested voice for apply command self.env['commandBuffer']['lastTestedModule'] = currentModule self.env['commandBuffer']['lastTestedVoice'] = currentVoice - + # Advance to next voice for next run voiceIndex += 1 if voiceIndex >= len(voices): voiceIndex = 0 moduleIndex = (moduleIndex + 1) % len(modules) - + # Store position for next run self.env['commandBuffer']['safeBrowserModuleIndex'] = moduleIndex self.env['commandBuffer']['safeBrowserVoiceIndex'] = voiceIndex - + # Give instructions - self.env['runtime']['outputManager'].presentText("Run again for next voice, or use apply voice command", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + "Run again for next voice, or use apply voice command", interrupt=True) + except Exception as e: - self.env['runtime']['outputManager'].presentText(f"Voice browser error: {str(e)}", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Voice browser error: {str(e)}", interrupt=True) self.env['runtime']['outputManager'].playSound('Error') - + def testVoiceAsync(self, module, voice): """Test voice in background thread to avoid blocking""" try: # Run with strict timeout cmd = ['spd-say', '-o', module, '-y', voice, self.testMessage] result = subprocess.run(cmd, timeout=5, capture_output=True) - + # Schedule success sound for main thread if result.returncode == 0: # We can't call outputManager from background thread safely # So we'll just let the main thread handle feedback pass - + except subprocess.TimeoutExpired: # Voice test timed out - this is okay, don't crash pass except Exception: # Any other error - also okay, don't crash pass - + def getSpeechdModulesWithTimeout(self): """Get speech modules with timeout protection""" try: - result = subprocess.run(['spd-say', '-O'], capture_output=True, text=True, timeout=3) + result = subprocess.run( + ['spd-say', '-O'], capture_output=True, text=True, timeout=3) if result.returncode == 0: lines = result.stdout.strip().split('\n') modules = [line.strip() for line in lines[1:] if line.strip()] - return modules[:10] # Limit to first 10 modules to prevent overload + # Limit to first 10 modules to prevent overload + return modules[:10] except subprocess.TimeoutExpired: - self.env['runtime']['outputManager'].presentText("Module detection timed out", interrupt=True) + self.env['runtime']['outputManager'].presentText( + "Module detection timed out", interrupt=True) except Exception as e: - self.env['runtime']['outputManager'].presentText(f"Module detection failed: {str(e)}", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Module detection failed: {str(e)}", interrupt=True) return [] - + def getModuleVoicesWithTimeout(self, module): """Get voices with timeout and limits""" try: - result = subprocess.run(['spd-say', '-o', module, '-L'], capture_output=True, text=True, timeout=5) + result = subprocess.run( + ['spd-say', '-o', module, '-L'], capture_output=True, text=True, timeout=5) if result.returncode == 0: lines = result.stdout.strip().split('\n') voices = [] @@ -141,19 +160,22 @@ class command(): voices.append(voice) else: voices.append(line.strip()) - + # Limit voice count to prevent memory issues if len(voices) > 1000: - self.env['runtime']['outputManager'].presentText(f"Found {len(voices)} voices, limiting to first 1000", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Found {len(voices)} voices, limiting to first 1000", interrupt=True) voices = voices[:1000] - + return voices except subprocess.TimeoutExpired: - self.env['runtime']['outputManager'].presentText(f"Voice detection for {module} timed out", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Voice detection for {module} timed out", interrupt=True) except Exception as e: - self.env['runtime']['outputManager'].presentText(f"Voice detection failed: {str(e)}", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Voice detection failed: {str(e)}", interrupt=True) return [] - + def processEspeakVoice(self, voiceLine): """Process espeak voice format""" try: @@ -165,6 +187,6 @@ class command(): return f"{langCode}+{variant}" if variant and variant != 'none' else langCode except Exception: return None - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/commands/voice_browser_test.py b/src/fenrirscreenreader/commands/commands/voice_browser_test.py index 9c023de4..c3ba67b2 100644 --- a/src/fenrirscreenreader/commands/commands/voice_browser_test.py +++ b/src/fenrirscreenreader/commands/commands/voice_browser_test.py @@ -1,21 +1,24 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Voice browser: test current voice" - + def run(self): if 'voiceBrowserInstance' in self.env['runtime']: self.env['runtime']['voiceBrowserInstance'].testVoice() - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/help/curr_help.py b/src/fenrirscreenreader/commands/help/curr_help.py index 3586c63d..f3b1da93 100644 --- a/src/fenrirscreenreader/commands/help/curr_help.py +++ b/src/fenrirscreenreader/commands/help/curr_help.py @@ -4,17 +4,25 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get current help message') + def run(self): - text = self.env['runtime']['helpManager'].getHelpForCurrentIndex() - self.env['runtime']['outputManager'].presentText(text, interrupt=True) + text = self.env['runtime']['helpManager'].getHelpForCurrentIndex() + self.env['runtime']['outputManager'].presentText(text, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/help/next_help.py b/src/fenrirscreenreader/commands/help/next_help.py index 3e4819b2..82fdd83d 100644 --- a/src/fenrirscreenreader/commands/help/next_help.py +++ b/src/fenrirscreenreader/commands/help/next_help.py @@ -4,18 +4,26 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get next help message') + def run(self): self.env['runtime']['helpManager'].nextIndex() - text = self.env['runtime']['helpManager'].getHelpForCurrentIndex() - self.env['runtime']['outputManager'].presentText(text, interrupt=True) + text = self.env['runtime']['helpManager'].getHelpForCurrentIndex() + self.env['runtime']['outputManager'].presentText(text, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/help/prev_help.py b/src/fenrirscreenreader/commands/help/prev_help.py index 62ad1d98..da368f48 100644 --- a/src/fenrirscreenreader/commands/help/prev_help.py +++ b/src/fenrirscreenreader/commands/help/prev_help.py @@ -4,18 +4,26 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get prev help message') + def run(self): self.env['runtime']['helpManager'].prevIndex() - text = self.env['runtime']['helpManager'].getHelpForCurrentIndex() - self.env['runtime']['outputManager'].presentText(text, interrupt=True) + text = self.env['runtime']['helpManager'].getHelpForCurrentIndex() + self.env['runtime']['outputManager'].presentText(text, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/onByteInput/10000-shut_up.py b/src/fenrirscreenreader/commands/onByteInput/10000-shut_up.py index ef808a0f..a479651a 100644 --- a/src/fenrirscreenreader/commands/onByteInput/10000-shut_up.py +++ b/src/fenrirscreenreader/commands/onByteInput/10000-shut_up.py @@ -5,31 +5,42 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return '' - + return '' + def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'interruptOnKeyPress'): - return + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'keyboard', 'interruptOnKeyPress'): + return if self.env['runtime']['inputManager'].noKeyPressed(): return if self.env['runtime']['screenManager'].isScreenChange(): return - if len(self.env['input']['currInput']) <= len(self.env['input']['prevInput']): + if len( + self.env['input']['currInput']) <= len( + self.env['input']['prevInput']): return # if the filter is set - if self.env['runtime']['settingsManager'].getSetting('keyboard', 'interruptOnKeyPressFilter').strip() != '': - filterList = self.env['runtime']['settingsManager'].getSetting('keyboard', 'interruptOnKeyPressFilter').split(',') + if self.env['runtime']['settingsManager'].getSetting( + 'keyboard', 'interruptOnKeyPressFilter').strip() != '': + filterList = self.env['runtime']['settingsManager'].getSetting( + 'keyboard', 'interruptOnKeyPressFilter').split(',') for currInput in self.env['input']['currInput']: - if not currInput in filterList: - return + if currInput not in filterList: + return self.env['runtime']['outputManager'].interruptOutput() def setCallback(self, callback): diff --git a/src/fenrirscreenreader/commands/onByteInput/15000-enable_temp_speech.py b/src/fenrirscreenreader/commands/onByteInput/15000-enable_temp_speech.py index 07fa7865..bbf0b86d 100644 --- a/src/fenrirscreenreader/commands/onByteInput/15000-enable_temp_speech.py +++ b/src/fenrirscreenreader/commands/onByteInput/15000-enable_temp_speech.py @@ -5,25 +5,34 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('disables speech until next keypress') - + return _('disables speech until next keypress') + def run(self): if not self.env['commandBuffer']['enableSpeechOnKeypress']: return - self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', str(self.env['commandBuffer']['enableSpeechOnKeypress'])) + self.env['runtime']['settingsManager'].setSetting( + 'speech', 'enabled', str( + self.env['commandBuffer']['enableSpeechOnKeypress'])) self.env['commandBuffer']['enableSpeechOnKeypress'] = False # Also disable prompt watching since speech was manually re-enabled if 'silenceUntilPrompt' in self.env['commandBuffer']: self.env['commandBuffer']['silenceUntilPrompt'] = False - self.env['runtime']['outputManager'].presentText(_("speech enabled"), soundIcon='SpeechOn', interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("speech enabled"), soundIcon='SpeechOn', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/onCursorChange/15000-char_echo.py b/src/fenrirscreenreader/commands/onCursorChange/15000-char_echo.py index e940c6de..7c8ea95b 100644 --- a/src/fenrirscreenreader/commands/onCursorChange/15000-char_echo.py +++ b/src/fenrirscreenreader/commands/onCursorChange/15000-char_echo.py @@ -5,19 +5,26 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): return 'No Description found' def run(self): - # enabled? - active = self.env['runtime']['settingsManager'].getSettingAsInt('keyboard', 'charEchoMode') + # enabled? + active = self.env['runtime']['settingsManager'].getSettingAsInt( + 'keyboard', 'charEchoMode') # 0 = off if active == 0: return @@ -25,17 +32,23 @@ class command(): if active == 2: if not self.env['input']['newCapsLock']: 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 buffer for now) - xMove = abs(self.env['screen']['newCursor']['x'] - self.env['screen']['oldCursor']['x']) + # 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 + # buffer for now) + xMove = abs( + self.env['screen']['newCursor']['x'] - + self.env['screen']['oldCursor']['x']) if xMove > 3: return if self.env['runtime']['inputManager'].getShortcutType() in ['KEY']: - if self.env['runtime']['inputManager'].getLastDeepestInput() in [['KEY_TAB']]: - return + if self.env['runtime']['inputManager'].getLastDeepestInput() in [ + ['KEY_TAB']]: + return elif self.env['runtime']['inputManager'].getShortcutType() in ['BYTE']: - if self.env['runtime']['byteManager'].getLastByteKey() in [b' ', b'\t']: - return - # detect deletion or chilling + if self.env['runtime']['byteManager'].getLastByteKey() in [ + b' ', b'\t']: + return + # detect deletion or chilling if self.env['screen']['newCursor']['x'] <= self.env['screen']['oldCursor']['x']: return # is there any change? @@ -44,10 +57,14 @@ class command(): # filter unneded space on word begin currDelta = self.env['screen']['newDelta'] if len(currDelta.strip()) != len(currDelta) and \ - currDelta.strip() != '': + currDelta.strip() != '': currDelta = currDelta.strip() - self.env['runtime']['outputManager'].presentText(currDelta, interrupt=True, ignorePunctuation=True, announceCapital=True, flush=False) + self.env['runtime']['outputManager'].presentText( + currDelta, + interrupt=True, + ignorePunctuation=True, + announceCapital=True, + flush=False) def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onCursorChange/25000-word_echo_type.py b/src/fenrirscreenreader/commands/onCursorChange/25000-word_echo_type.py index 6a05cdef..8397e14c 100644 --- a/src/fenrirscreenreader/commands/onCursorChange/25000-word_echo_type.py +++ b/src/fenrirscreenreader/commands/onCursorChange/25000-word_echo_type.py @@ -4,25 +4,33 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import word_utils import string + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No Description found' + return 'No Description found' def run(self): - # is it enabled? - if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'wordEcho'): + # is it enabled? + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'keyboard', 'wordEcho'): return # is naviation? - if self.env['screen']['newCursor']['x'] - self.env['screen']['oldCursor']['x'] != 1: + if self.env['screen']['newCursor']['x'] - \ + self.env['screen']['oldCursor']['x'] != 1: return # just when cursor move worddetection is needed if not self.env['runtime']['cursorManager'].isCursorHorizontalMove(): @@ -32,26 +40,29 @@ class command(): return # currently writing if self.env['runtime']['screenManager'].isDelta(): - return - - # get the word - newContent = self.env['screen']['newContentText'].split('\n')[self.env['screen']['newCursor']['y']] - x, y, currWord, endOfScreen, lineBreak = \ - word_utils.getCurrentWord(self.env['screen']['newCursor']['x'], 0, newContent) - - # is there a word? + return + + # get the word + newContent = self.env['screen']['newContentText'].split( + '\n')[self.env['screen']['newCursor']['y']] + x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord( + self.env['screen']['newCursor']['x'], 0, newContent) + + # is there a word? if currWord == '': return - # at the end of a word + # at the end of a word if not newContent[self.env['screen']['newCursor']['x']].isspace(): return - # at the end of a word - if (x + len(currWord) != self.env['screen']['newCursor']['x']) and \ - (x + len(currWord) != self.env['screen']['newCursor']['x']-1): - return + # at the end of a word + if (x + + len(currWord) != self.env['screen']['newCursor']['x']) and (x + + len(currWord) != self.env['screen']['newCursor']['x'] - + 1): + return - self.env['runtime']['outputManager'].presentText(currWord, interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + currWord, interrupt=True, flush=False) def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onCursorChange/35000-spell_check.py b/src/fenrirscreenreader/commands/onCursorChange/35000-spell_check.py index 61bccb1a..9921fac8 100644 --- a/src/fenrirscreenreader/commands/onCursorChange/35000-spell_check.py +++ b/src/fenrirscreenreader/commands/onCursorChange/35000-spell_check.py @@ -4,8 +4,11 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import word_utils -import os, string +import os +import string initialized = False try: @@ -13,31 +16,40 @@ try: initialized = True except Exception as e: pass - + + class command(): def __init__(self): self.language = '' self.spellChecker = '' + def initialize(self, environment): self.env = environment self.updateSpellLanguage() + def shutdown(self): pass + def getDescription(self): return 'No Description found' - - def updateSpellLanguage(self): + + def updateSpellLanguage(self): if not initialized: - return - self.spellChecker = enchant.Dict(self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage')) - self.language = self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') + return + self.spellChecker = enchant.Dict( + self.env['runtime']['settingsManager'].getSetting( + 'general', 'spellCheckLanguage')) + self.language = self.env['runtime']['settingsManager'].getSetting( + 'general', 'spellCheckLanguage') def run(self): if not initialized: - return - if not self.env['runtime']['settingsManager'].getSettingAsBool('general', 'autoSpellCheck'): return - if self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') != self.language: + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'autoSpellCheck'): + return + if self.env['runtime']['settingsManager'].getSetting( + 'general', 'spellCheckLanguage') != self.language: try: self.updateSpellLanguage() except Exception as e: @@ -46,87 +58,118 @@ class command(): # just when horizontal cursor move worddetection is needed if not self.env['runtime']['cursorManager'].isCursorHorizontalMove(): return - + # for now no new line if self.env['runtime']['cursorManager'].isCursorVerticalMove(): return # more than a keyecho? if len(self.env['screen']['newDelta']) > 1: - return + return # deletion if self.env['runtime']['screenManager'].isNegativeDelta(): - return + return # first place could not be the end of a word if self.env['screen']['newCursor']['x'] == 0: return - + # get the word (just for speedup only look at current line - newContent = self.env['screen']['newContentText'].split('\n')[self.env['screen']['newCursor']['y']] - x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord(self.env['screen']['newCursor']['x'], 0, newContent) + newContent = self.env['screen']['newContentText'].split( + '\n')[self.env['screen']['newCursor']['y']] + x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord( + self.env['screen']['newCursor']['x'], 0, newContent) # was this a typed word? if self.env['runtime']['screenManager'].isDelta(): - if not(newContent[self.env['screen']['oldCursor']['x']] in string.whitespace + '!"#$%&()*+,-./:;<=>?@[\\]^_{|}~' and x != self.env['screen']['oldCursor']['x']): + if not (newContent[self.env['screen']['oldCursor']['x']] in string.whitespace + + '!"#$%&()*+,-./:;<=>?@[\\]^_{|}~' and x != self.env['screen']['oldCursor']['x']): return else: - currWord = currWord.strip(string.whitespace + '!"#$%&()*+,-./:;<=>?@[\\]^_{|}~') + currWord = currWord.strip( + string.whitespace + '!"#$%&()*+,-./:;<=>?@[\\]^_{|}~') else: - # or just arrow arround? + # or just arrow arround? if not newContent[self.env['screen']['newCursor']['x']].isspace(): return - if (x + len(currWord) != self.env['screen']['newCursor']['x']) and \ - (x + len(currWord) != self.env['screen']['newCursor']['x']-1): - return + if (x + + len(currWord) != self.env['screen']['newCursor']['x']) and (x + + len(currWord) != self.env['screen']['newCursor']['x'] - + 1): + return # just on end of word if self.env['screen']['newCursor']['x'] > 0: - if not newContent[self.env['screen']['oldCursor']['x'] - 1].lower() in string.ascii_lowercase: + if not newContent[self.env['screen']['oldCursor'] + ['x'] - 1].lower() in string.ascii_lowercase: return - + # ignore bash buildins - if currWord in ['cd','fg','bg','alias','bind','dir','caller','buildin','command','declare','echo','enable','help','let','local','logout',\ - 'mapfile','printf','read','readarray','source','type','typeset','ulimit','unalias']: + if currWord in [ + 'cd', + 'fg', + 'bg', + 'alias', + 'bind', + 'dir', + 'caller', + 'buildin', + 'command', + 'declare', + 'echo', + 'enable', + 'help', + 'let', + 'local', + 'logout', + 'mapfile', + 'printf', + 'read', + 'readarray', + 'source', + 'type', + 'typeset', + 'ulimit', + 'unalias']: return # ignore the application name if currWord.upper() == 'FENRIR': - return - if currWord[0] =='-': + return + if currWord[0] == '-': return if currWord[0] == '/': return if currWord[0] == '#': return if currWord.startswith('./'): - return + return if '@' in currWord and '.' in currWord: - return + return if currWord[0] == '@': - return + return if currWord.isnumeric(): - return + return if currWord.isdecimal(): return if currWord.isspace(): return - + try: - if os.path.exists("/bin/"+currWord): + if os.path.exists("/bin/" + currWord): return except Exception as e: pass try: - if os.path.exists("/usr/bin/"+currWord): - return + if os.path.exists("/usr/bin/" + currWord): + return except Exception as e: pass try: - if os.path.exists("/sbin/"+currWord): - return + if os.path.exists("/sbin/" + currWord): + return except Exception as e: pass if not self.spellChecker.check(currWord): - self.env['runtime']['outputManager'].presentText(_('misspelled'), soundIcon='mispell', interrupt=False, flush=False) + self.env['runtime']['outputManager'].presentText( + _('misspelled'), soundIcon='mispell', interrupt=False, flush=False) def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onCursorChange/45000-char_delete_echo.py b/src/fenrirscreenreader/commands/onCursorChange/45000-char_delete_echo.py index 41feec75..c5619722 100644 --- a/src/fenrirscreenreader/commands/onCursorChange/45000-char_delete_echo.py +++ b/src/fenrirscreenreader/commands/onCursorChange/45000-char_delete_echo.py @@ -5,22 +5,29 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No Description found' + return 'No Description found' def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'charDeleteEcho'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'keyboard', 'charDeleteEcho'): return # detect typing or chilling if self.env['screen']['newCursor']['x'] >= self.env['screen']['oldCursor']['x']: - return + return # More than just a deletion happend if self.env['runtime']['screenManager'].isDelta(ignoreSpace=True): @@ -28,18 +35,23 @@ class command(): # no deletion if not self.env['runtime']['screenManager'].isNegativeDelta(): - return + return # too much for a single backspace... # word begin produce a diff wiht len == 2 |a | others with 1 |a| if len(self.env['screen']['newNegativeDelta']) > 2: return - + currNegativeDelta = self.env['screen']['newNegativeDelta'] if len(currNegativeDelta.strip()) != len(currNegativeDelta) and \ - currNegativeDelta.strip() != '': + currNegativeDelta.strip() != '': currNegativeDelta = currNegativeDelta.strip() - self.env['runtime']['outputManager'].presentText(currNegativeDelta, interrupt=True, ignorePunctuation=True, announceCapital=True, flush=False) + self.env['runtime']['outputManager'].presentText( + currNegativeDelta, + interrupt=True, + ignorePunctuation=True, + announceCapital=True, + flush=False) + def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onCursorChange/50000-present_char_if_cursor_change_horizontal.py b/src/fenrirscreenreader/commands/onCursorChange/50000-present_char_if_cursor_change_horizontal.py index a6609ea5..64b28392 100644 --- a/src/fenrirscreenreader/commands/onCursorChange/50000-present_char_if_cursor_change_horizontal.py +++ b/src/fenrirscreenreader/commands/onCursorChange/50000-present_char_if_cursor_change_horizontal.py @@ -4,54 +4,72 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import char_utils from fenrirscreenreader.utils import word_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return '' - + return '' + def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'cursor'): - return + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'focus', 'cursor'): + return if self.env['runtime']['screenManager'].isScreenChange(): - return - # detect an change on the screen, we just want to cursor arround, so no change should appear + return + # detect an change on the screen, we just want to cursor arround, so no + # change should appear if self.env['runtime']['screenManager'].isDelta(): return if self.env['runtime']['screenManager'].isNegativeDelta(): return # is a vertical change? if self.env['runtime']['cursorManager'].isCursorVerticalMove(): - return + return # is it a horizontal change? if not self.env['runtime']['cursorManager'].isCursorHorizontalMove(): return - - # echo word insteed of char - if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'wordEcho'): - if abs(self.env['screen']['oldCursor']['x'] - self.env['screen']['newCursor']['x']) != 1: - # get the word - newContent = self.env['screen']['newContentText'].split('\n')[self.env['screen']['newCursor']['y']] - x, y, currWord, endOfScreen, lineBreak = \ - word_utils.getCurrentWord(self.env['screen']['newCursor']['x'], 0, newContent) + + # echo word insteed of char + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'keyboard', 'wordEcho'): + if abs(self.env['screen']['oldCursor']['x'] - + self.env['screen']['newCursor']['x']) != 1: + # get the word + newContent = self.env['screen']['newContentText'].split( + '\n')[self.env['screen']['newCursor']['y']] + x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord( + self.env['screen']['newCursor']['x'], 0, newContent) if self.env['screen']['newCursor']['x'] == x: - return - x, y, currChar = char_utils.getCurrentChar(self.env['screen']['newCursor']['x'], self.env['screen']['newCursor']['y'], self.env['screen']['newContentText']) + return + x, y, currChar = char_utils.getCurrentChar( + self.env['screen']['newCursor']['x'], self.env['screen']['newCursor']['y'], self.env['screen']['newContentText']) if currChar.isspace(): # Only announce spaces during pure navigation (arrow keys) # Check if this is really navigation by looking at input history - if (self.env['runtime']['inputManager'].getShortcutType() in ['KEY'] and - self.env['runtime']['inputManager'].getLastDeepestInput()[0] in ['KEY_LEFT', 'KEY_RIGHT', 'KEY_UP', 'KEY_DOWN']): - char_utils.presentCharForReview(self.env, currChar, interrupt=True, announceCapital=True, flush=False) + if (self.env['runtime']['inputManager'].getShortcutType() in ['KEY'] and self.env['runtime'][ + 'inputManager'].getLastDeepestInput()[0] in ['KEY_LEFT', 'KEY_RIGHT', 'KEY_UP', 'KEY_DOWN']): + char_utils.presentCharForReview( + self.env, currChar, interrupt=True, announceCapital=True, flush=False) else: - self.env['runtime']['outputManager'].presentText(currChar, interrupt=True, ignorePunctuation=True, announceCapital=True, flush=False) + self.env['runtime']['outputManager'].presentText( + currChar, + interrupt=True, + ignorePunctuation=True, + announceCapital=True, + flush=False) + def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onCursorChange/55000-tab_completion.py b/src/fenrirscreenreader/commands/onCursorChange/55000-tab_completion.py index b980c78e..1762b1f4 100644 --- a/src/fenrirscreenreader/commands/onCursorChange/55000-tab_completion.py +++ b/src/fenrirscreenreader/commands/onCursorChange/55000-tab_completion.py @@ -5,32 +5,43 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): return 'No Description found' + def run(self): # try to detect the tab completion by cursor change - xMove = self.env['screen']['newCursor']['x'] - self.env['screen']['oldCursor']['x'] + xMove = self.env['screen']['newCursor']['x'] - \ + self.env['screen']['oldCursor']['x'] if xMove <= 0: return if self.env['runtime']['inputManager'].getShortcutType() in ['KEY']: - if not (self.env['runtime']['inputManager'].getLastDeepestInput() in [['KEY_TAB']]): + if not ( + self.env['runtime']['inputManager'].getLastDeepestInput() in [ + ['KEY_TAB']]): if xMove < 5: - return + return elif self.env['runtime']['inputManager'].getShortcutType() in ['BYTE']: found = False - for currByte in self.env['runtime']['byteManager'].getLastByteKey(): + for currByte in self.env['runtime']['byteManager'].getLastByteKey( + ): if currByte == 9: found = True if not found: if xMove < 5: - return + return # is there any change? if not self.env['runtime']['screenManager'].isDelta(): return @@ -39,10 +50,10 @@ class command(): # filter unneded space on word begin currDelta = self.env['screen']['newDelta'] if len(currDelta.strip()) != len(currDelta) and \ - currDelta.strip() != '': + currDelta.strip() != '': currDelta = currDelta.strip() - self.env['runtime']['outputManager'].presentText(currDelta, interrupt=True, announceCapital=True, flush=False) + self.env['runtime']['outputManager'].presentText( + currDelta, interrupt=True, announceCapital=True, flush=False) def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onCursorChange/60000-word_echo_navigation.py b/src/fenrirscreenreader/commands/onCursorChange/60000-word_echo_navigation.py index d108c1cd..b236dd2a 100644 --- a/src/fenrirscreenreader/commands/onCursorChange/60000-word_echo_navigation.py +++ b/src/fenrirscreenreader/commands/onCursorChange/60000-word_echo_navigation.py @@ -4,22 +4,29 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import word_utils import string + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No Description found' + return 'No Description found' def run(self): - # is navigation? - if not abs(self.env['screen']['oldCursor']['x'] - self.env['screen']['newCursor']['x']) > 1: + # is navigation? + if not abs(self.env['screen']['oldCursor']['x'] - + self.env['screen']['newCursor']['x']) > 1: return # just when cursor move worddetection is needed @@ -30,24 +37,25 @@ class command(): return # currently writing if self.env['runtime']['screenManager'].isDelta(): - return - - # get the word - newContent = self.env['screen']['newContentText'].split('\n')[self.env['screen']['newCursor']['y']] - x, y, currWord, endOfScreen, lineBreak = \ - word_utils.getCurrentWord(self.env['screen']['newCursor']['x'], 0, newContent) - - # is there a word? + return + + # get the word + newContent = self.env['screen']['newContentText'].split( + '\n')[self.env['screen']['newCursor']['y']] + x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord( + self.env['screen']['newCursor']['x'], 0, newContent) + + # is there a word? if currWord == '': return - # at the start of a word - if (x + len(currWord) != self.env['screen']['newCursor']['x']) and \ - (self.env['screen']['newCursor']['x'] != x): - return + # at the start of a word + if (x + len(currWord) != self.env['screen']['newCursor']['x']) and \ + (self.env['screen']['newCursor']['x'] != x): + return - self.env['runtime']['outputManager'].presentText(currWord, interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + currWord, interrupt=True, flush=False) def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onCursorChange/65000-present_line_if_cursor_change_vertical.py b/src/fenrirscreenreader/commands/onCursorChange/65000-present_line_if_cursor_change_vertical.py index 057ffe27..f5f79b86 100644 --- a/src/fenrirscreenreader/commands/onCursorChange/65000-present_line_if_cursor_change_vertical.py +++ b/src/fenrirscreenreader/commands/onCursorChange/65000-present_line_if_cursor_change_vertical.py @@ -4,58 +4,76 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import line_utils from fenrirscreenreader.utils import word_utils + class command(): def __init__(self): self.lastIdent = -1 + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return '' - + return '' + def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'cursor'): - return + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'focus', 'cursor'): + return if self.env['runtime']['screenManager'].isScreenChange(): - self.lastIdent = 0 - return - # this leads to problems in vim -> status line change -> no announcement, so we do check the lengh as hack + self.lastIdent = 0 + return + # this leads to problems in vim -> status line change -> no + # announcement, so we do check the lengh as hack if self.env['runtime']['screenManager'].isDelta(): return - + # is a vertical change? if not self.env['runtime']['cursorManager'].isCursorVerticalMove(): - return - - x, y, currLine = line_utils.getCurrentLine(self.env['screen']['newCursor']['x'], self.env['screen']['newCursor']['y'], self.env['screen']['newContentText']) + return + + x, y, currLine = line_utils.getCurrentLine( + self.env['screen']['newCursor']['x'], self.env['screen']['newCursor']['y'], self.env['screen']['newContentText']) if currLine.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + _("blank"), soundIcon='EmptyLine', interrupt=True, flush=False) else: # ident currIdent = len(currLine) - len(currLine.lstrip()) if self.lastIdent == -1: self.lastIdent = currIdent doInterrupt = True - if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'autoPresentIndent'): - if self.env['runtime']['settingsManager'].getSettingAsInt('general', 'autoPresentIndentMode') in [0,1]: - self.env['runtime']['outputManager'].playFrequence(currIdent * 50, 0.1, interrupt=doInterrupt) - if self.env['runtime']['settingsManager'].getSettingAsInt('general', 'autoPresentIndentMode') in [0,2]: - if self.lastIdent != currIdent: - self.env['runtime']['outputManager'].presentText(_('indented ') + str(currIdent) + ' ', interrupt=doInterrupt, flush=False) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'autoPresentIndent'): + if self.env['runtime']['settingsManager'].getSettingAsInt( + 'general', 'autoPresentIndentMode') in [0, 1]: + self.env['runtime']['outputManager'].playFrequence( + currIdent * 50, 0.1, interrupt=doInterrupt) + if self.env['runtime']['settingsManager'].getSettingAsInt( + 'general', 'autoPresentIndentMode') in [0, 2]: + if self.lastIdent != currIdent: + self.env['runtime']['outputManager'].presentText( + _('indented ') + str(currIdent) + ' ', interrupt=doInterrupt, flush=False) doInterrupt = False # barrier sayLine = currLine - if self.env['runtime']['settingsManager'].getSettingAsBool('barrier','enabled'): - isBarrier, barrierLine = self.env['runtime']['barrierManager'].handleLineBarrier(self.env['screen']['newContentText'].split('\n'), self.env['screen']['newCursor']['x'],self.env['screen']['newCursor']['y']) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'barrier', 'enabled'): + isBarrier, barrierLine = self.env['runtime']['barrierManager'].handleLineBarrier( + self.env['screen']['newContentText'].split('\n'), self.env['screen']['newCursor']['x'], self.env['screen']['newCursor']['y']) if isBarrier: sayLine = barrierLine # output - self.env['runtime']['outputManager'].presentText(sayLine, interrupt=doInterrupt, flush=False) + self.env['runtime']['outputManager'].presentText( + sayLine, interrupt=doInterrupt, flush=False) self.lastIdent = currIdent + def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onCursorChange/68000-auto_identation_horizontal.py b/src/fenrirscreenreader/commands/onCursorChange/68000-auto_identation_horizontal.py index 49d9e50c..07f51b82 100644 --- a/src/fenrirscreenreader/commands/onCursorChange/68000-auto_identation_horizontal.py +++ b/src/fenrirscreenreader/commands/onCursorChange/68000-auto_identation_horizontal.py @@ -4,21 +4,28 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import line_utils from fenrirscreenreader.utils import word_utils + class command(): def __init__(self): self.lastIdent = -1 + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): return '' - + def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'cursor'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'focus', 'cursor'): return if self.env['runtime']['screenManager'].isScreenChange(): self.lastIdent = 0 @@ -27,12 +34,14 @@ class command(): # is a vertical change? if not self.env['runtime']['cursorManager'].isCursorHorizontalMove(): return - x, y, currLine = line_utils.getCurrentLine(self.env['screen']['newCursor']['x'], self.env['screen']['newCursor']['y'], self.env['screen']['newContentText']) + x, y, currLine = line_utils.getCurrentLine( + self.env['screen']['newCursor']['x'], self.env['screen']['newCursor']['y'], self.env['screen']['newContentText']) currIdent = self.env['screen']['newCursor']['x'] if not currLine.isspace(): # ident - lastIdent, lastY, lastLine = line_utils.getCurrentLine(self.env['screen']['newCursor']['x'], self.env['screen']['newCursor']['y'], self.env['screen']['oldContentText']) + lastIdent, lastY, lastLine = line_utils.getCurrentLine( + self.env['screen']['newCursor']['x'], self.env['screen']['newCursor']['y'], self.env['screen']['oldContentText']) if currLine.strip() != lastLine.strip(): return if len(currLine.lstrip()) == len(lastLine.lstrip()): @@ -44,13 +53,18 @@ class command(): self.lastIdent = currIdent if currIdent <= 0: return - if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'autoPresentIndent'): - if self.env['runtime']['settingsManager'].getSettingAsInt('general', 'autoPresentIndentMode') in [0,1]: - self.env['runtime']['outputManager'].playFrequence(currIdent * 50, 0.1, interrupt=False) - if self.env['runtime']['settingsManager'].getSettingAsInt('general', 'autoPresentIndentMode') in [0,2]: - if self.lastIdent != currIdent: - self.env['runtime']['outputManager'].presentText(_('indented ') + str(currIdent) + ' ', interrupt=False, flush=False) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'autoPresentIndent'): + if self.env['runtime']['settingsManager'].getSettingAsInt( + 'general', 'autoPresentIndentMode') in [0, 1]: + self.env['runtime']['outputManager'].playFrequence( + currIdent * 50, 0.1, interrupt=False) + if self.env['runtime']['settingsManager'].getSettingAsInt( + 'general', 'autoPresentIndentMode') in [0, 2]: + if self.lastIdent != currIdent: + self.env['runtime']['outputManager'].presentText( + _('indented ') + str(currIdent) + ' ', interrupt=False, flush=False) self.lastIdent = currIdent + def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onCursorChange/85000-has_attribute.py b/src/fenrirscreenreader/commands/onCursorChange/85000-has_attribute.py index c7e9eed0..4c1a2fc3 100644 --- a/src/fenrirscreenreader/commands/onCursorChange/85000-has_attribute.py +++ b/src/fenrirscreenreader/commands/onCursorChange/85000-has_attribute.py @@ -4,30 +4,41 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.utils import screen_utils + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return _('Reads attributes of current cursor position') + return _('Reads attributes of current cursor position') + def run(self): - # is it enabled? - if not self.env['runtime']['settingsManager'].getSettingAsBool('general', 'hasAttributes'): - return + # is it enabled? + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'hasAttributes'): + return # is a vertical change? - if not (self.env['runtime']['cursorManager'].isCursorVerticalMove() or\ - self.env['runtime']['cursorManager'].isCursorHorizontalMove()): - return + if not (self.env['runtime']['cursorManager'].isCursorVerticalMove() or + self.env['runtime']['cursorManager'].isCursorHorizontalMove()): + return cursorPos = self.env['screen']['newCursor'] - - if not self.env['runtime']['attributeManager'].hasAttributes(cursorPos): + + if not self.env['runtime']['attributeManager'].hasAttributes( + cursorPos): return - self.env['runtime']['outputManager'].presentText('has attribute', soundIcon='HasAttributes', interrupt=False) + self.env['runtime']['outputManager'].presentText( + 'has attribute', soundIcon='HasAttributes', interrupt=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/onCursorChange/95000-exit_review_mode.py b/src/fenrirscreenreader/commands/onCursorChange/95000-exit_review_mode.py index bde418da..aced019b 100644 --- a/src/fenrirscreenreader/commands/onCursorChange/95000-exit_review_mode.py +++ b/src/fenrirscreenreader/commands/onCursorChange/95000-exit_review_mode.py @@ -5,21 +5,28 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('exits review mode') - + return _('exits review mode') + def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('review', 'leaveReviewOnCursorChange'): - return + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'leaveReviewOnCursorChange'): + return if self.env['runtime']['cursorManager'].isReviewMode(): self.env['runtime']['cursorManager'].clearReviewCursor() - + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/onHeartBeat/2000-GetSessionInfo.py b/src/fenrirscreenreader/commands/onHeartBeat/2000-GetSessionInfo.py index c986b0d9..171986d4 100755 --- a/src/fenrirscreenreader/commands/onHeartBeat/2000-GetSessionInfo.py +++ b/src/fenrirscreenreader/commands/onHeartBeat/2000-GetSessionInfo.py @@ -1,4 +1,7 @@ #!/usr/bin/env python3 + +from fenrirscreenreader.core.i18n import _ + import time # -*- coding: utf-8 -*- @@ -8,21 +11,25 @@ import time import time import datetime + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment self.lastTime = datetime.datetime.now() self.lastDateString = '' - self.lastTimeString = '' + self.lastTimeString = '' + def shutdown(self): pass + def getDescription(self): - return 'No Description found' + return 'No Description found' def run(self): - self.env['runtime']['screenDriver'].getSessionInformation() + self.env['runtime']['screenDriver'].getSessionInformation() + def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onHeartBeat/76000-time.py b/src/fenrirscreenreader/commands/onHeartBeat/76000-time.py index 59537a44..7094077b 100755 --- a/src/fenrirscreenreader/commands/onHeartBeat/76000-time.py +++ b/src/fenrirscreenreader/commands/onHeartBeat/76000-time.py @@ -4,9 +4,12 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import time import datetime + class command(): def __init__(self): pass @@ -24,11 +27,14 @@ class command(): return 'No Description found' def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('time', 'enabled'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'time', 'enabled'): return - onMinutes = self.env['runtime']['settingsManager'].getSetting('time', 'onMinutes') - delaySec = self.env['runtime']['settingsManager'].getSettingAsInt('time', 'delaySec') + onMinutes = self.env['runtime']['settingsManager'].getSetting( + 'time', 'onMinutes') + delaySec = self.env['runtime']['settingsManager'].getSettingAsInt( + 'time', 'delaySec') # no need if onMinutes == '' and delaySec <= 0: @@ -50,32 +56,44 @@ class command(): if now.minute == self.lastTime.minute: return - dateFormat = self.env['runtime']['settingsManager'].getSetting('general', 'dateFormat') + dateFormat = self.env['runtime']['settingsManager'].getSetting( + 'general', 'dateFormat') dateString = datetime.datetime.strftime(now, dateFormat) - presentDate = self.env['runtime']['settingsManager'].getSettingAsBool('time', 'presentDate') and \ - self.lastDateString != dateString - presentTime = self.env['runtime']['settingsManager'].getSettingAsBool('time', 'presentTime') + presentDate = self.env['runtime']['settingsManager'].getSettingAsBool( + 'time', 'presentDate') and self.lastDateString != dateString + presentTime = self.env['runtime']['settingsManager'].getSettingAsBool( + 'time', 'presentTime') # no changed value to announce if not (presentDate or presentTime): return - timeFormat = self.env['runtime']['settingsManager'].getSetting('general', 'timeFormat') + timeFormat = self.env['runtime']['settingsManager'].getSetting( + 'general', 'timeFormat') timeString = datetime.datetime.strftime(now, timeFormat) - if self.env['runtime']['settingsManager'].getSettingAsBool('time', 'interrupt'): + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'time', 'interrupt'): self.env['runtime']['outputManager'].interruptOutput() - if self.env['runtime']['settingsManager'].getSettingAsBool('time', 'announce'): + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'time', 'announce'): self.env['runtime']['outputManager'].playSoundIcon('announce') if presentTime: # present the time - self.env['runtime']['outputManager'].presentText(_("It's {0}").format(timeString.replace(':00', " O'clock ").lstrip('0')), soundIcon='', interrupt=False) + self.env['runtime']['outputManager'].presentText( + _("It's {0}").format( + timeString.replace( + ':00', + " O'clock ").lstrip('0')), + soundIcon='', + interrupt=False) # Check if it's 12:00 AM if now.hour == 0 and now.minute == 0: # present the date - self.env['runtime']['outputManager'].presentText(dateString, soundIcon='', interrupt=False) + self.env['runtime']['outputManager'].presentText( + dateString, soundIcon='', interrupt=False) self.lastTime = datetime.datetime.now() self.lastTimeString = timeString diff --git a/src/fenrirscreenreader/commands/onKeyInput/10000-shut_up.py b/src/fenrirscreenreader/commands/onKeyInput/10000-shut_up.py index 71f0b1b1..080721b7 100644 --- a/src/fenrirscreenreader/commands/onKeyInput/10000-shut_up.py +++ b/src/fenrirscreenreader/commands/onKeyInput/10000-shut_up.py @@ -4,31 +4,42 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return '' - + return '' + def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'interruptOnKeyPress'): - return + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'keyboard', 'interruptOnKeyPress'): + return if self.env['runtime']['inputManager'].noKeyPressed(): return if self.env['runtime']['screenManager'].isScreenChange(): return - if len(self.env['input']['currInput']) <= len(self.env['input']['prevInput']): + if len( + self.env['input']['currInput']) <= len( + self.env['input']['prevInput']): return # if the filter is set - if self.env['runtime']['settingsManager'].getSetting('keyboard', 'interruptOnKeyPressFilter').strip() != '': - filterList = self.env['runtime']['settingsManager'].getSetting('keyboard', 'interruptOnKeyPressFilter').split(',') + if self.env['runtime']['settingsManager'].getSetting( + 'keyboard', 'interruptOnKeyPressFilter').strip() != '': + filterList = self.env['runtime']['settingsManager'].getSetting( + 'keyboard', 'interruptOnKeyPressFilter').split(',') for currInput in self.env['input']['currInput']: - if not currInput in filterList: - return + if currInput not in filterList: + return self.env['runtime']['outputManager'].interruptOutput() def setCallback(self, callback): diff --git a/src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py b/src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py index 00a5d9a5..5a2fc2c1 100644 --- a/src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py +++ b/src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py @@ -5,29 +5,38 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('disables speech until next keypress') - + return _('disables speech until next keypress') + def run(self): if self.env['runtime']['inputManager'].noKeyPressed(): - return - if len(self.env['input']['prevInput']) >0: + return + if len(self.env['input']['prevInput']) > 0: return if not self.env['commandBuffer']['enableSpeechOnKeypress']: return - self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', str(self.env['commandBuffer']['enableSpeechOnKeypress'])) + self.env['runtime']['settingsManager'].setSetting( + 'speech', 'enabled', str( + self.env['commandBuffer']['enableSpeechOnKeypress'])) self.env['commandBuffer']['enableSpeechOnKeypress'] = False # Also disable prompt watching since speech was manually re-enabled if 'silenceUntilPrompt' in self.env['commandBuffer']: self.env['commandBuffer']['silenceUntilPrompt'] = False - self.env['runtime']['outputManager'].presentText(_("speech enabled"), soundIcon='SpeechOn', interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("speech enabled"), soundIcon='SpeechOn', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/onKeyInput/80000-capslock.py b/src/fenrirscreenreader/commands/onKeyInput/80000-capslock.py index 6568b836..d045bd0c 100644 --- a/src/fenrirscreenreader/commands/onKeyInput/80000-capslock.py +++ b/src/fenrirscreenreader/commands/onKeyInput/80000-capslock.py @@ -5,22 +5,31 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): if self.env['input']['oldCapsLock'] == self.env['input']['newCapsLock']: return if self.env['input']['newCapsLock']: - self.env['runtime']['outputManager'].presentText(_("Capslock on"), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _("Capslock on"), interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_("Capslock off"), interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("Capslock off"), interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/onKeyInput/80300-scrolllock.py b/src/fenrirscreenreader/commands/onKeyInput/80300-scrolllock.py index 752110ba..d1fae9b2 100644 --- a/src/fenrirscreenreader/commands/onKeyInput/80300-scrolllock.py +++ b/src/fenrirscreenreader/commands/onKeyInput/80300-scrolllock.py @@ -5,22 +5,31 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): if self.env['input']['oldScrollLock'] == self.env['input']['newScrollLock']: return if self.env['input']['newScrollLock']: - self.env['runtime']['outputManager'].presentText(_("Scrolllock on"), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _("Scrolllock on"), interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_("Scrolllock off"), interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("Scrolllock off"), interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/onKeyInput/80500-numlock.py b/src/fenrirscreenreader/commands/onKeyInput/80500-numlock.py index 39b0fb92..9b79caf3 100644 --- a/src/fenrirscreenreader/commands/onKeyInput/80500-numlock.py +++ b/src/fenrirscreenreader/commands/onKeyInput/80500-numlock.py @@ -5,22 +5,31 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): if self.env['input']['oldNumLock'] == self.env['input']['newNumLock']: return if self.env['input']['newNumLock']: - self.env['runtime']['outputManager'].presentText(_("Numlock on"), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _("Numlock on"), interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_("Numlock off"), interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _("Numlock off"), interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/onKeyInput/81000-key_echo.py b/src/fenrirscreenreader/commands/onKeyInput/81000-key_echo.py index a5df3c4c..f6dffda9 100644 --- a/src/fenrirscreenreader/commands/onKeyInput/81000-key_echo.py +++ b/src/fenrirscreenreader/commands/onKeyInput/81000-key_echo.py @@ -5,15 +5,22 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): return 'No description found' + def run(self): if self.env['runtime']['helpManager'].isTutorialMode(): self.env['runtime']['inputManager'].keyEcho() diff --git a/src/fenrirscreenreader/commands/onPlugInputDevice/50000-plugSound.py b/src/fenrirscreenreader/commands/onPlugInputDevice/50000-plugSound.py index cdcede66..f923c249 100755 --- a/src/fenrirscreenreader/commands/onPlugInputDevice/50000-plugSound.py +++ b/src/fenrirscreenreader/commands/onPlugInputDevice/50000-plugSound.py @@ -4,30 +4,40 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import time + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment self.lastTime = time.time() + def shutdown(self): pass + def getDescription(self): return 'No description found' + def run(self): playSound = False - deviceList = self.env['runtime']['inputManager'].getLastDetectedDevices() + deviceList = self.env['runtime']['inputManager'].getLastDetectedDevices( + ) try: for deviceEntry in deviceList: - # dont play sounds for virtual devices + # dont play sounds for virtual devices playSound = playSound or not deviceEntry['virtual'] except Exception as e: playSound = True if playSound: if time.time() - self.lastTime > 5: - self.env['runtime']['outputManager'].playSoundIcon(soundIcon = 'accept', interrupt=True) + self.env['runtime']['outputManager'].playSoundIcon( + soundIcon='accept', interrupt=True) lastTime = time.time() + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/onScreenChanged/10000-shut_up.py b/src/fenrirscreenreader/commands/onScreenChanged/10000-shut_up.py index e1e18141..5ac64550 100644 --- a/src/fenrirscreenreader/commands/onScreenChanged/10000-shut_up.py +++ b/src/fenrirscreenreader/commands/onScreenChanged/10000-shut_up.py @@ -4,16 +4,22 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return '' - + return '' + def run(self): self.env['runtime']['outputManager'].interruptOutput() diff --git a/src/fenrirscreenreader/commands/onScreenChanged/20000-reset_last_cursor_attribute.py b/src/fenrirscreenreader/commands/onScreenChanged/20000-reset_last_cursor_attribute.py index 945bbe5c..b9c46148 100644 --- a/src/fenrirscreenreader/commands/onScreenChanged/20000-reset_last_cursor_attribute.py +++ b/src/fenrirscreenreader/commands/onScreenChanged/20000-reset_last_cursor_attribute.py @@ -5,15 +5,21 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No Description found' + return 'No Description found' def run(self): self.env['runtime']['attributeManager'].resetLastCursorAttribute() diff --git a/src/fenrirscreenreader/commands/onScreenChanged/21000-reset_barrier_change.py b/src/fenrirscreenreader/commands/onScreenChanged/21000-reset_barrier_change.py index 2f4d51e4..00ef1855 100644 --- a/src/fenrirscreenreader/commands/onScreenChanged/21000-reset_barrier_change.py +++ b/src/fenrirscreenreader/commands/onScreenChanged/21000-reset_barrier_change.py @@ -5,15 +5,21 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No Description found' + return 'No Description found' def run(self): self.env['runtime']['barrierManager'].resetBarrierChange() diff --git a/src/fenrirscreenreader/commands/onScreenChanged/70000-barrier_detect.py b/src/fenrirscreenreader/commands/onScreenChanged/70000-barrier_detect.py index 02a23b70..05fcf955 100644 --- a/src/fenrirscreenreader/commands/onScreenChanged/70000-barrier_detect.py +++ b/src/fenrirscreenreader/commands/onScreenChanged/70000-barrier_detect.py @@ -5,22 +5,31 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No Description found' + return 'No Description found' def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('barrier','enabled'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'barrier', 'enabled'): return - self.env['runtime']['barrierManager'].handleLineBarrier(self.env['screen']['newContentText'].split('\n'), self.env['screen']['newCursor']['x'],self.env['screen']['newCursor']['y']) + self.env['runtime']['barrierManager'].handleLineBarrier( + self.env['screen']['newContentText'].split('\n'), + self.env['screen']['newCursor']['x'], + self.env['screen']['newCursor']['y']) def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onScreenChanged/80000-screen_change_announcement.py b/src/fenrirscreenreader/commands/onScreenChanged/80000-screen_change_announcement.py index cbd60d48..65d8bc3d 100644 --- a/src/fenrirscreenreader/commands/onScreenChanged/80000-screen_change_announcement.py +++ b/src/fenrirscreenreader/commands/onScreenChanged/80000-screen_change_announcement.py @@ -5,20 +5,31 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No Description found' + return 'No Description found' def run(self): - self.env['runtime']['outputManager'].presentText(_("screen {0}").format(self.env['screen']['newTTY']),soundIcon='ChangeTTY', interrupt=True, flush=False) - self.env['runtime']['outputManager'].presentText(self.env['screen']['newContentText'], interrupt=False, flush=False) + self.env['runtime']['outputManager'].presentText( + _("screen {0}").format( + self.env['screen']['newTTY']), + soundIcon='ChangeTTY', + interrupt=True, + flush=False) + self.env['runtime']['outputManager'].presentText( + self.env['screen']['newContentText'], interrupt=False, flush=False) def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onScreenChanged/85000-reset_marks.py b/src/fenrirscreenreader/commands/onScreenChanged/85000-reset_marks.py index 1cc55473..ac28a580 100644 --- a/src/fenrirscreenreader/commands/onScreenChanged/85000-reset_marks.py +++ b/src/fenrirscreenreader/commands/onScreenChanged/85000-reset_marks.py @@ -5,19 +5,24 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No Description found' + return 'No Description found' def run(self): self.env['runtime']['cursorManager'].clearMarks() def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onScreenChanged/89000-leave_review_mode.py b/src/fenrirscreenreader/commands/onScreenChanged/89000-leave_review_mode.py index 505bbddf..a8d735b5 100644 --- a/src/fenrirscreenreader/commands/onScreenChanged/89000-leave_review_mode.py +++ b/src/fenrirscreenreader/commands/onScreenChanged/89000-leave_review_mode.py @@ -5,21 +5,27 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No Description found' + return 'No Description found' def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('review', 'leaveReviewOnScreenChange'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'review', 'leaveReviewOnScreenChange'): return self.env['runtime']['cursorManager'].clearReviewCursor() def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onScreenUpdate/56000-highlight_tracking.py b/src/fenrirscreenreader/commands/onScreenUpdate/56000-highlight_tracking.py index 5198ebd5..70cc4801 100644 --- a/src/fenrirscreenreader/commands/onScreenUpdate/56000-highlight_tracking.py +++ b/src/fenrirscreenreader/commands/onScreenUpdate/56000-highlight_tracking.py @@ -4,19 +4,30 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('enables or disables tracking of highlighted') + def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'highlight'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'focus', 'highlight'): return - attributeDelta = self.env['runtime']['attributeManager'].getAttributeDelta() - self.env['runtime']['outputManager'].presentText(attributeDelta, soundIcon='', interrupt=True, flush=False) + attributeDelta = self.env['runtime']['attributeManager'].getAttributeDelta( + ) + self.env['runtime']['outputManager'].presentText( + attributeDelta, soundIcon='', interrupt=True, flush=False) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/onScreenUpdate/60000-history.py b/src/fenrirscreenreader/commands/onScreenUpdate/60000-history.py index fba8c870..64ecd4f1 100644 --- a/src/fenrirscreenreader/commands/onScreenUpdate/60000-history.py +++ b/src/fenrirscreenreader/commands/onScreenUpdate/60000-history.py @@ -5,18 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): return '' + def run(self): if self.env['screen']['newAttribDelta'] != '': - return + return if self.env['runtime']['screenManager'].isScreenChange(): return if self.env['runtime']['cursorManager'].isCursorVerticalMove(): @@ -25,25 +32,34 @@ class command(): return # hack for pdmenu and maybe other dialog apps that place the cursor at last cell/row # this is not to be identified as history - if (self.env['screen']['newCursor']['x'] == self.env['runtime']['screenManager'].getColumns() - 1) and (self.env['screen']['newCursor']['y'] == self.env['runtime']['screenManager'].getRows() - 1): + if (self.env['screen']['newCursor']['x'] == self.env['runtime']['screenManager'].getColumns( + ) - 1) and (self.env['screen']['newCursor']['y'] == self.env['runtime']['screenManager'].getRows() - 1): return if self.env['runtime']['inputManager'].getShortcutType() in ['KEY']: - if not (self.env['runtime']['inputManager'].getLastDeepestInput() in [['KEY_UP'],['KEY_DOWN']]): - return + if not ( + self.env['runtime']['inputManager'].getLastDeepestInput() in [ + ['KEY_UP'], + ['KEY_DOWN']]): + return elif self.env['runtime']['inputManager'].getShortcutType() in ['BYTE']: - if not (self.env['runtime']['byteManager'].getLastByteKey() in [b'^[[A',b'^[[B']): - return + if not ( + self.env['runtime']['byteManager'].getLastByteKey() in [ + b'^[[A', + b'^[[B']): + return # Get the current cursor's line from both old and new content - prevLine = self.env['screen']['oldContentText'].split('\n')[self.env['screen']['newCursor']['y']] - currLine = self.env['screen']['newContentText'].split('\n')[self.env['screen']['newCursor']['y']] - + prevLine = self.env['screen']['oldContentText'].split( + '\n')[self.env['screen']['newCursor']['y']] + currLine = self.env['screen']['newContentText'].split( + '\n')[self.env['screen']['newCursor']['y']] + is_blank = currLine.strip() == '' - + if prevLine == currLine: if self.env['screen']['newDelta'] != '': return - + announce = currLine if not is_blank: currPrompt = currLine.find('$') @@ -55,18 +71,22 @@ class command(): announce = currLine if currPrompt > 0: remove_digits = str.maketrans('0123456789', ' ') - if prevLine[:currPrompt].translate(remove_digits) == currLine[:currPrompt].translate(remove_digits): - announce = currLine[currPrompt+1:] + if prevLine[:currPrompt].translate( + remove_digits) == currLine[:currPrompt].translate(remove_digits): + announce = currLine[currPrompt + 1:] else: announce = currLine if is_blank: - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True, flush=False) + self.env['runtime']['outputManager'].presentText( + _("blank"), soundIcon='EmptyLine', interrupt=True, flush=False) else: - self.env['runtime']['outputManager'].presentText(announce, interrupt=True, flush=False) - + self.env['runtime']['outputManager'].presentText( + announce, interrupt=True, flush=False) + self.env['commandsIgnore']['onScreenUpdate']['CHAR_DELETE_ECHO'] = True self.env['commandsIgnore']['onScreenUpdate']['CHAR_ECHO'] = True self.env['commandsIgnore']['onScreenUpdate']['INCOMING_IGNORE'] = True + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py b/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py index a10101b7..009882b8 100644 --- a/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py +++ b/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py @@ -4,110 +4,137 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.core import debug + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return 'Detects progress patterns for progress bar monitoring' - + def run(self): # Only run if progress monitoring is enabled try: if 'progressMonitoring' in self.env['commandBuffer'] and self.env['commandBuffer']['progressMonitoring']: - # Check if current line is a prompt - if so, reset progress state + # Check if current line is a prompt - if so, reset progress + # state if self.isCurrentLinePrompt(): self.resetProgressState() - # Only check new incoming text (newDelta), but filter out screen changes + # Only check new incoming text (newDelta), but filter out + # screen changes elif self.env['screen']['newDelta'] and self.isRealProgressUpdate(): self.detectProgress(self.env['screen']['newDelta']) except Exception as e: # Silently ignore errors to avoid disrupting normal operation pass - + def isRealProgressUpdate(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'].isScreenChange(): return False - - # If there was a large cursor movement, it's likely navigation, not progress + + # If there was a large cursor movement, it's likely navigation, not + # progress if self.env['runtime']['cursorManager'].isCursorVerticalMove(): - xMove = abs(self.env['screen']['newCursor']['x'] - self.env['screen']['oldCursor']['x']) - yMove = abs(self.env['screen']['newCursor']['y'] - self.env['screen']['oldCursor']['y']) + xMove = abs( + self.env['screen']['newCursor']['x'] - + self.env['screen']['oldCursor']['x']) + yMove = abs( + self.env['screen']['newCursor']['y'] - + self.env['screen']['oldCursor']['y']) # Large movements suggest navigation, not progress output if yMove > 2 or xMove > 20: return False - - # Check if delta is too large (screen change) vs small incremental updates + + # Check if delta is too large (screen change) vs small incremental + # updates deltaLength = len(self.env['screen']['newDelta']) if deltaLength > 200: # Allow longer progress lines like Claude Code's status return False - - # Check if current line looks like a prompt - progress unlikely during prompts + + # Check if current line looks like a prompt - progress unlikely during + # prompts if self.isCurrentLinePrompt(): return False - + return True - + def resetProgressState(self): """Reset progress state when a prompt is detected, allowing new progress operations to start fresh""" - self.env['runtime']['debug'].writeDebugOut("Resetting progress state due to prompt detection", debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "Resetting progress state due to prompt detection", + debug.debugLevel.INFO) self.env['commandBuffer']['lastProgressValue'] = -1 self.env['commandBuffer']['lastProgressTime'] = 0 - + def detectProgress(self, text): import re import time - + currentTime = time.time() - + # Debug: Print what we're checking - self.env['runtime']['debug'].writeDebugOut("Progress detector checking: '" + text + "'", debug.debugLevel.INFO) - - # Note: Auto-disable on 100% completion removed to respect user settings - + self.env['runtime']['debug'].writeDebugOut( + "Progress detector checking: '" + text + "'", debug.debugLevel.INFO) + + # Note: Auto-disable on 100% completion removed to respect user + # settings + # Pattern 1: Percentage (50%, 25.5%, etc.) - # Filter out common non-progress percentages (weather, system stats, etc.) + # Filter out common non-progress percentages (weather, system stats, + # etc.) percentMatch = re.search(r'(\d+(?:\.\d+)?)\s*%', text) if percentMatch: percentage = float(percentMatch.group(1)) # Only trigger on realistic progress percentages (0-100%) if 0 <= percentage <= 100: # Filter out weather/system stats that contain percentages - if not re.search(r'\b(?:humidity|cpu|memory|disk|usage|temp|weather|forecast)\b', text, re.IGNORECASE): - self.env['runtime']['debug'].writeDebugOut("Found percentage: " + str(percentage), debug.debugLevel.INFO) + if not re.search( + r'\b(?:humidity|cpu|memory|disk|usage|temp|weather|forecast)\b', + text, + re.IGNORECASE): + self.env['runtime']['debug'].writeDebugOut( + "Found percentage: " + str(percentage), debug.debugLevel.INFO) if percentage != self.env['commandBuffer']['lastProgressValue']: - self.env['runtime']['debug'].writeDebugOut("Playing tone for: " + str(percentage), debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "Playing tone for: " + str(percentage), debug.debugLevel.INFO) self.playProgressTone(percentage) self.env['commandBuffer']['lastProgressValue'] = percentage self.env['commandBuffer']['lastProgressTime'] = currentTime return - - # Pattern 1b: Time/token activity (not percentage-based, so use single beep) + + # Pattern 1b: Time/token activity (not percentage-based, so use single + # beep) timeMatch = re.search(r'(\d+)s\s', text) tokenMatch = re.search(r'(\d+)\s+tokens', text) # Pattern 1c: dd command output (bytes copied with transfer rate) ddMatch = re.search(r'\d+\s+bytes.*copied.*\d+\s+s.*[kMGT]?B/s', text) # Pattern 1d: Curl-style transfer data (bytes, speed indicators) - curlMatch = re.search(r'(\d+\s+\d+\s+\d+\s+\d+.*?(?:k|M|G)?.*?--:--:--|Speed)', text) - + curlMatch = re.search( + r'(\d+\s+\d+\s+\d+\s+\d+.*?(?:k|M|G)?.*?--:--:--|Speed)', text) + if timeMatch or tokenMatch or ddMatch or curlMatch: - # For non-percentage progress, use a single activity beep every 2 seconds - if currentTime - self.env['commandBuffer']['lastProgressTime'] >= 2.0: - self.env['runtime']['debug'].writeDebugOut("Playing activity beep for transfer progress", debug.debugLevel.INFO) + # For non-percentage progress, use a single activity beep every 2 + # seconds + if currentTime - \ + self.env['commandBuffer']['lastProgressTime'] >= 2.0: + self.env['runtime']['debug'].writeDebugOut( + "Playing activity beep for transfer progress", debug.debugLevel.INFO) self.playActivityBeep() self.env['commandBuffer']['lastProgressTime'] = currentTime return - + # Pattern 2: Fraction (15/100, 3 of 10, etc.) fractionMatch = re.search(r'(\d+)\s*(?:of|/)\s*(\d+)', text) if fractionMatch: @@ -120,7 +147,7 @@ class command(): self.env['commandBuffer']['lastProgressValue'] = percentage self.env['commandBuffer']['lastProgressTime'] = currentTime return - + # Pattern 3: Progress bars ([#### ], [====> ], etc.) # Improved pattern to avoid matching IRC channels like [#channel] barMatch = re.search(r'\[([#=\-\*]+)([\s\.]*)\]', text) @@ -128,131 +155,157 @@ class command(): filled = len(barMatch.group(1)) unfilled = len(barMatch.group(2)) total = filled + unfilled - # Require at least 2 progress chars total and unfilled portion must be spaces/dots - if total >= 2 and (not barMatch.group(2) or re.match(r'^[\s\.]*$', barMatch.group(2))): + # Require at least 2 progress chars total and unfilled portion must + # be spaces/dots + if total >= 2 and ( + not barMatch.group(2) or re.match( + r'^[\s\.]*$', + barMatch.group(2))): percentage = (filled / total) * 100 if percentage != self.env['commandBuffer']['lastProgressValue']: self.playProgressTone(percentage) self.env['commandBuffer']['lastProgressValue'] = percentage self.env['commandBuffer']['lastProgressTime'] = currentTime return - + # Pattern 4: Generic activity indicators (Loading..., Working..., etc.) - activityPattern = re.search(r'(loading|processing|working|installing|downloading|compiling|building).*\.{2,}', text, re.IGNORECASE) + activityPattern = re.search( + r'(loading|processing|working|installing|downloading|compiling|building).*\.{2,}', + text, + re.IGNORECASE) if activityPattern: # Play a steady beep every 2 seconds for ongoing activity - if currentTime - self.env['commandBuffer']['lastProgressTime'] >= 2.0: + if currentTime - \ + self.env['commandBuffer']['lastProgressTime'] >= 2.0: self.playActivityBeep() self.env['commandBuffer']['lastProgressTime'] = currentTime - + def playProgressTone(self, percentage): - # Map 0-100% to 400-1200Hz frequency range + # Map 0-100% to 400-1200Hz frequency range frequency = 400 + (percentage * 8) frequency = max(400, min(1200, frequency)) # Clamp to safe range - - # Use Sox directly for clean quiet tones like: play -qn synth .1 tri 400 gain -8 + + # Use Sox directly for clean quiet tones like: play -qn synth .1 tri + # 400 gain -8 self.playQuietTone(frequency, 0.1) - + def playActivityBeep(self): # Single tone for generic activity self.playQuietTone(800, 0.08) - + def playQuietTone(self, frequency, duration): """Play a quiet tone using Sox directly""" import subprocess import shlex - - # Build the Sox command: play -qn synth tri gain -8 + + # Build the Sox command: play -qn synth tri gain + # -8 command = f"play -qn synth {duration} tri {frequency} gain -8" - + try: # Only play if sound is enabled - if self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled'): - subprocess.Popen(shlex.split(command), stdin=None, stdout=None, stderr=None, shell=False) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'sound', 'enabled'): + subprocess.Popen( + shlex.split(command), + stdin=None, + stdout=None, + stderr=None, + shell=False) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("Sox tone error: " + str(e), debug.debugLevel.ERROR) - + self.env['runtime']['debug'].writeDebugOut( + "Sox tone error: " + str(e), debug.debugLevel.ERROR) + def isCurrentLinePrompt(self): """Check if the current line looks like a standalone prompt (not command with progress)""" import re - + try: # Get the current screen content if not self.env['screen']['newContentText']: return False - + lines = self.env['screen']['newContentText'].split('\n') if not lines: return False - - # Check the last line (most common) and current cursor line for prompt patterns + + # Check the last line (most common) and current cursor line for + # prompt patterns linesToCheck = [] - + # Add last line (most common for prompts) if lines: linesToCheck.append(lines[-1]) - + # Add current cursor line if different from last line - if (self.env['screen']['newCursor']['y'] < len(lines) and - self.env['screen']['newCursor']['y'] != len(lines) - 1): - linesToCheck.append(lines[self.env['screen']['newCursor']['y']]) - + if (self.env['screen']['newCursor']['y'] < len(lines) and + self.env['screen']['newCursor']['y'] != len(lines) - 1): + linesToCheck.append( + lines[self.env['screen']['newCursor']['y']]) + # Standalone prompt patterns (no commands mixed in) standalonePromptPatterns = [ r'^\s*\$\s*$', # Just $ (with whitespace) - r'^\s*#\s*$', # Just # (with whitespace) + r'^\s*#\s*$', # Just # (with whitespace) r'^\s*>\s*$', # Just > (with whitespace) r'^\[.*\]\s*[\\\$#>]\s*$', # [path]$ without commands r'^[a-zA-Z0-9._-]+[\\\$#>]\s*$', # bash-5.1$ without commands - + # Interactive prompt patterns (these ARE standalone) r'.*\?\s*\[[YyNn]/[YyNn]\]\s*$', # ? [Y/n] or ? [y/N] style r'.*\?\s*\[[Yy]es/[Nn]o\]\s*$', # ? [Yes/No] style - r'.*continue\?\s*\[[YyNn]/[YyNn]\].*$', # "continue? [Y/n]" style + # "continue? [Y/n]" style + r'.*continue\?\s*\[[YyNn]/[YyNn]\].*$', r'^::.*\?\s*\[[YyNn]/[YyNn]\].*$', # pacman style prompts - + # Authentication prompts (these ARE standalone) r'^\[[Ss]udo\]\s*[Pp]assword\s*for\s+.*:\s*$', # [sudo] password r'^[Pp]assword\s*:\s*$', # Password: r'.*[Pp]assword\s*:\s*$', # general password prompts - + # Continuation prompts (these ARE standalone) r'^[Pp]ress\s+any\s+key\s+to\s+continue.*$', # Press any key r'^[Aa]re\s+you\s+sure\?\s*.*$', # Are you sure? ] - + for line in linesToCheck: line = line.strip() if not line: continue - + # Check if this line contains both a prompt AND other content (like commands) # If so, don't treat it as a standalone prompt - hasPromptMarker = bool(re.search(r'.*@.*[\\\$#>]', line) or re.search(r'^\[.*\]\s*[\\\$#>]', line)) + hasPromptMarker = bool( + re.search( + r'.*@.*[\\\$#>]', + line) or re.search( + r'^\[.*\]\s*[\\\$#>]', + line)) if hasPromptMarker: - # If line has prompt marker but also has significant content after it, + # If line has prompt marker but also has significant content after it, # it's a command line, not a standalone prompt promptEnd = max( - line.rfind('$'), - line.rfind('#'), + line.rfind('$'), + line.rfind('#'), line.rfind('>'), line.rfind('\\') ) - if promptEnd >= 0 and promptEnd < len(line) - 5: # More than just whitespace after prompt + if promptEnd >= 0 and promptEnd < len( + line) - 5: # More than just whitespace after prompt continue # This is a command line, not a standalone prompt - + for pattern in standalonePromptPatterns: try: if re.search(pattern, line): return True except re.error: continue - + return False - + except Exception: # If anything fails, assume it's not a prompt to be safe return False - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/onScreenUpdate/66000-prompt_detector.py b/src/fenrirscreenreader/commands/onScreenUpdate/66000-prompt_detector.py index 28c981f9..85457335 100644 --- a/src/fenrirscreenreader/commands/onScreenUpdate/66000-prompt_detector.py +++ b/src/fenrirscreenreader/commands/onScreenUpdate/66000-prompt_detector.py @@ -4,21 +4,24 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + from fenrirscreenreader.core import debug + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return 'Detects shell prompts for silence until prompt feature' - + def run(self): # Only run if silence until prompt is active try: @@ -26,55 +29,69 @@ class command(): # Check the current line for prompt patterns if self.env['screen']['newContentText']: lines = self.env['screen']['newContentText'].split('\n') - if lines and self.env['screen']['newCursor']['y'] < len(lines): - currentLine = lines[self.env['screen']['newCursor']['y']] + if lines and self.env['screen']['newCursor']['y'] < len( + lines): + currentLine = lines[self.env['screen'] + ['newCursor']['y']] self.checkForPrompt(currentLine) except Exception as e: # Silently ignore errors to avoid disrupting normal operation - self.env['runtime']['debug'].writeDebugOut('prompt_detector run: Error in prompt detection: ' + str(e), debug.debugLevel.ERROR) - + self.env['runtime']['debug'].writeDebugOut( + 'prompt_detector run: Error in prompt detection: ' + str(e), + debug.debugLevel.ERROR) + def checkForPrompt(self, text): """Check if the current line contains a shell prompt pattern""" import re - + # Debug: Print what we're checking - self.env['runtime']['debug'].writeDebugOut("Prompt detector checking: '" + text + "'", debug.debugLevel.INFO) - - # First check for exact matches from settings (with backward compatibility) + self.env['runtime']['debug'].writeDebugOut( + "Prompt detector checking: '" + text + "'", debug.debugLevel.INFO) + + # First check for exact matches from settings (with backward + # compatibility) try: - exactMatches = self.env['runtime']['settingsManager'].getSetting('prompt', 'exactMatches') + exactMatches = self.env['runtime']['settingsManager'].getSetting( + 'prompt', 'exactMatches') if exactMatches: - exactList = [match.strip() for match in exactMatches.split(',') if match.strip()] + exactList = [match.strip() + for match in exactMatches.split(',') if match.strip()] for exactMatch in exactList: if text.strip() == exactMatch: - self.env['runtime']['debug'].writeDebugOut("Found exact prompt match: " + exactMatch, debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "Found exact prompt match: " + exactMatch, debug.debugLevel.INFO) self._restoreSpeech() return True except Exception as e: - # Prompt section doesn't exist in settings, skip custom exact matches + # Prompt section doesn't exist in settings, skip custom exact + # matches pass - + # Get custom patterns from settings (with backward compatibility) promptPatterns = [] try: - customPatterns = self.env['runtime']['settingsManager'].getSetting('prompt', 'customPatterns') + customPatterns = self.env['runtime']['settingsManager'].getSetting( + 'prompt', 'customPatterns') # Add custom patterns from settings if they exist if customPatterns: - customList = [pattern.strip() for pattern in customPatterns.split(',') if pattern.strip()] + customList = [ + pattern.strip() for pattern in customPatterns.split(',') if pattern.strip()] promptPatterns.extend(customList) except Exception as e: # Prompt section doesn't exist in settings, skip custom patterns pass - + # Add default shell prompt patterns promptPatterns.extend([ r'^\s*\$\s*$', # Just $ (with whitespace) - r'^\s*#\s*$', # Just # (with whitespace) + r'^\s*#\s*$', # Just # (with whitespace) r'^\s*>\s*$', # Just > (with whitespace) - r'.*@.*[\\\$#>]\s*$', # Contains @ and ends with prompt char (user@host style) + r'.*@.*[\\\$#>]\s*$', + # Contains @ and ends with prompt char (user@host style) r'^\[.*\]\s*[\\\$#>]\s*$', # [anything]$ style prompts - r'^[a-zA-Z0-9._-]+[\\\$#>]\s*$', # Simple shell names like bash-5.1$ - + # Simple shell names like bash-5.1$ + r'^[a-zA-Z0-9._-]+[\\\$#>]\s*$', + # Interactive prompt patterns # Package manager confirmation prompts r'.*\?\s*\[[YyNn]/[YyNn]\]\s*$', # ? [Y/n] or ? [y/N] style @@ -83,47 +100,57 @@ class command(): r'.*\?\s*\([Yy]es/[Nn]o\)\s*$', # ? (Yes/No) style r'.*continue\?\s*\[[YyNn]/[YyNn]\].*$', # "continue? [Y/n]" style r'.*ok\s*\[[YyNn]/[YyNn]\].*$', # "Is this ok [y/N]:" style - r'^::.*\?\s*\[[YyNn]/[YyNn]\].*$', # pacman ":: Proceed? [Y/n]" style - + # pacman ":: Proceed? [Y/n]" style + r'^::.*\?\s*\[[YyNn]/[YyNn]\].*$', + # Authentication prompts - r'^\[[Ss]udo\]\s*[Pp]assword\s*for\s+.*:\s*$', # [sudo] password for user: + # [sudo] password for user: + r'^\[[Ss]udo\]\s*[Pp]assword\s*for\s+.*:\s*$', r'^[Pp]assword\s*:\s*$', # Password: r'.*[Pp]assword\s*:\s*$', # general password prompts r".*'s\s*[Pp]assword\s*:\s*$", # user's password: r'^[Ee]nter\s+[Pp]assphrase.*:\s*$', # Enter passphrase: - r'^[Pp]lease\s+enter\s+[Pp]assphrase.*:\s*$', # Please enter passphrase: - + # Please enter passphrase: + r'^[Pp]lease\s+enter\s+[Pp]assphrase.*:\s*$', + # General confirmation and continuation prompts - r'^[Pp]ress\s+any\s+key\s+to\s+continue.*$', # Press any key to continue + # Press any key to continue + r'^[Pp]ress\s+any\s+key\s+to\s+continue.*$', r'^[Aa]re\s+you\s+sure\?\s*.*$', # Are you sure? r'^[Pp]lease\s+confirm.*$', # Please confirm r'.*confirm.*\([YyNn]/[YyNn]\).*$', # confirm (y/n) r'.*\([Yy]/[Nn]\)\s*$', # ends with (Y/n) or (y/N) ]) - + for pattern in promptPatterns: try: if re.search(pattern, text.strip()): - self.env['runtime']['debug'].writeDebugOut("Found prompt pattern: " + pattern, debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "Found prompt pattern: " + pattern, debug.debugLevel.INFO) self._restoreSpeech() return True except re.error as e: # Invalid regex pattern, skip it and log the error - self.env['runtime']['debug'].writeDebugOut("Invalid prompt pattern: " + pattern + " Error: " + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "Invalid prompt pattern: " + pattern + " Error: " + str(e), + debug.debugLevel.ERROR) continue - + return False - + def _restoreSpeech(self): """Helper method to restore speech when prompt is detected""" # Disable silence mode self.env['commandBuffer']['silenceUntilPrompt'] = False - # Also disable the keypress-based speech restoration since we're enabling it now + # Also disable the keypress-based speech restoration since we're + # enabling it now if 'enableSpeechOnKeypress' in self.env['commandBuffer']: self.env['commandBuffer']['enableSpeechOnKeypress'] = False # Re-enable speech - self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', 'True') - self.env['runtime']['outputManager'].presentText(_("Speech restored"), soundIcon='SpeechOn', interrupt=True) - + self.env['runtime']['settingsManager'].setSetting( + 'speech', 'enabled', 'True') + self.env['runtime']['outputManager'].presentText( + _("Speech restored"), soundIcon='SpeechOn', interrupt=True) + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/onScreenUpdate/70000-incoming.py b/src/fenrirscreenreader/commands/onScreenUpdate/70000-incoming.py index 40ad22e3..2ec49dab 100644 --- a/src/fenrirscreenreader/commands/onScreenUpdate/70000-incoming.py +++ b/src/fenrirscreenreader/commands/onScreenUpdate/70000-incoming.py @@ -5,34 +5,47 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): return 'No Description found' def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'autoReadIncoming'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'speech', 'autoReadIncoming'): return # is there something to read? if not self.env['runtime']['screenManager'].isDelta(ignoreSpace=True): return # this must be a keyecho or something - #if len(self.env['screen']['newDelta'].strip(' \n\t')) <= 1: - xMove = abs(self.env['screen']['newCursor']['x'] - self.env['screen']['oldCursor']['x']) - yMove = abs(self.env['screen']['newCursor']['y'] - self.env['screen']['oldCursor']['y']) - + # if len(self.env['screen']['newDelta'].strip(' \n\t')) <= 1: + xMove = abs( + self.env['screen']['newCursor']['x'] - + self.env['screen']['oldCursor']['x']) + yMove = abs( + self.env['screen']['newCursor']['y'] - + self.env['screen']['oldCursor']['y']) + if (xMove >= 1) and xMove == len(self.env['screen']['newDelta']): - # if len(self.env['screen']['newDelta'].strip(' \n\t0123456789')) <= 2: - if not '\n' in self.env['screen']['newDelta']: + # if len(self.env['screen']['newDelta'].strip(' \n\t0123456789')) + # <= 2: + if '\n' not in self.env['screen']['newDelta']: return - #print(xMove, yMove, len(self.env['screen']['newDelta']), len(self.env['screen']['newNegativeDelta'])) - self.env['runtime']['outputManager'].presentText(self.env['screen']['newDelta'], interrupt=False, flush=False) + # print(xMove, yMove, len(self.env['screen']['newDelta']), len(self.env['screen']['newNegativeDelta'])) + self.env['runtime']['outputManager'].presentText( + self.env['screen']['newDelta'], interrupt=False, flush=False) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/onScreenUpdate/75000-incoming_promote.py b/src/fenrirscreenreader/commands/onScreenUpdate/75000-incoming_promote.py index 23f2864b..70cf5624 100644 --- a/src/fenrirscreenreader/commands/onScreenUpdate/75000-incoming_promote.py +++ b/src/fenrirscreenreader/commands/onScreenUpdate/75000-incoming_promote.py @@ -1,4 +1,7 @@ #!/usr/bin/env python3 + +from fenrirscreenreader.core.i18n import _ + import time # -*- coding: utf-8 -*- @@ -9,26 +12,41 @@ import time class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): return 'No Description found' + def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('promote', 'enabled'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'promote', 'enabled'): return - if self.env['runtime']['settingsManager'].getSetting('promote', 'list').strip(" \t\n") == '': + if self.env['runtime']['settingsManager'].getSetting( + 'promote', 'list').strip(" \t\n") == '': return - if int(time.time() - self.env['input']['lastInputTime']) < self.env['runtime']['settingsManager'].getSettingAsInt('promote', 'inactiveTimeoutSec'): + if int( + time.time() - + self.env['input']['lastInputTime']) < self.env['runtime']['settingsManager'].getSettingAsInt( + 'promote', + 'inactiveTimeoutSec'): return - if len(self.env['runtime']['settingsManager'].getSetting('promote', 'list')) == 0: + if len( + self.env['runtime']['settingsManager'].getSetting( + 'promote', + 'list')) == 0: return - for promote in self.env['runtime']['settingsManager'].getSetting('promote', 'list').split(','): - if promote in self.env['screen']['newDelta']: - self.env['runtime']['outputManager'].playSoundIcon('PromotedText') + for promote in self.env['runtime']['settingsManager'].getSetting( + 'promote', 'list').split(','): + if promote in self.env['screen']['newDelta']: + self.env['runtime']['outputManager'].playSoundIcon( + 'PromotedText') self.env['input']['lastInputTime'] = time.time() return + def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onScreenUpdate/80000-barrier_detect.py b/src/fenrirscreenreader/commands/onScreenUpdate/80000-barrier_detect.py index 3b516f8f..0a0b2f8d 100644 --- a/src/fenrirscreenreader/commands/onScreenUpdate/80000-barrier_detect.py +++ b/src/fenrirscreenreader/commands/onScreenUpdate/80000-barrier_detect.py @@ -5,21 +5,32 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): return 'No Description found' + def run(self): - if not self.env['runtime']['settingsManager'].getSettingAsBool('barrier','enabled'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'barrier', 'enabled'): return if not self.env['runtime']['screenManager'].isDelta(ignoreSpace=True): return - self.env['runtime']['barrierManager'].handleLineBarrier(self.env['screen']['newContentText'].split('\n'), self.env['screen']['newCursor']['x'],self.env['screen']['newCursor']['y']) + self.env['runtime']['barrierManager'].handleLineBarrier( + self.env['screen']['newContentText'].split('\n'), + self.env['screen']['newCursor']['x'], + self.env['screen']['newCursor']['y']) + def setCallback(self, callback): pass - diff --git a/src/fenrirscreenreader/commands/onSwitchApplicationProfile/__init__.py b/src/fenrirscreenreader/commands/onSwitchApplicationProfile/__init__.py index 8b137891..e69de29b 100644 --- a/src/fenrirscreenreader/commands/onSwitchApplicationProfile/__init__.py +++ b/src/fenrirscreenreader/commands/onSwitchApplicationProfile/__init__.py @@ -1 +0,0 @@ - diff --git a/src/fenrirscreenreader/commands/onSwitchApplicationProfile/default.py b/src/fenrirscreenreader/commands/onSwitchApplicationProfile/default.py index 764a2292..5305aade 100644 --- a/src/fenrirscreenreader/commands/onSwitchApplicationProfile/default.py +++ b/src/fenrirscreenreader/commands/onSwitchApplicationProfile/default.py @@ -5,28 +5,35 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def load(self): return print('--------------') - print('default') - print('load new',self.env['screen']['newApplication']) + print('default') + print('load new', self.env['screen']['newApplication']) print('--------------') - + def unload(self): return print('--------------') - print('default') - print('unload old',self.env['screen']['oldApplication']) + print('default') + print('unload old', self.env['screen']['oldApplication']) print('--------------') - + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/quickMenu/current_quick_menu_entry.py b/src/fenrirscreenreader/commands/quickMenu/current_quick_menu_entry.py index a89ce3ee..f0232482 100644 --- a/src/fenrirscreenreader/commands/quickMenu/current_quick_menu_entry.py +++ b/src/fenrirscreenreader/commands/quickMenu/current_quick_menu_entry.py @@ -5,21 +5,30 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get current quick menu entry') + def run(self): menu = '' value = '' menu = self.env['runtime']['quickMenuManager'].getCurrentEntry() if menu != '': value = self.env['runtime']['quickMenuManager'].getCurrentValue() - self.env['runtime']['outputManager'].presentText(menu + ' ' + value, interrupt=True) + self.env['runtime']['outputManager'].presentText( + menu + ' ' + value, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/quickMenu/current_quick_menu_value.py b/src/fenrirscreenreader/commands/quickMenu/current_quick_menu_value.py index 6522e080..23a3a75c 100644 --- a/src/fenrirscreenreader/commands/quickMenu/current_quick_menu_value.py +++ b/src/fenrirscreenreader/commands/quickMenu/current_quick_menu_value.py @@ -5,17 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get current quick menu value') + def run(self): value = self.env['runtime']['quickMenuManager'].getCurrentValue() self.env['runtime']['outputManager'].presentText(value, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/quickMenu/next_quick_menu_entry.py b/src/fenrirscreenreader/commands/quickMenu/next_quick_menu_entry.py index 1d2a5fb1..13b52c43 100644 --- a/src/fenrirscreenreader/commands/quickMenu/next_quick_menu_entry.py +++ b/src/fenrirscreenreader/commands/quickMenu/next_quick_menu_entry.py @@ -5,15 +5,22 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get next quick menu entry') + def run(self): menu = '' value = '' @@ -21,8 +28,11 @@ class command(): menu = self.env['runtime']['quickMenuManager'].getCurrentEntry() if menu != '': value = self.env['runtime']['quickMenuManager'].getCurrentValue() - self.env['runtime']['outputManager'].presentText(menu + ' ' + value, interrupt=True) + self.env['runtime']['outputManager'].presentText( + menu + ' ' + value, interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_('Quick menu not available'), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('Quick menu not available'), interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/quickMenu/next_quick_menu_value.py b/src/fenrirscreenreader/commands/quickMenu/next_quick_menu_value.py index 78a0f9ad..d52adad9 100644 --- a/src/fenrirscreenreader/commands/quickMenu/next_quick_menu_value.py +++ b/src/fenrirscreenreader/commands/quickMenu/next_quick_menu_value.py @@ -5,18 +5,27 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get next quick menu value') + def run(self): if self.env['runtime']['quickMenuManager'].nextValue(): value = self.env['runtime']['quickMenuManager'].getCurrentValue() - self.env['runtime']['outputManager'].presentText(value, interrupt=True) + self.env['runtime']['outputManager'].presentText( + value, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/quickMenu/prev_quick_menu_entry.py b/src/fenrirscreenreader/commands/quickMenu/prev_quick_menu_entry.py index 87aef5df..b6910ea2 100644 --- a/src/fenrirscreenreader/commands/quickMenu/prev_quick_menu_entry.py +++ b/src/fenrirscreenreader/commands/quickMenu/prev_quick_menu_entry.py @@ -5,15 +5,22 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get previous quick menu entry') + def run(self): menu = '' value = '' @@ -21,8 +28,11 @@ class command(): menu = self.env['runtime']['quickMenuManager'].getCurrentEntry() if menu != '': value = self.env['runtime']['quickMenuManager'].getCurrentValue() - self.env['runtime']['outputManager'].presentText(menu + ' ' + value, interrupt=True) + self.env['runtime']['outputManager'].presentText( + menu + ' ' + value, interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_('Quick menu not available'), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('Quick menu not available'), interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/quickMenu/prev_quick_menu_value.py b/src/fenrirscreenreader/commands/quickMenu/prev_quick_menu_value.py index bfa7e8cb..3ba6840b 100644 --- a/src/fenrirscreenreader/commands/quickMenu/prev_quick_menu_value.py +++ b/src/fenrirscreenreader/commands/quickMenu/prev_quick_menu_value.py @@ -5,18 +5,27 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get previous quick menu value') + def run(self): if self.env['runtime']['quickMenuManager'].prevValue(): value = self.env['runtime']['quickMenuManager'].getCurrentValue() - self.env['runtime']['outputManager'].presentText(value, interrupt=True) + self.env['runtime']['outputManager'].presentText( + value, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/switchTrigger_template.py b/src/fenrirscreenreader/commands/switchTrigger_template.py index f8c837ff..72ebeccc 100644 --- a/src/fenrirscreenreader/commands/switchTrigger_template.py +++ b/src/fenrirscreenreader/commands/switchTrigger_template.py @@ -5,18 +5,27 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def unload(self): pass + def load(self): pass + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/curr_vmenu_entry.py b/src/fenrirscreenreader/commands/vmenu-navigation/curr_vmenu_entry.py index 41787ef8..c5ea1b43 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/curr_vmenu_entry.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/curr_vmenu_entry.py @@ -5,17 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get current v menu entry') + def run(self): text = self.env['runtime']['vmenuManager'].getCurrentEntry() self.env['runtime']['outputManager'].presentText(text, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/dec_level_vmenu.py b/src/fenrirscreenreader/commands/vmenu-navigation/dec_level_vmenu.py index 56fcd4ff..1b79b5c2 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/dec_level_vmenu.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/dec_level_vmenu.py @@ -5,18 +5,26 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('leave v menu submenu') + def run(self): self.env['runtime']['vmenuManager'].decLevel() text = self.env['runtime']['vmenuManager'].getCurrentEntry() self.env['runtime']['outputManager'].presentText(text, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/exec_vmenu_entry.py b/src/fenrirscreenreader/commands/vmenu-navigation/exec_vmenu_entry.py index 6ec99f52..e7ec0608 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/exec_vmenu_entry.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/exec_vmenu_entry.py @@ -5,16 +5,24 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('execute v menu entry') + def run(self): self.env['runtime']['vmenuManager'].executeMenu() + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/inc_level_vmenu.py b/src/fenrirscreenreader/commands/vmenu-navigation/inc_level_vmenu.py index f902dd00..637224b2 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/inc_level_vmenu.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/inc_level_vmenu.py @@ -5,18 +5,26 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('enter v menu submenu') + def run(self): self.env['runtime']['vmenuManager'].incLevel() text = self.env['runtime']['vmenuManager'].getCurrentEntry() self.env['runtime']['outputManager'].presentText(text, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/next_vmenu_entry.py b/src/fenrirscreenreader/commands/vmenu-navigation/next_vmenu_entry.py index 8aa5b011..d15e1b2b 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/next_vmenu_entry.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/next_vmenu_entry.py @@ -5,18 +5,26 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get next v menu entry') + def run(self): self.env['runtime']['vmenuManager'].nextIndex() text = self.env['runtime']['vmenuManager'].getCurrentEntry() self.env['runtime']['outputManager'].presentText(text, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/page_down_vmenu.py b/src/fenrirscreenreader/commands/vmenu-navigation/page_down_vmenu.py index 2e6e1550..b03d5ca4 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/page_down_vmenu.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/page_down_vmenu.py @@ -5,18 +5,26 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('jump down 10% in v menu') + def run(self): self.env['runtime']['vmenuManager'].pageDown() text = self.env['runtime']['vmenuManager'].getCurrentEntry() self.env['runtime']['outputManager'].presentText(text, interrupt=True) + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/page_up_vmenu.py b/src/fenrirscreenreader/commands/vmenu-navigation/page_up_vmenu.py index c1c78ffa..c93cd29d 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/page_up_vmenu.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/page_up_vmenu.py @@ -5,18 +5,26 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('jump up 10% in v menu') + def run(self): self.env['runtime']['vmenuManager'].pageUp() text = self.env['runtime']['vmenuManager'].getCurrentEntry() self.env['runtime']['outputManager'].presentText(text, interrupt=True) + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/prev_vmenu_entry.py b/src/fenrirscreenreader/commands/vmenu-navigation/prev_vmenu_entry.py index 32ee67c1..9422d383 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/prev_vmenu_entry.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/prev_vmenu_entry.py @@ -5,18 +5,26 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): return _('get prev v menu entry') + def run(self): self.env['runtime']['vmenuManager'].prevIndex() text = self.env['runtime']['vmenuManager'].getCurrentEntry() self.env['runtime']['outputManager'].presentText(text, interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_a.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_a.py index 7ef8987e..620bcbf2 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_a.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_a.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('a') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_b.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_b.py index 78575c33..10c02be3 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_b.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_b.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('b') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_c.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_c.py index 3b2733ac..62df6298 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_c.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_c.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('c') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_d.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_d.py index 08e46880..964fb030 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_d.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_d.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('d') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_e.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_e.py index 6591af03..c5abdfe3 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_e.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_e.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('e') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_f.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_f.py index 2ec56cad..01a0d974 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_f.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_f.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('f') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_g.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_g.py index 85efbb07..817134a6 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_g.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_g.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('g') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_h.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_h.py index 78751213..0ed9a889 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_h.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_h.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('h') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_i.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_i.py index 050ae6e1..6eca2d35 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_i.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_i.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('i') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_j.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_j.py index a6389c10..58f313e3 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_j.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_j.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('j') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_k.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_k.py index 121849d5..a193b7ec 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_k.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_k.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('k') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_l.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_l.py index a7c5e661..b7fb4e55 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_l.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_l.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('l') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_m.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_m.py index 2c11eb16..3f7d9c84 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_m.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_m.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('m') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_n.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_n.py index 06c6c944..8aacd03e 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_n.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_n.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('n') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_o.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_o.py index 5cf8ef4a..8006d0e0 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_o.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_o.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('o') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_p.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_p.py index b32fd29f..da0c3aee 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_p.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_p.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('p') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_q.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_q.py index 56844daa..530c1b5d 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_q.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_q.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('q') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_r.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_r.py index 61e9536b..22342f92 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_r.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_r.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('r') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_s.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_s.py index c0c9389b..c6ba2c40 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_s.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_s.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('s') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_t.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_t.py index 318d4275..c182fecf 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_t.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_t.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('t') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_u.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_u.py index 66b2eb4a..a844030a 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_u.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_u.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('u') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_v.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_v.py index 3ce4be06..592bcee2 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_v.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_v.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('v') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_w.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_w.py index 0c4639f3..6894b880 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_w.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_w.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('w') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_x.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_x.py index 07b476ca..8f552f05 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_x.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_x.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('x') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_y.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_y.py index 81a2d4cf..cccb41c8 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_y.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_y.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('y') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/search_z.py b/src/fenrirscreenreader/commands/vmenu-navigation/search_z.py index bd1ed83f..46ba367c 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/search_z.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/search_z.py @@ -4,13 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import importlib.util import os -_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py")) +_spec = importlib.util.spec_from_file_location( + "vmenu_search_base", os.path.join( + os.path.dirname(__file__), "vmenu_search_base.py")) _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) VMenuSearchCommand = _module.VMenuSearchCommand + class command(VMenuSearchCommand): def __init__(self): super().__init__('z') diff --git a/src/fenrirscreenreader/commands/vmenu-navigation/vmenu_search_base.py b/src/fenrirscreenreader/commands/vmenu-navigation/vmenu_search_base.py index e3e8fafc..06d884de 100644 --- a/src/fenrirscreenreader/commands/vmenu-navigation/vmenu_search_base.py +++ b/src/fenrirscreenreader/commands/vmenu-navigation/vmenu_search_base.py @@ -4,26 +4,33 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class VMenuSearchCommand(): """Base class for VMenu search commands""" + def __init__(self, search_char): self.search_char = search_char.lower() - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return _('search for an menu entry') - + def run(self): - text = self.env['runtime']['vmenuManager'].searchEntry(self.search_char) + text = self.env['runtime']['vmenuManager'].searchEntry( + self.search_char) if text != '': - self.env['runtime']['outputManager'].presentText(text, interrupt=True) + self.env['runtime']['outputManager'].presentText( + text, interrupt=True) else: - self.env['runtime']['outputManager'].presentText(_('not found'), soundIcon='ErrorScreen', interrupt=True) - + self.env['runtime']['outputManager'].presentText( + _('not found'), soundIcon='ErrorScreen', interrupt=True) + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/__init__.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/__init__.py index 1c602751..a107eb8b 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/__init__.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/__init__.py @@ -1 +1 @@ -# Fenrir Configuration VMenu Profile \ No newline at end of file +# Fenrir Configuration VMenu Profile diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/config_base.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/config_base.py index 02f9d2bb..b9c49128 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/config_base.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/config_base.py @@ -4,35 +4,39 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import os import shutil import tempfile import configparser from datetime import datetime + class ConfigCommand(): """Base class for configuration management commands""" - + def __init__(self): self.env = None self.settingsFile = None self.config = None - + def initialize(self, environment): self.env = environment self.settingsFile = self.env['runtime']['settingsManager'].settingsFile self.config = self.env['runtime']['settingsManager'].settings - + def shutdown(self): pass - + def setCallback(self, callback): pass - + def presentText(self, text, interrupt=True, flush=True): """Present text to user with proper speech handling""" - self.env['runtime']['outputManager'].presentText(text, interrupt=interrupt, flush=flush) - + self.env['runtime']['outputManager'].presentText( + text, interrupt=interrupt, flush=flush) + def playSound(self, soundName): """Play system sound""" soundIcon = '' @@ -42,10 +46,11 @@ class ConfigCommand(): soundIcon = 'ErrorSound' elif soundName == 'Cancel': soundIcon = 'Cancel' - + if soundIcon: - self.env['runtime']['outputManager'].presentText('', soundIcon=soundIcon, interrupt=False) - + self.env['runtime']['outputManager'].presentText( + '', soundIcon=soundIcon, interrupt=False) + def backupConfig(self, announce=True): """Create backup of current configuration file""" try: @@ -54,24 +59,24 @@ class ConfigCommand(): if announce: self.presentText(message) return False, message - + # Create backup with timestamp timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") backup_path = f"{self.settingsFile}.backup_{timestamp}" - + shutil.copy2(self.settingsFile, backup_path) - + message = f"Configuration backed up to {backup_path}" if announce: self.presentText("Configuration backup created successfully") return True, message - + except Exception as e: message = f"Failed to backup configuration: {str(e)}" if announce: self.presentText(message) return False, message - + def reloadConfig(self): """Reload configuration from file""" try: @@ -79,56 +84,63 @@ class ConfigCommand(): self.env['runtime']['settingsManager'].loadSettings() self.config = self.env['runtime']['settingsManager'].settings return True - + except Exception as e: self.presentText(f"Failed to reload configuration: {str(e)}") return False - + def findDefaultConfig(self): """Find default configuration file path""" # Look for default config in multiple locations default_paths = [ '/etc/fenrir/settings/settings.conf.default', '/usr/share/fenrir/settings/settings.conf', - os.path.join(os.path.dirname(self.settingsFile), 'settings.conf.default'), - os.path.join(os.path.dirname(os.path.dirname(self.settingsFile)), 'settings', 'settings.conf.default') - ] - + os.path.join( + os.path.dirname( + self.settingsFile), + 'settings.conf.default'), + os.path.join( + os.path.dirname( + os.path.dirname( + self.settingsFile)), + 'settings', + 'settings.conf.default')] + for path in default_paths: if os.path.exists(path): return path - + return None - + def createBasicDefaults(self): """Create basic default configuration manually""" try: # Create a new config with basic defaults self.config = configparser.ConfigParser() - + # Add basic sections and settings self.config.add_section('speech') self.config.set('speech', 'driver', 'speechdDriver') self.config.set('speech', 'rate', '0.75') self.config.set('speech', 'pitch', '0.5') self.config.set('speech', 'volume', '1.0') - + self.config.add_section('sound') self.config.set('sound', 'driver', 'genericDriver') self.config.set('sound', 'volume', '0.7') - + self.config.add_section('keyboard') self.config.set('keyboard', 'driver', 'evdevDriver') self.config.set('keyboard', 'keyboardLayout', 'desktop') - + self.config.add_section('screen') self.config.set('screen', 'driver', 'vcsaDriver') - + self.config.add_section('general') self.config.set('general', 'debugMode', 'Off') - + return True - + except Exception as e: self.presentText(f"Failed to create basic defaults: {str(e)}") - return False \ No newline at end of file + return False diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/general/set_punctuation_level.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/general/set_punctuation_level.py index 1f03fdee..d4fd5259 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/general/set_punctuation_level.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/general/set_punctuation_level.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,16 +12,17 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Set punctuation verbosity level" - + def run(self): currentLevel = self.getSetting('general', 'punctuationLevel', 'some') - + # Present current level levelDescriptions = { 'none': 'None - no punctuation spoken', @@ -27,10 +30,10 @@ class command(ConfigCommand): 'most': 'Most - detailed punctuation', 'all': 'All - every punctuation mark' } - + currentDescription = levelDescriptions.get(currentLevel, 'Unknown') self.presentText(f"Current punctuation level: {currentDescription}") - + # Cycle through the four levels levels = ['none', 'some', 'most', 'all'] try: @@ -39,13 +42,13 @@ class command(ConfigCommand): newLevel = levels[nextIndex] except ValueError: newLevel = 'some' # Default to some - + success = self.setSetting('general', 'punctuationLevel', newLevel) - + if success: newDescription = levelDescriptions[newLevel] self.presentText(f"Punctuation level set to: {newDescription}") self.playSound('Accept') else: self.presentText("Failed to change punctuation level") - self.playSound('Error') \ No newline at end of file + self.playSound('Error') diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/general/toggle_debug.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/general/toggle_debug.py index 8a5e077a..85eb4d39 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/general/toggle_debug.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/general/toggle_debug.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,16 +12,17 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Toggle debug mode" - + def run(self): currentLevel = self.getSetting('general', 'debugLevel', '0') - + # Present current debug level if currentLevel == '0': self.presentText("Current debug mode: disabled") @@ -29,18 +32,19 @@ class command(ConfigCommand): self.presentText(f"Current debug level: {currentLevel}") newLevel = '0' stateText = "disabled" - + success = self.setSetting('general', 'debugLevel', newLevel) - + if success: self.presentText(f"Debug mode {stateText}") if newLevel != '0': debugMode = self.getSetting('general', 'debugMode', 'File') if debugMode == 'File': - self.presentText("Debug output will be written to log file") + self.presentText( + "Debug output will be written to log file") else: self.presentText("Debug output will be printed to console") self.playSound('Accept') else: self.presentText("Failed to change debug mode") - self.playSound('Error') \ No newline at end of file + self.playSound('Error') diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/select_layout.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/select_layout.py index 49d3f7f4..6dc757f7 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/select_layout.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/select_layout.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,27 +12,33 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Select keyboard layout (desktop or laptop)" - + def run(self): - currentLayout = self.getSetting('keyboard', 'keyboardLayout', 'desktop') - + currentLayout = self.getSetting( + 'keyboard', 'keyboardLayout', 'desktop') + # Present current layout self.presentText(f"Current keyboard layout: {currentLayout}") - + # Find available keyboard layouts keyboardPath = '/etc/fenrirscreenreader/keyboard' if not os.path.isdir(keyboardPath): # Development path - keyboardPath = os.path.join(os.path.dirname(self.settingsFile), '..', 'keyboard') - + keyboardPath = os.path.join( + os.path.dirname( + self.settingsFile), + '..', + 'keyboard') + availableLayouts = self.getAvailableLayouts(keyboardPath) - + if len(availableLayouts) > 1: # Cycle through available layouts try: @@ -40,12 +48,13 @@ class command(ConfigCommand): except ValueError: # Current layout not found, use first available newLayout = availableLayouts[0] - + success = self.setSetting('keyboard', 'keyboardLayout', newLayout) - + if success: self.presentText(f"Keyboard layout changed to: {newLayout}") - self.presentText("Please restart Fenrir for this change to take effect.") + self.presentText( + "Please restart Fenrir for this change to take effect.") self.playSound('Accept') else: self.presentText("Failed to change keyboard layout") @@ -53,11 +62,11 @@ class command(ConfigCommand): else: self.presentText("Only default keyboard layout is available") self.playSound('Cancel') - + def getAvailableLayouts(self, keyboardPath): """Find available keyboard layout files""" layouts = [] - + if os.path.isdir(keyboardPath): try: for file in os.listdir(keyboardPath): @@ -66,9 +75,9 @@ class command(ConfigCommand): layouts.append(layoutName) except Exception: pass - + # Ensure we have at least the default layouts if not layouts: layouts = ['desktop', 'laptop'] - - return sorted(layouts) \ No newline at end of file + + return sorted(layouts) diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/set_char_echo.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/set_char_echo.py index 523df8b5..c8e07314 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/set_char_echo.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/set_char_echo.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,26 +12,27 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Set character echo mode" - + def run(self): currentMode = self.getSetting('keyboard', 'charEchoMode', '1') - + # Present current mode modeDescriptions = { '0': 'None - no character echo', '1': 'Always - echo all typed characters', '2': 'Caps Lock - echo only when caps lock is on' } - + currentDescription = modeDescriptions.get(currentMode, 'Unknown') self.presentText(f"Current character echo mode: {currentDescription}") - + # Cycle through the three modes modes = ['0', '1', '2'] try: @@ -38,13 +41,13 @@ class command(ConfigCommand): newMode = modes[nextIndex] except ValueError: newMode = '1' # Default to always - + success = self.setSetting('keyboard', 'charEchoMode', newMode) - + if success: newDescription = modeDescriptions[newMode] self.presentText(f"Character echo mode set to: {newDescription}") self.playSound('Accept') else: self.presentText("Failed to change character echo mode") - self.playSound('Error') \ No newline at end of file + self.playSound('Error') diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/toggle_grab_devices.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/toggle_grab_devices.py index fc10dd12..43b8564d 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/toggle_grab_devices.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/toggle_grab_devices.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,26 +12,30 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Toggle exclusive keyboard access" - + def run(self): currentState = self.getBooleanSetting('keyboard', 'grabDevices', True) newState = self.toggleBooleanSetting('keyboard', 'grabDevices') - + if newState != currentState: stateText = "enabled" if newState else "disabled" self.presentText(f"Exclusive keyboard access {stateText}") if newState: - self.presentText("Fenrir will have exclusive control of keyboard input") + self.presentText( + "Fenrir will have exclusive control of keyboard input") else: - self.presentText("Fenrir will share keyboard input with other applications") - self.presentText("Please restart Fenrir for this change to take effect") + self.presentText( + "Fenrir will share keyboard input with other applications") + self.presentText( + "Please restart Fenrir for this change to take effect") self.playSound('Accept') else: self.presentText("Failed to change keyboard grab setting") - self.playSound('Error') \ No newline at end of file + self.playSound('Error') diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/toggle_word_echo.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/toggle_word_echo.py index 14202636..f2f06471 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/toggle_word_echo.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/keyboard/toggle_word_echo.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,25 +12,27 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Toggle word echo when pressing space" - + def run(self): currentState = self.getBooleanSetting('keyboard', 'wordEcho', False) newState = self.toggleBooleanSetting('keyboard', 'wordEcho') - + if newState != currentState: stateText = "enabled" if newState else "disabled" self.presentText(f"Word echo {stateText}") if newState: self.presentText("Words will be spoken when you press space") else: - self.presentText("Words will not be spoken when you press space") + self.presentText( + "Words will not be spoken when you press space") self.playSound('Accept') else: self.presentText("Failed to change word echo setting") - self.playSound('Error') \ No newline at end of file + self.playSound('Error') diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/backup_config.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/backup_config.py index 7aa588ba..3e32b2f3 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/backup_config.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/backup_config.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,20 +12,23 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Create backup of current configuration" - + def run(self): self.presentText("Creating configuration backup...") - + success, message = self.backupConfig(announce=False) - + if success: # Force the message to be queued and spoken - self.env['runtime']['outputManager'].presentText("Configuration backup created successfully", interrupt=False, flush=False) + self.env['runtime']['outputManager'].presentText( + "Configuration backup created successfully", interrupt=False, flush=False) else: - self.env['runtime']['outputManager'].presentText("Failed to create configuration backup", interrupt=False, flush=False) \ No newline at end of file + self.env['runtime']['outputManager'].presentText( + "Failed to create configuration backup", interrupt=False, flush=False) diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/reload_config.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/reload_config.py index 7f0c3935..18986a04 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/reload_config.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/reload_config.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,21 +12,22 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Reload configuration from file" - + def run(self): self.presentText("Reloading configuration from file...") - + success = self.reloadConfig() - + if success: self.presentText("Configuration reloaded successfully") self.playSound('Accept') else: self.presentText("Failed to reload configuration") - self.playSound('Error') \ No newline at end of file + self.playSound('Error') diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/reset_defaults.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/reset_defaults.py index 29388aa0..8dbaa771 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/reset_defaults.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/reset_defaults.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util import shutil @@ -11,65 +13,89 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Reset configuration to default settings" - + def run(self): self.presentText("WARNING: This will reset all settings to defaults") self.presentText("Creating backup before reset...") - + # Create backup first backupSuccess, backupMessage = self.backupConfig(announce=False) if not backupSuccess: - self.presentText("Failed to create backup. Reset cancelled for safety.", interrupt=False) + self.presentText( + "Failed to create backup. Reset cancelled for safety.", + interrupt=False) self.playSound('Error') return - + # Find default configuration file defaultConfigPath = self.findDefaultConfig() - + if defaultConfigPath and os.path.isfile(defaultConfigPath): try: # Copy default configuration over current shutil.copy2(defaultConfigPath, self.settingsFile) - + # Reload the configuration self.reloadConfig() - - self.presentText("Configuration reset to defaults successfully", interrupt=False, flush=False) - self.presentText("Please restart Fenrir for all changes to take effect", interrupt=False, flush=False) - + + self.presentText( + "Configuration reset to defaults successfully", + interrupt=False, + flush=False) + self.presentText( + "Please restart Fenrir for all changes to take effect", + interrupt=False, + flush=False) + except Exception as e: - self.presentText(f"Failed to reset configuration: {str(e)}", interrupt=False, flush=False) + self.presentText( + f"Failed to reset configuration: { + str(e)}", interrupt=False, flush=False) else: # Manually create basic default configuration self.createBasicDefaults() - + def findDefaultConfig(self): """Find the default configuration file""" possiblePaths = [ '/usr/share/fenrirscreenreader/config/settings/settings.conf', '/etc/fenrirscreenreader/settings/settings.conf.default', - os.path.join(os.path.dirname(self.settingsFile), 'settings.conf.default'), + os.path.join( + os.path.dirname( + self.settingsFile), + 'settings.conf.default'), # Development path - os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..', '..', 'config', 'settings', 'settings.conf') + os.path.join( + os.path.dirname(__file__), + '..', + '..', + '..', + '..', + '..', + '..', + 'config', + 'settings', + 'settings.conf') ] - + for path in possiblePaths: if os.path.isfile(path): return path - + return None - + def createBasicDefaults(self): """Create basic default configuration manually""" try: self.config.clear() - + # Basic speech defaults self.config['speech'] = { 'enabled': 'True', @@ -79,7 +105,7 @@ class command(ConfigCommand): 'volume': '1.0', 'autoReadIncoming': 'True' } - + # Basic sound defaults self.config['sound'] = { 'enabled': 'True', @@ -87,7 +113,7 @@ class command(ConfigCommand): 'theme': 'default', 'volume': '0.7' } - + # Basic keyboard defaults self.config['keyboard'] = { 'driver': 'evdevDriver', @@ -97,26 +123,34 @@ class command(ConfigCommand): 'wordEcho': 'False', 'charDeleteEcho': 'True' } - + # Basic screen defaults self.config['screen'] = { 'driver': 'vcsaDriver', 'encoding': 'auto' } - + # Basic general defaults self.config['general'] = { 'punctuationLevel': 'some', 'debugLevel': '0', 'numberOfClipboards': '50' } - + # Write the configuration with open(self.settingsFile, 'w') as configfile: self.config.write(configfile) - - self.presentText("Basic default configuration created", interrupt=False, flush=False) - self.presentText("Please restart Fenrir for changes to take effect", interrupt=False, flush=False) - + + self.presentText( + "Basic default configuration created", + interrupt=False, + flush=False) + self.presentText( + "Please restart Fenrir for changes to take effect", + interrupt=False, + flush=False) + except Exception as e: - self.presentText(f"Failed to create default configuration: {str(e)}", interrupt=False, flush=False) \ No newline at end of file + self.presentText( + f"Failed to create default configuration: { + str(e)}", interrupt=False, flush=False) diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/revert_to_saved.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/revert_to_saved.py index 5629524a..2c59dd66 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/revert_to_saved.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/revert_to_saved.py @@ -1,26 +1,30 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Discard temporary changes and revert to saved settings" - + def run(self): - self.env['runtime']['outputManager'].presentText("Reverting to saved configuration...", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + "Reverting to saved configuration...", interrupt=True) + try: # Reload settings from file, discarding runtime changes settingsManager = self.env['runtime']['settingsManager'] settingsManager.loadSettings() - + # Reinitialize speech system with restored settings if 'speechDriver' in self.env['runtime']: try: @@ -28,23 +32,31 @@ class command(): speechDriver.shutdown() speechDriver.initialize(self.env) except Exception as e: - print(f'revert_to_saved speechDriver: Error reinitializing speech driver: {str(e)}') - - # Reinitialize sound system with restored settings + print( + f'revert_to_saved speechDriver: Error reinitializing speech driver: { + str(e)}') + + # Reinitialize sound system with restored settings if 'soundDriver' in self.env['runtime']: try: soundDriver = self.env['runtime']['soundDriver'] soundDriver.shutdown() soundDriver.initialize(self.env) except Exception as e: - print(f'revert_to_saved soundDriver: Error reinitializing sound driver: {str(e)}') - - self.env['runtime']['outputManager'].presentText("Successfully reverted to saved settings", interrupt=False, flush=False) - self.env['runtime']['outputManager'].presentText("All temporary changes have been discarded", interrupt=False, flush=False) - + print( + f'revert_to_saved soundDriver: Error reinitializing sound driver: { + str(e)}') + + self.env['runtime']['outputManager'].presentText( + "Successfully reverted to saved settings", interrupt=False, flush=False) + self.env['runtime']['outputManager'].presentText( + "All temporary changes have been discarded", interrupt=False, flush=False) + except Exception as e: - self.env['runtime']['outputManager'].presentText(f"Error reverting settings: {str(e)}", interrupt=False, flush=False) - self.env['runtime']['outputManager'].presentText("You may need to restart Fenrir", interrupt=False, flush=False) - + self.env['runtime']['outputManager'].presentText( + f"Error reverting settings: {str(e)}", interrupt=False, flush=False) + self.env['runtime']['outputManager'].presentText( + "You may need to restart Fenrir", interrupt=False, flush=False) + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/save_config.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/save_config.py index 85cb011b..957945ed 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/save_config.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/save_config.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,27 +12,28 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Save current configuration to file" - + def run(self): self.presentText("Saving current configuration...") - + try: # Force reload and save of current configuration self.reloadConfig() - + # Write the configuration file with open(self.settingsFile, 'w') as configfile: self.config.write(configfile) - + self.presentText("Configuration saved successfully") self.playSound('Accept') - + except Exception as e: self.presentText(f"Failed to save configuration: {str(e)}") - self.playSound('Error') \ No newline at end of file + self.playSound('Error') diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/save_session_settings.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/save_session_settings.py index 262c16fa..061cd731 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/save_session_settings.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/save_session_settings.py @@ -1,30 +1,38 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Save current session settings to configuration file" - + def run(self): - self.env['runtime']['outputManager'].presentText("Saving current session settings to configuration file...", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + "Saving current session settings to configuration file...", interrupt=True) + try: - # This calls the settings manager's save method which writes current runtime settings to file + # This calls the settings manager's save method which writes + # current runtime settings to file self.env['runtime']['settingsManager'].saveSettings() - - self.env['runtime']['outputManager'].presentText("Session settings saved successfully!", interrupt=False, flush=False) - self.env['runtime']['outputManager'].presentText("All temporary changes are now permanent.", interrupt=False, flush=False) - + + self.env['runtime']['outputManager'].presentText( + "Session settings saved successfully!", interrupt=False, flush=False) + self.env['runtime']['outputManager'].presentText( + "All temporary changes are now permanent.", interrupt=False, flush=False) + except Exception as e: - self.env['runtime']['outputManager'].presentText(f"Failed to save settings: {str(e)}", interrupt=False, flush=False) - + self.env['runtime']['outputManager'].presentText( + f"Failed to save settings: {str(e)}", interrupt=False, flush=False) + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/show_unsaved_changes.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/show_unsaved_changes.py index 6af2aae5..b43cb07e 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/show_unsaved_changes.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/management/show_unsaved_changes.py @@ -1,37 +1,46 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import configparser + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Show temporary changes not yet saved to file" - + def run(self): - self.env['runtime']['outputManager'].presentText("Checking for unsaved changes...", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + "Checking for unsaved changes...", interrupt=True) + try: # Read the current config file settingsFile = self.env['runtime']['settingsManager'].settingsFile fileConfig = configparser.ConfigParser(interpolation=None) fileConfig.read(settingsFile) - + # Compare with runtime settings runtimeSettings = self.env['runtime']['settingsManager'].settings - + changes = [] - + # Check speech settings specifically - speechSections = ['speech', 'sound', 'keyboard', 'screen', 'general'] - + speechSections = [ + 'speech', + 'sound', + 'keyboard', + 'screen', + 'general'] + for section in speechSections: if section in runtimeSettings and section in fileConfig: for option in runtimeSettings[section]: @@ -40,27 +49,34 @@ class command(): fileValue = fileConfig[section][option] except Exception as e: fileValue = "" - + if runtimeValue != fileValue: - changes.append(f"{section}.{option}: {fileValue} → {runtimeValue}") - + changes.append( + f"{section}.{option}: {fileValue} → {runtimeValue}") + if changes: - self.env['runtime']['outputManager'].presentText(f"Found {len(changes)} unsaved changes:", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Found {len(changes)} unsaved changes:", interrupt=True) for change in changes[:5]: # Limit to first 5 changes - self.env['runtime']['outputManager'].presentText(change, interrupt=True) - + self.env['runtime']['outputManager'].presentText( + change, interrupt=True) + if len(changes) > 5: - self.env['runtime']['outputManager'].presentText(f"... and {len(changes) - 5} more changes", interrupt=True) - - self.env['runtime']['outputManager'].presentText("Use save command to make these changes permanent", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"... and {len(changes) - 5} more changes", interrupt=True) + + self.env['runtime']['outputManager'].presentText( + "Use save command to make these changes permanent", interrupt=True) self.env['runtime']['outputManager'].playSound('Accept') else: - self.env['runtime']['outputManager'].presentText("No unsaved changes found", interrupt=True) + self.env['runtime']['outputManager'].presentText( + "No unsaved changes found", interrupt=True) self.env['runtime']['outputManager'].playSound('Cancel') - + except Exception as e: - self.env['runtime']['outputManager'].presentText(f"Error checking for changes: {str(e)}", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Error checking for changes: {str(e)}", interrupt=True) self.env['runtime']['outputManager'].playSound('Error') - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/screen/select_driver.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/screen/select_driver.py index 8b39be77..53a69d24 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/screen/select_driver.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/screen/select_driver.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,16 +12,17 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Select screen driver" - + def run(self): currentDriver = self.getSetting('screen', 'driver', 'vcsaDriver') - + # Present current driver driverDescriptions = { 'vcsaDriver': 'VCSA Driver - Linux TTY console access', @@ -27,10 +30,11 @@ class command(ConfigCommand): 'dummyDriver': 'Dummy Driver - for testing only', 'debugDriver': 'Debug Driver - development/debugging' } - - currentDescription = driverDescriptions.get(currentDriver, 'Unknown driver') + + currentDescription = driverDescriptions.get( + currentDriver, 'Unknown driver') self.presentText(f"Current screen driver: {currentDescription}") - + # Cycle through the available drivers drivers = ['vcsaDriver', 'ptyDriver', 'dummyDriver', 'debugDriver'] try: @@ -39,14 +43,15 @@ class command(ConfigCommand): newDriver = drivers[nextIndex] except ValueError: newDriver = 'vcsaDriver' # Default to VCSA - + success = self.setSetting('screen', 'driver', newDriver) - + if success: newDescription = driverDescriptions[newDriver] self.presentText(f"Screen driver changed to: {newDescription}") - self.presentText("Please restart Fenrir for this change to take effect.") + self.presentText( + "Please restart Fenrir for this change to take effect.") self.playSound('Accept') else: self.presentText("Failed to change screen driver") - self.playSound('Error') \ No newline at end of file + self.playSound('Error') diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/screen/set_encoding.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/screen/set_encoding.py index e94c36ce..85ccbb1c 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/screen/set_encoding.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/screen/set_encoding.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,19 +12,20 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Set screen text encoding" - + def run(self): currentEncoding = self.getSetting('screen', 'encoding', 'auto') - + # Present current encoding self.presentText(f"Current screen encoding: {currentEncoding}") - + # Cycle through available encodings encodings = ['auto', 'utf-8', 'cp1252', 'iso-8859-1'] try: @@ -31,16 +34,17 @@ class command(ConfigCommand): newEncoding = encodings[nextIndex] except ValueError: newEncoding = 'auto' # Default to auto - + success = self.setSetting('screen', 'encoding', newEncoding) - + if success: self.presentText(f"Screen encoding set to: {newEncoding}") if newEncoding == 'auto': - self.presentText("Fenrir will automatically detect text encoding") + self.presentText( + "Fenrir will automatically detect text encoding") else: self.presentText(f"Fenrir will use {newEncoding} encoding") self.playSound('Accept') else: self.presentText("Failed to change screen encoding") - self.playSound('Error') \ No newline at end of file + self.playSound('Error') diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/adjust_volume.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/adjust_volume.py index ee26d606..d220b546 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/adjust_volume.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/adjust_volume.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,34 +12,40 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Adjust sound volume" - + def run(self): currentVolume = self.getFloatSetting('sound', 'volume', 0.7) - + # Present current volume volumePercent = int(currentVolume * 100) self.presentText(f"Current sound volume: {volumePercent} percent") - + # Adjust volume by 10% newVolume = self.adjustFloatSetting('sound', 'volume', 0.1, 0.0, 1.0) - + if newVolume != currentVolume: newPercent = int(newVolume * 100) - self.presentText(f"Sound volume set to {newPercent} percent", interrupt=False) + self.presentText( + f"Sound volume set to {newPercent} percent", + interrupt=False) self.playSound('Accept') else: # If we hit the maximum, try decreasing instead - newVolume = self.adjustFloatSetting('sound', 'volume', -0.1, 0.0, 1.0) + newVolume = self.adjustFloatSetting( + 'sound', 'volume', -0.1, 0.0, 1.0) if newVolume != currentVolume: newPercent = int(newVolume * 100) - self.presentText(f"Sound volume set to {newPercent} percent", interrupt=False) + self.presentText( + f"Sound volume set to {newPercent} percent", + interrupt=False) self.playSound('Accept') else: self.presentText("Sound volume unchanged", interrupt=False) - self.playSound('Cancel') \ No newline at end of file + self.playSound('Cancel') diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/select_driver.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/select_driver.py index d524492b..f1d30ea6 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/select_driver.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/select_driver.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,19 +12,20 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Select sound driver (genericDriver or gstreamerDriver)" - + def run(self): currentDriver = self.getSetting('sound', 'driver', 'genericDriver') - + # Present current driver self.presentText(f"Current sound driver: {currentDriver}") - + # Toggle between the two available drivers if currentDriver == 'genericDriver': newDriver = 'gstreamerDriver' @@ -30,13 +33,15 @@ class command(ConfigCommand): else: newDriver = 'genericDriver' driverDescription = "Generic Driver - uses SOX for audio playback" - + success = self.setSetting('sound', 'driver', newDriver) - + if success: - self.presentText(f"Sound driver changed to {newDriver}. {driverDescription}") - self.presentText("Please restart Fenrir for this change to take effect.") + self.presentText( + f"Sound driver changed to {newDriver}. {driverDescription}") + self.presentText( + "Please restart Fenrir for this change to take effect.") self.playSound('Accept') else: self.presentText("Failed to change sound driver") - self.playSound('Error') \ No newline at end of file + self.playSound('Error') diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/select_theme.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/select_theme.py index 9203f0a5..a5396e63 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/select_theme.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/select_theme.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,28 +12,29 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Select sound theme" - + def run(self): currentTheme = self.getSetting('sound', 'theme', 'default') - + # Present current theme self.presentText(f"Current sound theme: {currentTheme}") - + # Look for available sound themes soundPaths = [ '/usr/share/sounds', '/usr/share/fenrirscreenreader/sounds', os.path.expanduser('~/.local/share/fenrirscreenreader/sounds') ] - + availableThemes = self.getAvailableThemes(soundPaths) - + if len(availableThemes) > 1: # For this implementation, cycle through available themes try: @@ -41,9 +44,9 @@ class command(ConfigCommand): except ValueError: # Current theme not found in available themes, use first one newTheme = availableThemes[0] - + success = self.setSetting('sound', 'theme', newTheme) - + if success: self.presentText(f"Sound theme changed to: {newTheme}") self.playSound('Accept') @@ -53,25 +56,27 @@ class command(ConfigCommand): else: self.presentText("Only default sound theme is available") self.playSound('Cancel') - + def getAvailableThemes(self, searchPaths): """Find available sound themes in the search paths""" themes = ['default'] # Always include default - + for path in searchPaths: if os.path.isdir(path): try: for item in os.listdir(path): fullPath = os.path.join(path, item) - if os.path.isdir(fullPath) and item != 'default' and item not in themes: - # Check if it looks like a sound theme (contains sound files) + if os.path.isdir( + fullPath) and item != 'default' and item not in themes: + # Check if it looks like a sound theme (contains + # sound files) if self.isValidSoundTheme(fullPath): themes.append(item) except Exception: continue - + return themes - + def isValidSoundTheme(self, themePath): """Check if a directory contains sound files""" soundExtensions = ['.wav', '.ogg', '.mp3', '.flac'] @@ -81,4 +86,4 @@ class command(ConfigCommand): return True except Exception: pass - return False \ No newline at end of file + return False diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/toggle_enabled.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/toggle_enabled.py index 892c2758..11dbfb96 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/toggle_enabled.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/sound/toggle_enabled.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + import os import importlib.util @@ -10,17 +12,18 @@ _module = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_module) ConfigCommand = _module.ConfigCommand + class command(ConfigCommand): def __init__(self): super().__init__() - + def getDescription(self): return "Toggle sound output on or off" - + def run(self): currentState = self.getBooleanSetting('sound', 'enabled', True) newState = self.toggleBooleanSetting('sound', 'enabled') - + if newState != currentState: stateText = "enabled" if newState else "disabled" self.presentText(f"Sound {stateText}") @@ -28,4 +31,4 @@ class command(ConfigCommand): if newState: self.playSound('Accept') else: - self.presentText("Failed to change sound setting") \ No newline at end of file + self.presentText("Failed to change sound setting") diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_pitch.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_pitch.py index d0993a42..88426f2d 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_pitch.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_pitch.py @@ -1,40 +1,48 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Adjust speech pitch (voice height)" - + def run(self): try: # Get current pitch - currentPitch = float(self.env['runtime']['settingsManager'].getSetting('speech', 'pitch')) + currentPitch = float( + self.env['runtime']['settingsManager'].getSetting( + 'speech', 'pitch')) except Exception as e: currentPitch = 0.5 - + # Present current pitch pitchPercent = int(currentPitch * 100) - self.env['runtime']['outputManager'].presentText(f"Current speech pitch: {pitchPercent} percent", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"Current speech pitch: {pitchPercent} percent", interrupt=True) + # Increase by 10%, wrap around if at max newPitch = currentPitch + 0.1 if newPitch > 1.0: newPitch = 0.1 # Wrap to minimum - + # Apply the new pitch - self.env['runtime']['settingsManager'].setSetting('speech', 'pitch', str(newPitch)) - + self.env['runtime']['settingsManager'].setSetting( + 'speech', 'pitch', str(newPitch)) + newPercent = int(newPitch * 100) - self.env['runtime']['outputManager'].presentText(f"Speech pitch set to {newPercent} percent", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Speech pitch set to {newPercent} percent", interrupt=True) self.env['runtime']['outputManager'].playSound('Accept') - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_rate.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_rate.py index e27b1515..b952f453 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_rate.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_rate.py @@ -1,39 +1,47 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Adjust speech rate (speed)" - + def run(self): try: # Get current rate - currentRate = float(self.env['runtime']['settingsManager'].getSetting('speech', 'rate')) + currentRate = float( + self.env['runtime']['settingsManager'].getSetting( + 'speech', 'rate')) except Exception as e: currentRate = 0.5 - + # Present current rate ratePercent = int(currentRate * 100) - self.env['runtime']['outputManager'].presentText(f"Current speech rate: {ratePercent} percent", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"Current speech rate: {ratePercent} percent", interrupt=True) + # Increase by 10%, wrap around if at max newRate = currentRate + 0.1 if newRate > 1.0: newRate = 0.1 # Wrap to minimum - + # Apply the new rate - self.env['runtime']['settingsManager'].setSetting('speech', 'rate', str(newRate)) - + self.env['runtime']['settingsManager'].setSetting( + 'speech', 'rate', str(newRate)) + newPercent = int(newRate * 100) - self.env['runtime']['outputManager'].presentText(f"Speech rate set to {newPercent} percent", interrupt=False, flush=False) - + self.env['runtime']['outputManager'].presentText( + f"Speech rate set to {newPercent} percent", interrupt=False, flush=False) + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_speech_rate.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_speech_rate.py index f9cd18de..92aaa174 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_speech_rate.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_speech_rate.py @@ -1,18 +1,21 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Adjust speech rate (temporary - use save to make permanent)" - + def run(self): try: # Get current rate from runtime settings (may be temporary) @@ -20,30 +23,37 @@ class command(): currentRate = float(settingsManager.getSetting('speech', 'rate')) except Exception as e: currentRate = 0.5 - + # Present current rate ratePercent = int(currentRate * 100) - self.env['runtime']['outputManager'].presentText(f"Current speech rate: {ratePercent} percent", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"Current speech rate: {ratePercent} percent", interrupt=True) + # Increase by 10%, wrap around if at max newRate = currentRate + 0.1 if newRate > 1.0: newRate = 0.1 # Wrap to minimum - + # Apply ONLY to runtime - this is temporary until saved settingsManager = self.env['runtime']['settingsManager'] settingsManager.settings['speech']['rate'] = str(newRate) - + # Apply to speech system immediately for this session if 'speechDriver' in self.env['runtime']: try: self.env['runtime']['speechDriver'].setRate(newRate) except Exception as e: - print(f'adjust_speech_rate setRate: Error setting speech rate: {str(e)}') - + print( + f'adjust_speech_rate setRate: Error setting speech rate: { + str(e)}') + newPercent = int(newRate * 100) - self.env['runtime']['outputManager'].presentText(f"Speech rate temporarily set to {newPercent} percent", interrupt=False, flush=False) - self.env['runtime']['outputManager'].presentText("Use save command to make permanent", interrupt=False, flush=False) - + self.env['runtime']['outputManager'].presentText( + f"Speech rate temporarily set to {newPercent} percent", + interrupt=False, + flush=False) + self.env['runtime']['outputManager'].presentText( + "Use save command to make permanent", interrupt=False, flush=False) + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_volume.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_volume.py index 14accb4a..4439c018 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_volume.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/adjust_volume.py @@ -1,40 +1,48 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Adjust speech volume (loudness)" - + def run(self): try: # Get current volume - currentVolume = float(self.env['runtime']['settingsManager'].getSetting('speech', 'volume')) + currentVolume = float( + self.env['runtime']['settingsManager'].getSetting( + 'speech', 'volume')) except Exception as e: currentVolume = 1.0 - + # Present current volume volumePercent = int(currentVolume * 100) - self.env['runtime']['outputManager'].presentText(f"Current speech volume: {volumePercent} percent", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"Current speech volume: {volumePercent} percent", interrupt=True) + # Increase by 10%, wrap around if at max newVolume = currentVolume + 0.1 if newVolume > 1.0: newVolume = 0.1 # Wrap to minimum - + # Apply the new volume - self.env['runtime']['settingsManager'].setSetting('speech', 'volume', str(newVolume)) - + self.env['runtime']['settingsManager'].setSetting( + 'speech', 'volume', str(newVolume)) + newPercent = int(newVolume * 100) - self.env['runtime']['outputManager'].presentText(f"Speech volume set to {newPercent} percent", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Speech volume set to {newPercent} percent", interrupt=True) self.env['runtime']['outputManager'].playSound('Accept') - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/show_current_settings.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/show_current_settings.py index 3d9c759d..ed926970 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/show_current_settings.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/fenrir/speech/show_current_settings.py @@ -1,59 +1,80 @@ #!/usr/bin/env python3 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Show current speech settings" - + def run(self): # Get current speech settings - driver = self.env['runtime']['settingsManager'].getSetting('speech', 'driver') - module = self.env['runtime']['settingsManager'].getSetting('speech', 'module') - voice = self.env['runtime']['settingsManager'].getSetting('speech', 'voice') - rate = self.env['runtime']['settingsManager'].getSetting('speech', 'rate') - pitch = self.env['runtime']['settingsManager'].getSetting('speech', 'pitch') - volume = self.env['runtime']['settingsManager'].getSetting('speech', 'volume') - enabled = self.env['runtime']['settingsManager'].getSetting('speech', 'enabled') - - self.env['runtime']['outputManager'].presentText("Current speech settings:", interrupt=True) - + driver = self.env['runtime']['settingsManager'].getSetting( + 'speech', 'driver') + module = self.env['runtime']['settingsManager'].getSetting( + 'speech', 'module') + voice = self.env['runtime']['settingsManager'].getSetting( + 'speech', 'voice') + rate = self.env['runtime']['settingsManager'].getSetting( + 'speech', 'rate') + pitch = self.env['runtime']['settingsManager'].getSetting( + 'speech', 'pitch') + volume = self.env['runtime']['settingsManager'].getSetting( + 'speech', 'volume') + enabled = self.env['runtime']['settingsManager'].getSetting( + 'speech', 'enabled') + + self.env['runtime']['outputManager'].presentText( + "Current speech settings:", interrupt=True) + # Present all settings - self.env['runtime']['outputManager'].presentText(f"Speech enabled: {enabled}", interrupt=True) - self.env['runtime']['outputManager'].presentText(f"Driver: {driver}", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"Speech enabled: {enabled}", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Driver: {driver}", interrupt=True) + if module: - self.env['runtime']['outputManager'].presentText(f"Module: {module}", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"Module: {module}", interrupt=True) + if voice: - self.env['runtime']['outputManager'].presentText(f"Voice: {voice}", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"Voice: {voice}", interrupt=True) + try: ratePercent = int(float(rate) * 100) - self.env['runtime']['outputManager'].presentText(f"Rate: {ratePercent} percent", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Rate: {ratePercent} percent", interrupt=True) except Exception as e: - self.env['runtime']['outputManager'].presentText(f"Rate: {rate}", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"Rate: {rate}", interrupt=True) + try: pitchPercent = int(float(pitch) * 100) - self.env['runtime']['outputManager'].presentText(f"Pitch: {pitchPercent} percent", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Pitch: {pitchPercent} percent", interrupt=True) except Exception as e: - self.env['runtime']['outputManager'].presentText(f"Pitch: {pitch}", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"Pitch: {pitch}", interrupt=True) + try: volumePercent = int(float(volume) * 100) - self.env['runtime']['outputManager'].presentText(f"Volume: {volumePercent} percent", interrupt=True) + self.env['runtime']['outputManager'].presentText( + f"Volume: {volumePercent} percent", interrupt=True) except Exception as e: - self.env['runtime']['outputManager'].presentText(f"Volume: {volume}", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"Volume: {volume}", interrupt=True) + self.env['runtime']['outputManager'].playSound('Accept') - + def setCallback(self, callback): - pass \ No newline at end of file + pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/file/open.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/file/open.py index 571f69c8..5545ea9b 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/file/open.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/file/open.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run open macro' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run open macro', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/file/save.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/file/save.py index d5d57e3c..f81a4427 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/file/save.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/file/save.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run open save' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run open save', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/replace.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/replace.py index 08e1e27a..829f320a 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/replace.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/replace.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run replace macro' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run replace macro', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/search.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/search.py index 6862f01b..70e316aa 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/search.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/search.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run search macro' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run search macro', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/test.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/test.py index 7a95ca1c..78f10e28 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/test.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mc/search/test.py @@ -4,26 +4,36 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import datetime + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('presents the date') - + return _('presents the date') + def run(self): - dateFormat = self.env['runtime']['settingsManager'].getSetting('general', 'dateFormat') + dateFormat = self.env['runtime']['settingsManager'].getSetting( + 'general', 'dateFormat') # get the time formatted - dateString = datetime.datetime.strftime(datetime.datetime.now(), dateFormat) + dateString = datetime.datetime.strftime( + datetime.datetime.now(), dateFormat) - # present the time via speak and braile, there is no soundicon, interrupt the current speech - self.env['runtime']['outputManager'].presentText(dateString , soundIcon='', interrupt=True) + # present the time via speak and braile, there is no soundicon, + # interrupt the current speech + self.env['runtime']['outputManager'].presentText( + dateString, soundIcon='', interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/file/issue.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/file/issue.py index 3329ab3e..60b3777b 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/file/issue.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/file/issue.py @@ -5,20 +5,26 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment - self.keyMakro = [[1, 'KEY_LEFTCTRL'], [1, 'KEY_G'], [0.05,'sleep'] ,[0, 'KEY_G'], [0, 'KEY_LEFTCTRL']] + self.keyMakro = [[1, 'KEY_LEFTCTRL'], [1, 'KEY_G'], [ + 0.05, 'sleep'], [0, 'KEY_G'], [0, 'KEY_LEFTCTRL']] + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): self.env['runtime']['inputManager'].sendKeys(self.keyMakro) + def setCallback(self, callback): pass - - - diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/file/open.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/file/open.py index a7d9ceab..17cfe0f2 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/file/open.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/file/open.py @@ -5,17 +5,33 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment - self.macro = [[1,'KEY_LEFTSHIFT'],[1,'KEY_LEFTCTRL'],[1,'KEY_N'],[0.05,'SLEEP'],[0,'KEY_N'],[0,'KEY_LEFTCTRL'],[0,'KEY_LEFTSHIFT']] + self.macro = [ + [ + 1, 'KEY_LEFTSHIFT'], [ + 1, 'KEY_LEFTCTRL'], [ + 1, 'KEY_N'], [ + 0.05, 'SLEEP'], [ + 0, 'KEY_N'], [ + 0, 'KEY_LEFTCTRL'], [ + 0, 'KEY_LEFTSHIFT']] + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): self.env['runtime']['inputManager'].sendKeys(self.macro) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/file/save.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/file/save.py index d5d57e3c..f81a4427 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/file/save.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/file/save.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run open save' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run open save', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/replace.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/replace.py index 08e1e27a..829f320a 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/replace.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/replace.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run replace macro' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run replace macro', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/search.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/search.py index 6862f01b..70e316aa 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/search.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/search.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run search macro' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run search macro', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/test.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/test.py index 7a95ca1c..78f10e28 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/test.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/mutt/search/test.py @@ -4,26 +4,36 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import datetime + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('presents the date') - + return _('presents the date') + def run(self): - dateFormat = self.env['runtime']['settingsManager'].getSetting('general', 'dateFormat') + dateFormat = self.env['runtime']['settingsManager'].getSetting( + 'general', 'dateFormat') # get the time formatted - dateString = datetime.datetime.strftime(datetime.datetime.now(), dateFormat) + dateString = datetime.datetime.strftime( + datetime.datetime.now(), dateFormat) - # present the time via speak and braile, there is no soundicon, interrupt the current speech - self.env['runtime']['outputManager'].presentText(dateString , soundIcon='', interrupt=True) + # present the time via speak and braile, there is no soundicon, + # interrupt the current speech + self.env['runtime']['outputManager'].presentText( + dateString, soundIcon='', interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/Help/about_nano.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/Help/about_nano.py index f4e2bddb..272c38f3 100755 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/Help/about_nano.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/Help/about_nano.py @@ -2,6 +2,9 @@ # -*- encoding: utf-8 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/file/open.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/file/open.py index 571f69c8..5545ea9b 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/file/open.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/file/open.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run open macro' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run open macro', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/file/save.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/file/save.py index 879f01b7..bf98dd6e 100755 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/file/save.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/file/save.py @@ -2,6 +2,9 @@ # -*- encoding: utf-8 +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/replace.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/replace.py index 08e1e27a..829f320a 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/replace.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/replace.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run replace macro' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run replace macro', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/search.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/search.py index 6862f01b..70e316aa 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/search.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/search.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run search macro' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run search macro', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/test.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/test.py index 7a95ca1c..78f10e28 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/test.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/nano/search/test.py @@ -4,26 +4,36 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import datetime + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('presents the date') - + return _('presents the date') + def run(self): - dateFormat = self.env['runtime']['settingsManager'].getSetting('general', 'dateFormat') + dateFormat = self.env['runtime']['settingsManager'].getSetting( + 'general', 'dateFormat') # get the time formatted - dateString = datetime.datetime.strftime(datetime.datetime.now(), dateFormat) + dateString = datetime.datetime.strftime( + datetime.datetime.now(), dateFormat) - # present the time via speak and braile, there is no soundicon, interrupt the current speech - self.env['runtime']['outputManager'].presentText(dateString , soundIcon='', interrupt=True) + # present the time via speak and braile, there is no soundicon, + # interrupt the current speech + self.env['runtime']['outputManager'].presentText( + dateString, soundIcon='', interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/file/open.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/file/open.py index 571f69c8..5545ea9b 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/file/open.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/file/open.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run open macro' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run open macro', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/file/save.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/file/save.py index d5d57e3c..f81a4427 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/file/save.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/file/save.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run open save' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run open save', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/replace.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/replace.py index 08e1e27a..829f320a 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/replace.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/replace.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run replace macro' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run replace macro', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/search.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/search.py index 6862f01b..70e316aa 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/search.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/search.py @@ -5,16 +5,25 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): - self.env['runtime']['outputManager'].presentText('ok i run search macro' , interrupt=True) + self.env['runtime']['outputManager'].presentText( + 'ok i run search macro', interrupt=True) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/test.py b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/test.py index 7a95ca1c..78f10e28 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/test.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/KEY/vim/search/test.py @@ -4,26 +4,36 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + import datetime + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def getDescription(self): - return _('presents the date') - + return _('presents the date') + def run(self): - dateFormat = self.env['runtime']['settingsManager'].getSetting('general', 'dateFormat') + dateFormat = self.env['runtime']['settingsManager'].getSetting( + 'general', 'dateFormat') # get the time formatted - dateString = datetime.datetime.strftime(datetime.datetime.now(), dateFormat) + dateString = datetime.datetime.strftime( + datetime.datetime.now(), dateFormat) - # present the time via speak and braile, there is no soundicon, interrupt the current speech - self.env['runtime']['outputManager'].presentText(dateString , soundIcon='', interrupt=True) + # present the time via speak and braile, there is no soundicon, + # interrupt the current speech + self.env['runtime']['outputManager'].presentText( + dateString, soundIcon='', interrupt=True) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/vmenu-profiles/template.py b/src/fenrirscreenreader/commands/vmenu-profiles/template.py index 922d5cc1..ef062275 100644 --- a/src/fenrirscreenreader/commands/vmenu-profiles/template.py +++ b/src/fenrirscreenreader/commands/vmenu-profiles/template.py @@ -5,9 +5,13 @@ # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.i18n import _ + + class command(): def __init__(self): pass + def initialize(self, environment): self.env = environment # examples: @@ -15,14 +19,18 @@ class command(): # self.keyMakro = [[1,'KEY_LEFTSHIFT'],[1,'KEY_LEFTCTRL'],[1,'KEY_N'],[0.05,'SLEEP'],[0,'KEY_N'],[0,'KEY_LEFTCTRL'],[0,'KEY_LEFTSHIFT']] self.keyMakro = [] self.byteMakro = [] + def shutdown(self): pass + def getDescription(self): - return 'No description found' + return 'No description found' + def run(self): if self.env['runtime']['inputManager'].getShortcutType() in ['KEY']: self.env['runtime']['inputManager'].sendKeys(self.keyMakro) elif self.env['runtime']['inputManager'].getShortcutType() in ['BYTE']: self.env['runtime']['byteManager'].sendBytes(self.byteMakro) + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/core/applicationManager.py b/src/fenrirscreenreader/core/applicationManager.py index b05fde9a..3f36ed98 100644 --- a/src/fenrirscreenreader/core/applicationManager.py +++ b/src/fenrirscreenreader/core/applicationManager.py @@ -6,26 +6,32 @@ from fenrirscreenreader.core import debug + class applicationManager(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getCurrentApplication(self): currApp = self.env['screen']['newApplication'].upper() if not currApp: - currApp = 'DEFAULT' + currApp = 'DEFAULT' if currApp == '': currApp = 'DEFAULT' return currApp + def getPrevApplication(self): prevApp = self.env['screen']['oldApplication'].upper() if not prevApp: - prevApp = 'DEFAULT' + prevApp = 'DEFAULT' if prevApp == '': - prevApp = 'DEFAULT' + prevApp = 'DEFAULT' return prevApp + def isApplicationChange(self): return self.env['screen']['oldApplication'] != self.env['screen']['newApplication'] diff --git a/src/fenrirscreenreader/core/attributeManager.py b/src/fenrirscreenreader/core/attributeManager.py index 43ced0d7..f4553621 100644 --- a/src/fenrirscreenreader/core/attributeManager.py +++ b/src/fenrirscreenreader/core/attributeManager.py @@ -5,8 +5,10 @@ # By Chrys, Storm Dragon, and contributers. from fenrirscreenreader.core import debug +from fenrirscreenreader.core.i18n import _ from collections import Counter + class attributeManager(): def __init__(self): self.currAttributes = None @@ -20,44 +22,59 @@ class attributeManager(): def initialize(self, environment): self.env = environment + def shutdown(self): pass + def setLastCursorAttribute(self, lastCursorAttribute): self.prevLastCursorAttribute = self.currLastCursorAttribute self.currLastCursorAttribute = lastCursorAttribute + def resetLastCursorAttribute(self): self.prevLastCursorAttribute = None self.currLastCursorAttribute = None + def isLastCursorAttributeChange(self): - if self.prevLastCursorAttribute == None: + if self.prevLastCursorAttribute is None: return False return self.prevLastCursorAttribute != self.currLastCursorAttribute + def getCurrAttributeCursor(self): return self.currAttributeCursor + def isAttributeCursorActive(self): - return self.currAttributeCursor != None + return self.currAttributeCursor is not None + def isAttributeChange(self): - if not self.prevAttributes: + if not self.prevAttributes: return False return self.currAttributes != self.prevAttributes + def resetAttributeAll(self): self.resetAttributeDelta() self.resetAttributeCursor() + def getAttributeDelta(self): return self.currAttributeDelta + def resetAttributeDelta(self): self.currAttributeDelta = '' + def setAttributeDelta(self, currAttributeDelta): self.currAttributeDelta = currAttributeDelta + def resetAttributeCursor(self): self.currAttributeCursor = None self.prefAttributeCursor = None + def setAttributeCursor(self, currAttributeCursor): self.prefAttributeCursor = self.currAttributeCursor self.currAttributeCursor = currAttributeCursor.copy() + def resetAttributes(self, currAttributes): self.prevAttributes = None self.currAttributes = currAttributes + def setAttributes(self, currAttributes): self.prevAttributes = self.currAttributes self.currAttributes = currAttributes.copy() @@ -75,36 +92,43 @@ class attributeManager(): try: return self.defaultAttributes[0] except Exception as e: - self.env['runtime']['debug'].writeDebugOut('attributeManager getAttributeByXY: Error accessing default attributes: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'attributeManager getAttributeByXY: Error accessing default attributes: ' + + str(e), + debug.debugLevel.ERROR) return None + def appendDefaultAttributes(self, attribute): if not attribute: return if len(attribute) != 10: return self.defaultAttributes.append(attribute) + def initDefaultAttributes(self): self.defaultAttributes = [None] self.defaultAttributes.append([ - 'default', # fg - 'default', # bg - False, # bold - False, # italics - False, # underscore - False, # strikethrough - False, # reverse - False, # blink - 'default', # fontsize - 'default' # fontfamily - ]) #end attribute - def isDefaultAttribute(self,attribute): + 'default', # fg + 'default', # bg + False, # bold + False, # italics + False, # underscore + False, # strikethrough + False, # reverse + False, # blink + 'default', # fontsize + 'default' # fontfamily + ]) # end attribute + + def isDefaultAttribute(self, attribute): return attribute in self.defaultAttributes + def hasAttributes(self, cursor, update=True): if not cursor: return False cursorPos = cursor.copy() try: - attribute = self.getAttributeByXY( cursorPos['x'], cursorPos['y']) + attribute = self.getAttributeByXY(cursorPos['x'], cursorPos['y']) if update: self.setLastCursorAttribute(attribute) @@ -118,7 +142,7 @@ class attributeManager(): return False return True - def formatAttributes(self, attribute, attributeFormatString = ''): + def formatAttributes(self, attribute, attributeFormatString=''): # "black", # "red", # "green", @@ -140,7 +164,8 @@ class attributeManager(): # "fontsieze" # "fontfamily" if attributeFormatString == '': - attributeFormatString = self.env['runtime']['settingsManager'].getSetting('general', 'attributeFormatString') + attributeFormatString = self.env['runtime']['settingsManager'].getSetting( + 'general', 'attributeFormatString') if not attributeFormatString: return '' if attributeFormatString == '': @@ -152,20 +177,25 @@ class attributeManager(): # 0 FG color (name) try: - attributeFormatString = attributeFormatString.replace('fenrirFGColor', _(attribute[0])) + attributeFormatString = attributeFormatString.replace( + 'fenrirFGColor', _(attribute[0])) except Exception as e: - attributeFormatString = attributeFormatString.replace('fenrirFGColor', '') + attributeFormatString = attributeFormatString.replace( + 'fenrirFGColor', '') # 1 BG color (name) try: - attributeFormatString = attributeFormatString.replace('fenrirBGColor', _(attribute[1])) + attributeFormatString = attributeFormatString.replace( + 'fenrirBGColor', _(attribute[1])) except Exception as e: - attributeFormatString = attributeFormatString.replace('fenrirBGColor', '') + attributeFormatString = attributeFormatString.replace( + 'fenrirBGColor', '') # 2 bold (True/ False) try: if attribute[2]: - attributeFormatString = attributeFormatString.replace('fenrirBold', _('bold')) + attributeFormatString = attributeFormatString.replace( + 'fenrirBold', _('bold')) except Exception as e: pass attributeFormatString = attributeFormatString.replace('fenrirBold', '') @@ -173,72 +203,94 @@ class attributeManager(): # 3 italics (True/ False) try: if attribute[3]: - attributeFormatString = attributeFormatString.replace('fenrirItalics', _('italic')) + attributeFormatString = attributeFormatString.replace( + 'fenrirItalics', _('italic')) except Exception as e: pass - attributeFormatString = attributeFormatString.replace('fenrirItalics', '') + attributeFormatString = attributeFormatString.replace( + 'fenrirItalics', '') # 4 underline (True/ False) try: if attribute[4]: - attributeFormatString = attributeFormatString.replace('fenrirUnderline', _('underline')) + attributeFormatString = attributeFormatString.replace( + 'fenrirUnderline', _('underline')) except Exception as e: pass - attributeFormatString = attributeFormatString.replace('fenrirUnderline', '') + attributeFormatString = attributeFormatString.replace( + 'fenrirUnderline', '') # 5 strikethrough (True/ False) try: if attribute[5]: - attributeFormatString = attributeFormatString.replace('fenrirStrikethrough', _('strikethrough')) + attributeFormatString = attributeFormatString.replace( + 'fenrirStrikethrough', _('strikethrough')) except Exception as e: pass - attributeFormatString = attributeFormatString.replace('fenrirStrikethrough', '') + attributeFormatString = attributeFormatString.replace( + 'fenrirStrikethrough', '') # 6 reverse (True/ False) try: if attribute[6]: - attributeFormatString = attributeFormatString.replace('fenrirReverse', _('reverse')) + attributeFormatString = attributeFormatString.replace( + 'fenrirReverse', _('reverse')) except Exception as e: pass - attributeFormatString = attributeFormatString.replace('fenrirReverse', '') + attributeFormatString = attributeFormatString.replace( + 'fenrirReverse', '') # 7 blink (True/ False) try: if attribute[7]: - attributeFormatString = attributeFormatString.replace('fenrirBlink', _('blink')) + attributeFormatString = attributeFormatString.replace( + 'fenrirBlink', _('blink')) except Exception as e: pass - attributeFormatString = attributeFormatString.replace('fenrirBlink', '') + attributeFormatString = attributeFormatString.replace( + 'fenrirBlink', '') # 8 font size (int/ string) try: try: - attributeFormatString = attributeFormatString.replace('fenrirFontSize', int(attribute[8])) + attributeFormatString = attributeFormatString.replace( + 'fenrirFontSize', int(attribute[8])) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('attributeManager formatAttributeToString: Error formatting font size as int: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'attributeManager formatAttributeToString: Error formatting font size as int: ' + + str(e), + debug.debugLevel.ERROR) try: - attributeFormatString = attributeFormatString.replace('fenrirFontSize', str(attribute[8])) + attributeFormatString = attributeFormatString.replace( + 'fenrirFontSize', str(attribute[8])) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('attributeManager formatAttributeToString: Error formatting font size as string: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'attributeManager formatAttributeToString: Error formatting font size as string: ' + + str(e), + debug.debugLevel.ERROR) except Exception as e: pass - attributeFormatString = attributeFormatString.replace('fenrirFontSize', _('default')) + attributeFormatString = attributeFormatString.replace( + 'fenrirFontSize', _('default')) # 9 font family (string) try: - attributeFormatString = attributeFormatString.replace('fenrirFont', attribute[9]) + attributeFormatString = attributeFormatString.replace( + 'fenrirFont', attribute[9]) except Exception as e: pass - attributeFormatString = attributeFormatString.replace('fenrirFont', _('default')) + attributeFormatString = attributeFormatString.replace( + 'fenrirFont', _('default')) return attributeFormatString + def trackHighlights(self): """ Detects text with changed attributes (highlighting) between screen updates. - + This is crucial for screen readers to announce when text becomes highlighted, selected, or changes visual emphasis (bold, reverse video, color changes, etc.) - + Returns: tuple: (highlighted_text, cursor_position) - highlighted_text: string of characters that gained highlighting @@ -246,60 +298,73 @@ class attributeManager(): """ result = '' currCursor = None - + # Early exit conditions - no attribute comparison possible - if self.prevAttributes == None: + if self.prevAttributes is None: # First screen load - no previous attributes to compare against - return result, currCursor + return result, currCursor if self.prevAttributes == self.currAttributes: # No attribute changes detected - return result, currCursor - if self.currAttributes == None: + return result, currCursor + if self.currAttributes is None: # Error condition - current attributes missing - return result, currCursor + return result, currCursor if len(self.currAttributes) == 0: # Special case for PTY environments with no text content - return result, currCursor - + return result, currCursor + # Get current screen text to correlate with attribute changes text = self.env['runtime']['screenManager'].getScreenText() textLines = text.split('\n') # Sanity check: text lines must match attribute array dimensions if len(textLines) != len(self.currAttributes): - return result, currCursor - + return result, currCursor + # Compare attributes line by line, character by character for line in range(len(self.prevAttributes)): if self.prevAttributes[line] != self.currAttributes[line]: - # This line has attribute changes - examine each character position + # This line has attribute changes - examine each character + # position for column in range(len(self.prevAttributes[line])): if self.prevAttributes[line][column] == self.currAttributes[line][column]: # No change at this position continue - # Attribute changed at this position - check if it's worth announcing - if self.isUsefulForTracking(line, column, self.currAttributes, self.prevAttributes): - # First highlighted character becomes cursor position for navigation + # Attribute changed at this position - check if it's worth + # announcing + if self.isUsefulForTracking( + line, column, self.currAttributes, self.prevAttributes): + # First highlighted character becomes cursor position + # for navigation if not currCursor: currCursor = {'x': column, 'y': line} # Accumulate highlighted characters result += textLines[line][column] - # Add space between lines of highlighted text for speech clarity + # Add space between lines of highlighted text for speech + # clarity result += ' ' return result, currCursor - def isUsefulForTracking(self, line, column, currAttributes, prevAttributes, attribute=1 , mode = 'zaxe'): + + def isUsefulForTracking( + self, + line, + column, + currAttributes, + prevAttributes, + attribute=1, + mode='zaxe'): """ Determines if an attribute change at a specific position is worth announcing. - + This prevents announcing every minor attribute change and focuses on meaningful highlighting that indicates user selections, focus changes, or important emphasis. - + Args: line, column: Position of the attribute change currAttributes, prevAttributes: Current and previous attribute arrays attribute: Which attribute to examine (1=background color by default) mode: Detection algorithm ('zaxe', 'default', 'barrier') - + Returns: bool: True if this attribute change should be announced to user """ @@ -307,37 +372,37 @@ class attributeManager(): if len(currAttributes) <= 3: return False if line < 0: - return False + return False if line > len(currAttributes): return False - + useful = False - + if mode == 'default': # Simple mode: announce any non-default attribute useful = not self.isDefaultAttribute(currAttributes[line][column]) - + elif (mode == 'zaxe') or (mode == ''): # Context-aware mode: only announce attributes that stand out from surroundings # This prevents announcing entire blocks of highlighted text character by character # by checking if the attribute differs from adjacent lines - + if line == 0: # Top line: compare against lines below - useful = (currAttributes[line][column][attribute] != currAttributes[line + 1][column][attribute]) and \ - (currAttributes[line][column][attribute] != currAttributes[line + 2][column][attribute]) + useful = (currAttributes[line][column][attribute] != currAttributes[line + 1][column][attribute]) and ( + currAttributes[line][column][attribute] != currAttributes[line + 2][column][attribute]) elif line >= len(prevAttributes): - # Bottom line: compare against lines above - useful = (currAttributes[line][column][attribute] != currAttributes[line - 1][column][attribute]) and \ - (currAttributes[line][column][attribute] != currAttributes[line - 2][column][attribute]) + # Bottom line: compare against lines above + useful = (currAttributes[line][column][attribute] != currAttributes[line - 1][column][attribute]) and ( + currAttributes[line][column][attribute] != currAttributes[line - 2][column][attribute]) else: # Middle lines: compare against both directions - useful = (currAttributes[line][column][attribute] != currAttributes[line + 1][column][attribute]) and \ - (currAttributes[line][column][attribute] != currAttributes[line - 1][column][attribute]) - + useful = (currAttributes[line][column][attribute] != currAttributes[line + 1][column][attribute]) and ( + currAttributes[line][column][attribute] != currAttributes[line - 1][column][attribute]) + elif mode == 'barrier': - # Barrier mode: future enhancement for detecting screen boundaries/separators + # Barrier mode: future enhancement for detecting screen + # boundaries/separators useful = True return useful - diff --git a/src/fenrirscreenreader/core/barrierManager.py b/src/fenrirscreenreader/core/barrierManager.py index 6e8b4585..68a114af 100644 --- a/src/fenrirscreenreader/core/barrierManager.py +++ b/src/fenrirscreenreader/core/barrierManager.py @@ -5,26 +5,39 @@ # By Chrys, Storm Dragon, and contributers. from fenrirscreenreader.core import debug -import re, string +import re +import string + class barrierManager(): def __init__(self): self.currIsBarrier = False self.prefIsBarrier = False + def initialize(self, environment): - self.env = environment + self.env = environment + def shutdown(self): - pass - def updateBarrierChange(self, isBarrier): + pass + + def updateBarrierChange(self, isBarrier): self.prefIsBarrier = self.currIsBarrier self.currIsBarrier = isBarrier - def resetBarrierChange(self): + def resetBarrierChange(self): self.currIsBarrier = False self.prefIsBarrier = False + def isBarrierChange(self): return self.currIsBarrier != self.prefIsBarrier - def handleLineBarrier(self, text, xCursor, yCursor, output=True, doInterrupt=True): + + def handleLineBarrier( + self, + text, + xCursor, + yCursor, + output=True, + doInterrupt=True): isBarrier = False try: isBarrier, sayLine = self.getBarrierText(text, xCursor, yCursor) @@ -33,47 +46,51 @@ class barrierManager(): self.updateBarrierChange(isBarrier) if self.isBarrierChange(): - if output: + if output: if isBarrier: - self.env['runtime']['outputManager'].playSoundIcon(soundIcon='BarrierStart', interrupt=doInterrupt) + self.env['runtime']['outputManager'].playSoundIcon( + soundIcon='BarrierStart', interrupt=doInterrupt) else: - self.env['runtime']['outputManager'].playSoundIcon(soundIcon='BarrierEnd', interrupt=doInterrupt) + self.env['runtime']['outputManager'].playSoundIcon( + soundIcon='BarrierEnd', interrupt=doInterrupt) if not isBarrier: - sayLine = '' + sayLine = '' return isBarrier, sayLine def getBarrierText(self, text, xCursor, yCursor): line = text[yCursor] - if not self.env['runtime']['settingsManager'].getSettingAsBool('barrier', 'enabled'): - return False, line - offset = xCursor + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'barrier', 'enabled'): + return False, line + offset = xCursor - leftBarriers = self.env['runtime']['settingsManager'].getSetting('barrier', 'leftBarriers') - rightBarriers = self.env['runtime']['settingsManager'].getSetting('barrier', 'rightBarriers') - # is the cursor at the begin or end of an entry: - #print(line[:offset + 1].count('│'),line[offset:].count('│')) + leftBarriers = self.env['runtime']['settingsManager'].getSetting( + 'barrier', 'leftBarriers') + rightBarriers = self.env['runtime']['settingsManager'].getSetting( + 'barrier', 'rightBarriers') + # is the cursor at the begin or end of an entry: + # print(line[:offset + 1].count('│'),line[offset:].count('│')) # start - for b in leftBarriers: + for b in leftBarriers: if line[:offset + 1].count(b) > line[offset:].count(b): offset = xCursor - 1 start = line[:offset].rfind(b) if start != -1: - start += 1 + start += 1 break if start == -1: - return False, line + return False, line # end - for b in rightBarriers: + for b in rightBarriers: end = line[start:].find(b) if end != -1: - end = start + end + end = start + end break if end == -1: - return False, line + return False, line if start == end: return False, line return True, line[start:end] - diff --git a/src/fenrirscreenreader/core/byteManager.py b/src/fenrirscreenreader/core/byteManager.py index 9d91158f..afa5cdce 100644 --- a/src/fenrirscreenreader/core/byteManager.py +++ b/src/fenrirscreenreader/core/byteManager.py @@ -5,31 +5,44 @@ # By Chrys, Storm Dragon, and contributers. from fenrirscreenreader.core import debug +from fenrirscreenreader.core.i18n import _ from fenrirscreenreader.core.eventData import fenrirEventType -import os, inspect, re, time -currentdir = os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe())))) +import os +import inspect +import re +import time +currentdir = os.path.dirname( + os.path.realpath( + os.path.abspath( + inspect.getfile( + inspect.currentframe())))) fenrirPath = os.path.dirname(currentdir) + class byteManager(): def __init__(self): - self.switchCtrlModeOnce = 0 + self.switchCtrlModeOnce = 0 self.controlMode = True self.repeat = 1 self.lastInputTime = time.time() self.lastByteKey = b'' + def initialize(self, environment): - self.env = environment + self.env = environment + def shutdown(self): pass - def unifyEscapeSeq(self, escapeSequence): + + def unifyEscapeSeq(self, escapeSequence): convertedEscapeSequence = escapeSequence if convertedEscapeSequence[0] == 27: convertedEscapeSequence = b'^[' + convertedEscapeSequence[1:] if len(convertedEscapeSequence) > 1: - if convertedEscapeSequence[0] == 94 and convertedEscapeSequence[1] ==91: - convertedEscapeSequence = b'^[' + convertedEscapeSequence[2:] + if convertedEscapeSequence[0] == 94 and convertedEscapeSequence[1] == 91: + convertedEscapeSequence = b'^[' + convertedEscapeSequence[2:] return convertedEscapeSequence - def handleByteStream(self, eventData, sep = b'\x1b'): + + def handleByteStream(self, eventData, sep=b'\x1b'): buffer = eventData # handle prefix endIndex = buffer.find(sep) @@ -51,16 +64,21 @@ class byteManager(): currSequence = buffer[:endIndex + len(sep)] buffer = buffer[endIndex + len(sep):] self.handleSingleByteSequence(currSequence) + def handleByteInput(self, eventData): if not eventData: return if eventData == b'': return try: - self.env['runtime']['debug'].writeDebugOut("handleByteInput " + eventData.decode('utf8') ,debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "handleByteInput " + eventData.decode('utf8'), debug.debugLevel.INFO) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('byteManager handleByteInput: Error decoding byte data: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'byteManager handleByteInput: Error decoding byte data: ' + str(e), + debug.debugLevel.ERROR) self.handleByteStream(eventData) + def handleSingleByteSequence(self, eventData): convertedEscapeSequence = self.unifyEscapeSeq(eventData) @@ -69,14 +87,15 @@ class byteManager(): isControlMode = False if self.controlMode and not self.switchCtrlModeOnce == 1 or\ - not self.controlMode: + not self.controlMode: isControlMode = self.handleControlMode(eventData) isCommand = False if self.controlMode and not self.switchCtrlModeOnce == 1 or\ - not self.controlMode and self.switchCtrlModeOnce == 1: + not self.controlMode and self.switchCtrlModeOnce == 1: if self.lastByteKey == convertedEscapeSequence: - if time.time() - self.lastInputTime <= self.env['runtime']['settingsManager'].getSettingAsFloat('keyboard','doubleTapTimeout'): + if time.time() - self.lastInputTime <= self.env['runtime']['settingsManager'].getSettingAsFloat( + 'keyboard', 'doubleTapTimeout'): self.repeat += 1 shortcutData = b'' for i in range(self.repeat): @@ -84,7 +103,7 @@ class byteManager(): isCommand = self.detectByteCommand(shortcutData) # fall back to single stroke - do we want this? if not isCommand: - isCommand = self.detectByteCommand(convertedEscapeSequence) + isCommand = self.detectByteCommand(convertedEscapeSequence) self.repeat = 1 if not (isCommand or isControlMode): self.env['runtime']['screenManager'].injectTextToScreen(eventData) @@ -92,48 +111,61 @@ class byteManager(): self.repeat = 1 self.lastByteKey = convertedEscapeSequence self.lastInputTime = time.time() + def getLastByteKey(self): return self.lastByteKey - def handleControlMode(self, escapeSequence): + + def handleControlMode(self, escapeSequence): convertedEscapeSequence = self.unifyEscapeSeq(escapeSequence) if convertedEscapeSequence == b'^[R': self.controlMode = not self.controlMode self.switchCtrlModeOnce = 0 if self.controlMode: - self.env['runtime']['outputManager'].presentText(_('Sticky Mode On'), soundIcon='Accept', interrupt=True, flush=True) + self.env['runtime']['outputManager'].presentText( + _('Sticky Mode On'), soundIcon='Accept', interrupt=True, flush=True) else: - self.env['runtime']['outputManager'].presentText(_('Sticky Mode On'), soundIcon='Cancel', interrupt=True, flush=True) - return True + self.env['runtime']['outputManager'].presentText( + _('Sticky Mode On'), soundIcon='Cancel', interrupt=True, flush=True) + return True if convertedEscapeSequence == b'^[:': self.switchCtrlModeOnce = 2 - self.env['runtime']['outputManager'].presentText(_('bypass'), soundIcon='PTYBypass', interrupt=True, flush=True) + self.env['runtime']['outputManager'].presentText( + _('bypass'), soundIcon='PTYBypass', interrupt=True, flush=True) return True - return False + return False + def sendBytes(self, byteMacro): pass + def detectByteCommand(self, escapeSequence): convertedEscapeSequence = self.unifyEscapeSeq(escapeSequence) - command = self.env['runtime']['inputManager'].getCommandForShortcut(convertedEscapeSequence) - if command != '': - self.env['runtime']['eventManager'].putToEventQueue(fenrirEventType.ExecuteCommand, command) + command = self.env['runtime']['inputManager'].getCommandForShortcut( + convertedEscapeSequence) + if command != '': + self.env['runtime']['eventManager'].putToEventQueue( + fenrirEventType.ExecuteCommand, command) command = '' return True - return False - def loadByteShortcuts(self, kbConfigPath=fenrirPath + '/../../config/keyboard/pty.conf'): - kbConfig = open(kbConfigPath,"r") - while(True): + return False + + def loadByteShortcuts( + self, + kbConfigPath=fenrirPath + + '/../../config/keyboard/pty.conf'): + kbConfig = open(kbConfigPath, "r") + while (True): line = kbConfig.readline() if not line: break - line = line.replace('\n','') - if line.replace(" ","") == '': - continue - if line.replace(" ","").startswith("#"): + line = line.replace('\n', '') + if line.replace(" ", "") == '': + continue + if line.replace(" ", "").startswith("#"): continue if line.count("=") != 1: continue Values = line.split('=') - cleanShortcut = bytes(Values[0],'UTF-8') + cleanShortcut = bytes(Values[0], 'UTF-8') repeat = 1 if len(cleanShortcut) > 2: if chr(cleanShortcut[1]) == ',': @@ -141,13 +173,21 @@ class byteManager(): repeat = int(chr(cleanShortcut[0])) cleanShortcut = cleanShortcut[2:] except Exception as e: - self.env['runtime']['debug'].writeDebugOut('byteManager loadByteShortcuts: Error parsing repeat count: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'byteManager loadByteShortcuts: Error parsing repeat count: ' + str(e), + debug.debugLevel.ERROR) repeat = 1 cleanShortcut = cleanShortcut - shortcut = b'' + shortcut = b'' for i in range(repeat): shortcut += cleanShortcut commandName = Values[1].upper() - self.env['bindings'][shortcut] = commandName - self.env['runtime']['debug'].writeDebugOut("Byte Shortcut: "+ str(shortcut) + ' command:' +commandName ,debug.debugLevel.INFO, onAnyLevel=True) - kbConfig.close() + self.env['bindings'][shortcut] = commandName + self.env['runtime']['debug'].writeDebugOut( + "Byte Shortcut: " + + str(shortcut) + + ' command:' + + commandName, + debug.debugLevel.INFO, + onAnyLevel=True) + kbConfig.close() diff --git a/src/fenrirscreenreader/core/commandData.py b/src/fenrirscreenreader/core/commandData.py index 65ec426a..8cdbcf9f 100644 --- a/src/fenrirscreenreader/core/commandData.py +++ b/src/fenrirscreenreader/core/commandData.py @@ -10,15 +10,15 @@ import time # used as shared memory between commands # use this in your own commands commandBuffer = { -'enableSpeechOnKeypress': False, -'Marks':{'1':None, '2':None}, -'bookMarks':{}, -'windowArea':{}, + 'enableSpeechOnKeypress': False, + 'Marks': {'1': None, '2': None}, + 'bookMarks': {}, + 'windowArea': {}, } # used by the commandManager commandInfo = { -#'currCommand': '', -'lastCommandExecutionTime': time.time(), -'lastCommandRequestTime': time.time(), + # 'currCommand': '', + 'lastCommandExecutionTime': time.time(), + 'lastCommandRequestTime': time.time(), } diff --git a/src/fenrirscreenreader/core/commandManager.py b/src/fenrirscreenreader/core/commandManager.py index c23af755..ef11fc04 100644 --- a/src/fenrirscreenreader/core/commandManager.py +++ b/src/fenrirscreenreader/core/commandManager.py @@ -4,45 +4,59 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. -import glob, os, time, inspect -currentdir = os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe())))) +from fenrirscreenreader.utils import module_utils +from fenrirscreenreader.core import debug +import glob +import os +import time +import inspect +currentdir = os.path.dirname( + os.path.realpath( + os.path.abspath( + inspect.getfile( + inspect.currentframe())))) fenrirPath = os.path.dirname(currentdir) -from fenrirscreenreader.core import debug -from fenrirscreenreader.utils import module_utils class commandManager(): def __init__(self): pass + def initialize(self, environment): self.env = environment # commands self.env['commands'] = {} - self.env['commandsIgnore'] = {} + self.env['commandsIgnore'] = {} for commandFolder in self.env['general']['commandFolderList']: - self.env['runtime']['commandManager'].loadCommands(commandFolder) - if self.env['runtime']['settingsManager'].getSetting('general', 'commandPath') != '': - self.env['runtime']['commandManager'].loadCommands(commandFolder, - self.env['runtime']['settingsManager'].getSetting('general', 'commandPath')) + self.env['runtime']['commandManager'].loadCommands(commandFolder) + if self.env['runtime']['settingsManager'].getSetting( + 'general', 'commandPath') != '': + self.env['runtime']['commandManager'].loadCommands( + commandFolder, self.env['runtime']['settingsManager'].getSetting( + 'general', 'commandPath')) # scripts for scriptKey self.env['runtime']['commandManager'].loadScriptCommands() def shutdown(self): - for commandFolder in self.env['general']['commandFolderList']: - self.env['runtime']['commandManager'].shutdownCommands(commandFolder) + for commandFolder in self.env['general']['commandFolderList']: + self.env['runtime']['commandManager'].shutdownCommands( + commandFolder) - def loadFile(self, filepath = ''): + def loadFile(self, filepath=''): if filepath == '': return None if not os.path.exists(filepath): - self.env['runtime']['debug'].writeDebugOut("loadFile: filepath not exists:" + filepath ,debug.debugLevel.WARNING) + self.env['runtime']['debug'].writeDebugOut( + "loadFile: filepath not exists:" + filepath, debug.debugLevel.WARNING) return None if os.path.isdir(filepath): - self.env['runtime']['debug'].writeDebugOut("loadFile: filepath is a directory:" + filepath ,debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "loadFile: filepath is a directory:" + filepath, debug.debugLevel.ERROR) return None if not os.access(filepath, os.R_OK): - self.env['runtime']['debug'].writeDebugOut("loadFile: filepath not readable:" + filepath ,debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "loadFile: filepath not readable:" + filepath, debug.debugLevel.ERROR) return None try: @@ -54,30 +68,41 @@ class commandManager(): command_mod = module_utils.importModule(fileName, filepath) command = command_mod.command() command.initialize(self.env) - self.env['runtime']['debug'].writeDebugOut("loadFile: Load command:" + filepath ,debug.debugLevel.INFO, onAnyLevel=True) + self.env['runtime']['debug'].writeDebugOut( + "loadFile: Load command:" + filepath, debug.debugLevel.INFO, onAnyLevel=True) return command except Exception as e: - self.env['runtime']['debug'].writeDebugOut("loadFile: Loading command:" + filepath ,debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "loadFile: Loading command:" + filepath, debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) return None - def loadCommands(self, section='commands',commandPath=''): - if commandPath =='': - commandPath = fenrirPath+ "/commands/" + + def loadCommands(self, section='commands', commandPath=''): + if commandPath == '': + commandPath = fenrirPath + "/commands/" if not commandPath.endswith('/'): commandPath += '/' - commandFolder = commandPath + section +"/" + commandFolder = commandPath + section + "/" if not os.path.exists(commandFolder): - self.env['runtime']['debug'].writeDebugOut("loadCommands: commandFolder not exists:" + commandFolder ,debug.debugLevel.WARNING) - return + self.env['runtime']['debug'].writeDebugOut( + "loadCommands: commandFolder not exists:" + commandFolder, + debug.debugLevel.WARNING) + return if not os.path.isdir(commandFolder): - self.env['runtime']['debug'].writeDebugOut("loadCommands: commandFolder not a directory:" + commandFolder ,debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "loadCommands: commandFolder not a directory:" + + commandFolder, + debug.debugLevel.ERROR) return if not os.access(commandFolder, os.R_OK): - self.env['runtime']['debug'].writeDebugOut("loadCommands: commandFolder not readable:" + commandFolder ,debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "loadCommands: commandFolder not readable:" + commandFolder, + debug.debugLevel.ERROR) return self.env['commands'][section] = {} self.env['commandsIgnore'][section] = {} - commandList = glob.glob(commandFolder+'*') + commandList = glob.glob(commandFolder + '*') for command in commandList: try: fileName, fileExtension = os.path.splitext(command) @@ -88,37 +113,53 @@ class commandManager(): if fileName.endswith('_base'): continue # Check if command already exists to prevent duplicate loading - if fileName.upper() in self.env['commands'][section] and self.env['commands'][section][fileName.upper()] is not None: + if fileName.upper( + ) in self.env['commands'][section] and self.env['commands'][section][fileName.upper()] is not None: continue if fileExtension.lower() == '.py': command_mod = module_utils.importModule(fileName, command) - self.env['commands'][section][fileName.upper()] = command_mod.command() - self.env['commandsIgnore'][section][fileName.upper()[fileName.upper().find('-')+1:]+'_IGNORE'] = False - self.env['commands'][section][fileName.upper()].initialize(self.env) - self.env['runtime']['debug'].writeDebugOut("loadCommands: Load command:" + section + "." + fileName.upper() ,debug.debugLevel.INFO, onAnyLevel=True) + self.env['commands'][section][fileName.upper() + ] = command_mod.command() + self.env['commandsIgnore'][section][fileName.upper( + )[fileName.upper().find('-') + 1:] + '_IGNORE'] = False + self.env['commands'][section][fileName.upper() + ].initialize(self.env) + self.env['runtime']['debug'].writeDebugOut( + "loadCommands: Load command:" + + section + + "." + + fileName.upper(), + debug.debugLevel.INFO, + onAnyLevel=True) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("loadCommands: Loading command:" + command ,debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "loadCommands: Loading command:" + command, debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) continue def loadScriptCommands(self, section='commands', scriptPath=''): - if scriptPath =='': - scriptPath = self.env['runtime']['settingsManager'].getSetting('general', 'scriptPath') + if scriptPath == '': + scriptPath = self.env['runtime']['settingsManager'].getSetting( + 'general', 'scriptPath') if not scriptPath.endswith('/'): scriptPath += '/' if not os.path.exists(scriptPath): - if os.path.exists(fenrirPath +'/../../config/scripts/'): - scriptPath = fenrirPath +'/../../config/scripts/' + if os.path.exists(fenrirPath + '/../../config/scripts/'): + scriptPath = fenrirPath + '/../../config/scripts/' else: - self.env['runtime']['debug'].writeDebugOut("scriptpath not exists:" + scriptPath ,debug.debugLevel.WARNING) - return + self.env['runtime']['debug'].writeDebugOut( + "scriptpath not exists:" + scriptPath, debug.debugLevel.WARNING) + return if not os.path.isdir(scriptPath): - self.env['runtime']['debug'].writeDebugOut("scriptpath not a directory:" + scriptPath ,debug.debugLevel.ERROR) - return + self.env['runtime']['debug'].writeDebugOut( + "scriptpath not a directory:" + scriptPath, debug.debugLevel.ERROR) + return if not os.access(scriptPath, os.R_OK): - self.env['runtime']['debug'].writeDebugOut("scriptpath not readable:" + scriptPath ,debug.debugLevel.ERROR) - return - commandList = glob.glob(scriptPath+'*') + self.env['runtime']['debug'].writeDebugOut( + "scriptpath not readable:" + scriptPath, debug.debugLevel.ERROR) + return + commandList = glob.glob(scriptPath + '*') subCommand = fenrirPath + '/commands/commands/subprocess.py' for command in commandList: invalid = False @@ -129,10 +170,18 @@ class commandManager(): continue if fileName.upper() in self.env['commands'][section]: continue - command_mod = module_utils.importModule(fileName ,subCommand) - self.env['commands'][section][fileName.upper()] = command_mod.command() - self.env['commands'][section][fileName.upper()].initialize(self.env,command) - self.env['runtime']['debug'].writeDebugOut("Load script:" + section + "." + fileName.upper() ,debug.debugLevel.INFO, onAnyLevel=True) + command_mod = module_utils.importModule(fileName, subCommand) + self.env['commands'][section][fileName.upper() + ] = command_mod.command() + self.env['commands'][section][fileName.upper()].initialize( + self.env, command) + self.env['runtime']['debug'].writeDebugOut( + "Load script:" + + section + + "." + + fileName.upper(), + debug.debugLevel.INFO, + onAnyLevel=True) commSettings = fileName.upper().split('__-__') if len(commSettings) == 1: keys = commSettings[0] @@ -144,27 +193,33 @@ class commandManager(): shortcutKeys = [] shortcut = [] for key in keys: - if not self.env['runtime']['inputManager'].isValidKey(key.upper()): - self.env['runtime']['debug'].writeDebugOut("invalid key : "+ key.upper() + ' script:' + fileName ,debug.debugLevel.WARNING) + if not self.env['runtime']['inputManager'].isValidKey( + key.upper()): + self.env['runtime']['debug'].writeDebugOut( + "invalid key : " + key.upper() + ' script:' + fileName, debug.debugLevel.WARNING) invalid = True break shortcutKeys.append(key.upper()) if invalid: continue - if not 'KEY_SCRIPT' in shortcutKeys: + if 'KEY_SCRIPT' not in shortcutKeys: shortcutKeys.append('KEY_SCRIPT') shortcut.append(1) - shortcut.append(sorted(shortcutKeys)) + shortcut.append(sorted(shortcutKeys)) self.env['bindings'][str(shortcut)] = fileName.upper() except Exception as e: - self.env['runtime']['debug'].writeDebugOut("Loading script:" + fileName ,debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "Loading script:" + fileName, debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) continue def shutdownCommands(self, section): # Check if the section exists in the commands dictionary if section not in self.env['commands']: - self.env['runtime']['debug'].writeDebugOut("shutdownCommands: section not found:" + section, debug.debugLevel.WARNING) + self.env['runtime']['debug'].writeDebugOut( + "shutdownCommands: section not found:" + section, + debug.debugLevel.WARNING) return for command in sorted(self.env['commands'][section]): @@ -172,31 +227,41 @@ class commandManager(): self.env['commands'][section][command].shutdown() del self.env['commands'][section][command] except Exception as e: - self.env['runtime']['debug'].writeDebugOut("Shutdown command:" + section + "." + command, debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "Shutdown command:" + section + "." + command, debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) continue def executeSwitchTrigger(self, trigger, unLoadScript, loadScript): if self.env['runtime']['screenManager'].isIgnoredScreen(): return - #unload + # unload oldScript = unLoadScript if self.commandExists(oldScript, trigger): try: - self.env['runtime']['debug'].writeDebugOut("Executing switchtrigger.unload:" + trigger + "." + oldScript ,debug.debugLevel.INFO) - self.env['commands'][trigger][oldScript].unload() + self.env['runtime']['debug'].writeDebugOut( + "Executing switchtrigger.unload:" + trigger + "." + oldScript, + debug.debugLevel.INFO) + self.env['commands'][trigger][oldScript].unload() except Exception as e: - self.env['runtime']['debug'].writeDebugOut("Executing trigger:" + trigger + "." + oldScript ,debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR) - #load + self.env['runtime']['debug'].writeDebugOut( + "Executing trigger:" + trigger + "." + oldScript, debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) + # load newScript = loadScript if self.commandExists(newScript, trigger): try: - self.env['runtime']['debug'].writeDebugOut("Executing switchtrigger.load:" + trigger + "." + newScript ,debug.debugLevel.INFO) - self.env['commands'][trigger][newScript].load() + self.env['runtime']['debug'].writeDebugOut( + "Executing switchtrigger.load:" + trigger + "." + newScript, + debug.debugLevel.INFO) + self.env['commands'][trigger][newScript].load() except Exception as e: - self.env['runtime']['debug'].writeDebugOut("Executing trigger:" + trigger + "." + newScript ,debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "Executing trigger:" + trigger + "." + newScript, debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) def executeDefaultTrigger(self, trigger, force=False): if not force: @@ -205,57 +270,73 @@ class commandManager(): for command in sorted(self.env['commands'][trigger]): if self.commandExists(command, trigger): try: - if self.env['commandsIgnore'][trigger][command[command.find('-')+1:]+'_IGNORE']: - self.env['commandsIgnore'][trigger][command[command.find('-')+1:]+'_IGNORE'] = False - self.env['runtime']['debug'].writeDebugOut("Ignore trigger.command:" + trigger + "." + command ,debug.debugLevel.INFO) + if self.env['commandsIgnore'][trigger][command[command.find( + '-') + 1:] + '_IGNORE']: + self.env['commandsIgnore'][trigger][command[command.find( + '-') + 1:] + '_IGNORE'] = False + self.env['runtime']['debug'].writeDebugOut( + "Ignore trigger.command:" + trigger + "." + command, debug.debugLevel.INFO) else: - self.env['runtime']['debug'].writeDebugOut("Executing trigger.command:" + trigger + "." + command ,debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "Executing trigger.command:" + trigger + "." + command, debug.debugLevel.INFO) self.env['commands'][trigger][command].run() except Exception as e: - self.env['runtime']['debug'].writeDebugOut("Executing trigger:" + trigger + "." + command + str(e) ,debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "Executing trigger:" + trigger + "." + command + str(e), debug.debugLevel.ERROR) - def executeCommand(self, command, section = 'commands'): + def executeCommand(self, command, section='commands'): if self.env['runtime']['screenManager'].isIgnoredScreen(): - return + return if self.commandExists(command, section): try: - if self.env['runtime']['helpManager'].isTutorialMode() and section != 'help': - self.env['runtime']['debug'].writeDebugOut("Tutorial for command:" + section + "." + command ,debug.debugLevel.INFO) + if self.env['runtime']['helpManager'].isTutorialMode( + ) and section != 'help': + self.env['runtime']['debug'].writeDebugOut( + "Tutorial for command:" + section + "." + command, debug.debugLevel.INFO) description = self.getCommandDescription(command, section) - self.env['runtime']['outputManager'].presentText(description, interrupt=False) + self.env['runtime']['outputManager'].presentText( + description, interrupt=False) else: - self.env['runtime']['debug'].writeDebugOut("Executing command:" + section + "." + command ,debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "Executing command:" + section + "." + command, debug.debugLevel.INFO) self.runCommand(command, section) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("Executing command:" + section + "." + command +' ' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "Executing command:" + section + "." + command + ' ' + str(e), + debug.debugLevel.ERROR) - - def runCommand(self, command, section = 'commands'): + def runCommand(self, command, section='commands'): if self.commandExists(command, section): try: - self.env['runtime']['debug'].writeDebugOut("runCommand command:" + section + "." + command ,debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "runCommand command:" + section + "." + command, debug.debugLevel.INFO) self.env['commands'][section][command].run() except Exception as e: - self.env['runtime']['debug'].writeDebugOut("runCommand command:" + section + "." + command +' ' + str(e),debug.debugLevel.ERROR) - self.env['commandInfo']['lastCommandExecutionTime'] = time.time() + self.env['runtime']['debug'].writeDebugOut( + "runCommand command:" + section + "." + command + ' ' + str(e), + debug.debugLevel.ERROR) + self.env['commandInfo']['lastCommandExecutionTime'] = time.time() - def getCommandDescription(self, command, section = 'commands'): + def getCommandDescription(self, command, section='commands'): if self.commandExists(command, section): try: return self.env['commands'][section][command].getDescription() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('commandManager.getCommandDescription:' + str(e),debug.debugLevel.ERROR) - self.env['commandInfo']['lastCommandExecutionTime'] = time.time() + self.env['runtime']['debug'].writeDebugOut( + 'commandManager.getCommandDescription:' + str(e), debug.debugLevel.ERROR) + self.env['commandInfo']['lastCommandExecutionTime'] = time.time() - def commandExists(self, command, section = 'commands'): + def commandExists(self, command, section='commands'): try: - return( command in self.env['commands'][section]) + return (command in self.env['commands'][section]) except Exception as e: return False - def getShortcutForCommand(self, command, formatKeys = False): + + def getShortcutForCommand(self, command, formatKeys=False): shortcut = [] try: - rawShortcut = list(self.env['bindings'].keys())[list(self.env['bindings'].values()).index(command)] + rawShortcut = list(self.env['bindings'].keys())[ + list(self.env['bindings'].values()).index(command)] # prefer numbers for multitap for k in ['2', '3', '4', '5', '6', '7', '8']: if k in rawShortcut: @@ -264,14 +345,21 @@ class commandManager(): formattedKey = formattedKey.lower() formattedKey += ' times ' shortcut.append(formattedKey) - rawShortcut.remove(k) + rawShortcut.remove(k) # prefer metha keys - for k in ['KEY_FENRIR', 'KEY_SCRIPT', 'KEY_CTRL', 'KEY_SHIFT', 'KEY_ALT', 'KEY_META']: + for k in [ + 'KEY_FENRIR', + 'KEY_SCRIPT', + 'KEY_CTRL', + 'KEY_SHIFT', + 'KEY_ALT', + 'KEY_META']: if k in rawShortcut: formattedKey = k if formatKeys: formattedKey = formattedKey.lower() - formattedKey = formattedKey.replace('key_kp', ' keypad ') + formattedKey = formattedKey.replace( + 'key_kp', ' keypad ') formattedKey = formattedKey.replace('key_', ' ') shortcut.append(formattedKey) rawShortcut.remove(k) @@ -282,7 +370,7 @@ class commandManager(): formattedKey = formattedKey.lower() formattedKey = formattedKey.replace('key_kp', ' keypad ') formattedKey = formattedKey.replace('key_', ' ') - shortcut.append(formattedKey) + shortcut.append(formattedKey) except Exception as e: pass - return shortcut + return shortcut diff --git a/src/fenrirscreenreader/core/cursorManager.py b/src/fenrirscreenreader/core/cursorManager.py index 69f10073..1ab0e9ee 100644 --- a/src/fenrirscreenreader/core/cursorManager.py +++ b/src/fenrirscreenreader/core/cursorManager.py @@ -6,11 +6,14 @@ from fenrirscreenreader.core import debug + class cursorManager(): def __init__(self): pass + def initialize(self, environment): self.env = environment + def shouldProcessNumpadCommands(self): """ Check if numpad commands should be processed based on numlock state @@ -19,19 +22,25 @@ class cursorManager(): """ # Return False if numlock is ON return not self.env['input']['newNumLock'] + def shutdown(self): pass + def clearMarks(self): self.env['commandBuffer']['Marks']['1'] = None self.env['commandBuffer']['Marks']['2'] = None + def isMarkSet(self): - return self.env['commandBuffer']['Marks']['1'] != None + return self.env['commandBuffer']['Marks']['1'] is not None + def isSingleMark(self): - return self.env['commandBuffer']['Marks']['1'] != None and \ - self.env['commandBuffer']['Marks']['2'] == None + return self.env['commandBuffer']['Marks']['1'] is not None and \ + self.env['commandBuffer']['Marks']['2'] is None + def isMultibleMark(self): - return self.env['commandBuffer']['Marks']['1'] != None and \ - self.env['commandBuffer']['Marks']['2'] != None + return self.env['commandBuffer']['Marks']['1'] is not None and \ + self.env['commandBuffer']['Marks']['2'] is not None + def setMark(self): currCursor = None if self.env['screen']['newCursorReview']: @@ -45,11 +54,13 @@ class cursorManager(): self.env['commandBuffer']['Marks']['2'] = currCursor.copy() return 2 return 0 + def getReviewOrTextCursor(self): if self.env['screen']['newCursorReview']: return self.env['screen']['newCursorReview'].copy() else: return self.env['screen']['newCursor'].copy() + def clearReviewCursor(self): if not self.isReviewMode(): return @@ -63,7 +74,7 @@ class cursorManager(): return self.env['screen']['newCursor']['y'] != self.env['screen']['oldCursor']['y'] def isReviewMode(self): - return self.env['screen']['newCursorReview'] != None + return self.env['screen']['newCursorReview'] is not None def enterReviewModeCurrTextCursor(self, overwrite=False): if self.isReviewMode() and not overwrite: @@ -71,9 +82,11 @@ class cursorManager(): self.env['screen']['oldCursorReview'] = self.env['screen']['newCursorReview'] if not self.env['screen']['newCursorReview']: self.env['screen']['newCursorReview'] = self.env['screen']['newCursor'].copy() - if self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'highlight') and \ - self.env['runtime']['attributeManager'].isAttributeCursorActive(): - self.env['screen']['newCursorReview'] = self.env['runtime']['attributeManager'].getCurrAttributeCursor().copy() + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'focus', + 'highlight') and self.env['runtime']['attributeManager'].isAttributeCursorActive(): + self.env['screen']['newCursorReview'] = self.env['runtime']['attributeManager'].getCurrAttributeCursor( + ).copy() def setReviewCursorPosition(self, x, y): if not self.isReviewMode(): @@ -84,18 +97,22 @@ class cursorManager(): def isApplicationWindowSet(self): try: - currApp = self.env['runtime']['applicationManager'].getCurrentApplication() - if self.env['commandBuffer']['windowArea'][currApp]['1'] != None: + currApp = self.env['runtime']['applicationManager'].getCurrentApplication( + ) + if self.env['commandBuffer']['windowArea'][currApp]['1'] is not None: return True except Exception as e: - self.env['runtime']['debug'].writeDebugOut('cursorManager isApplicationWindowSet: Error checking window area: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'cursorManager isApplicationWindowSet: Error checking window area: ' + str(e), + debug.debugLevel.ERROR) return False - def setWindowForApplication(self, start = None, end = None): + + def setWindowForApplication(self, start=None, end=None): x1 = 0 x2 = 0 y1 = 0 y2 = 0 - if start == None: + if start is None: if not self.env['commandBuffer']['Marks']['1']: return False else: @@ -104,32 +121,40 @@ class cursorManager(): else: x1 = start['x'] y1 = start['y'] - if end == None: + if end is None: if not self.env['commandBuffer']['Marks']['2']: return False else: x1 = self.env['commandBuffer']['Marks']['2']['x'] - y1 = self.env['commandBuffer']['Marks']['2']['y'] + y1 = self.env['commandBuffer']['Marks']['2']['y'] else: x1 = start['x'] - y1 = start['y'] + y1 = start['y'] currApp = self.env['runtime']['applicationManager'].getCurrentApplication() self.env['commandBuffer']['windowArea'][currApp] = {} if x1 * y1 <= \ - x2 * y2: - self.env['commandBuffer']['windowArea'][currApp]['1'] = {'x':x1, 'y':y1} - self.env['commandBuffer']['windowArea'][currApp]['2'] = {'x':x2, 'y':y2} + x2 * y2: + self.env['commandBuffer']['windowArea'][currApp]['1'] = { + 'x': x1, 'y': y1} + self.env['commandBuffer']['windowArea'][currApp]['2'] = { + 'x': x2, 'y': y2} else: - self.env['commandBuffer']['windowArea'][currApp]['1'] = {'x':x2, 'y':y2} - self.env['commandBuffer']['windowArea'][currApp]['2'] = {'x':x1, 'y':y1} - return True + self.env['commandBuffer']['windowArea'][currApp]['1'] = { + 'x': x2, 'y': y2} + self.env['commandBuffer']['windowArea'][currApp]['2'] = { + 'x': x1, 'y': y1} + return True + def clearWindowForApplication(self): currApp = self.env['runtime']['applicationManager'].getCurrentApplication() try: del self.env['commandBuffer']['windowArea'][currApp] except Exception as e: - self.env['runtime']['debug'].writeDebugOut('cursorManager clearWindowForApplication: Error clearing window area: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'cursorManager clearWindowForApplication: Error clearing window area: ' + + str(e), + debug.debugLevel.ERROR) return False - return True + return True diff --git a/src/fenrirscreenreader/core/debug.py b/src/fenrirscreenreader/core/debug.py index 7c7d0885..2cd5137e 100644 --- a/src/fenrirscreenreader/core/debug.py +++ b/src/fenrirscreenreader/core/debug.py @@ -2,12 +2,15 @@ from enum import Enum + class debugLevel(Enum): DEACTIVE = 0 ERROR = 1 WARNING = 2 INFO = 3 + def __int__(self): return self.value + def __str__(self): return self.name diff --git a/src/fenrirscreenreader/core/debugManager.py b/src/fenrirscreenreader/core/debugManager.py index 42d7d417..94b5016d 100644 --- a/src/fenrirscreenreader/core/debugManager.py +++ b/src/fenrirscreenreader/core/debugManager.py @@ -3,19 +3,25 @@ from fenrirscreenreader.core import debug from datetime import datetime -import pathlib, os +import pathlib +import os + class debugManager(): - def __init__(self, fileName = ''): + def __init__(self, fileName=''): self._file = None self._fileOpened = False - self._fileName = '/tmp/fenrir_' + str(os.getpid()) + '_' + str(datetime.utcnow().strftime('%Y-%m-%d_%H-%M-%S')) + '.log' + self._fileName = '/tmp/fenrir_' + \ + str(os.getpid()) + '_' + str(datetime.utcnow().strftime('%Y-%m-%d_%H-%M-%S')) + '.log' if fileName != '': self._fileName = fileName + def initialize(self, environment): self.env = environment + def shutdown(self): self.closeDebugFile() + def __del__(self): try: self.shutdown() @@ -23,7 +29,7 @@ class debugManager(): # Cannot use debug manager to log its own shutdown errors print(f'debugManager shutdown: Error during shutdown: {e}') - def openDebugFile(self, fileName = ''): + def openDebugFile(self, fileName=''): self._fileOpened = False if fileName != '': self._fileName = fileName @@ -32,23 +38,33 @@ class debugManager(): if not os.path.exists(directory): pathlib.Path(directory).mkdir(parents=True, exist_ok=True) try: - self._file = open(self._fileName,'a') + self._file = open(self._fileName, 'a') # Set readable permissions for all users (644) os.chmod(self._fileName, 0o644) self._fileOpened = True except Exception as e: print(e) - def writeDebugOut(self, text, level = debug.debugLevel.DEACTIVE, onAnyLevel=False): - mode = self.env['runtime']['settingsManager'].getSetting('general','debugMode') + def writeDebugOut( + self, + text, + level=debug.debugLevel.DEACTIVE, + onAnyLevel=False): + + mode = self.env['runtime']['settingsManager'].getSetting( + 'general', 'debugMode') if mode == '': - mode = 'FILE' + mode = 'FILE' mode = mode.upper().split(',') fileMode = 'FILE' in mode printMode = 'PRINT' in mode - if (self.env['runtime']['settingsManager'].getSettingAsInt('general','debugLevel') < int(level)) and \ - not (onAnyLevel and self.env['runtime']['settingsManager'].getSettingAsInt('general','debugLevel') > int(debug.debugLevel.DEACTIVE)) : + if ( + self.env['runtime']['settingsManager'].getSettingAsInt( + 'general', 'debugLevel') < int(level)) and not ( + onAnyLevel and self.env['runtime']['settingsManager'].getSettingAsInt( + 'general', 'debugLevel') > int( + debug.debugLevel.DEACTIVE)): if self._fileOpened: self.closeDebugFile() return @@ -58,27 +74,28 @@ class debugManager(): timestamp = str(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')) if onAnyLevel: levelInfo = 'INFO ANY' - else: + else: levelInfo = str(level) - + # Changed order: text comes first, then level and timestamp msg = text + ' - ' + levelInfo + ' ' + timestamp - + if printMode: print(msg) if fileMode: try: - self._file.write(msg + '\n') + self._file.write(msg + '\n') except Exception as e: print(e) + def closeDebugFile(self): if not self._fileOpened: return False - if self._file != None: + if self._file is not None: try: self._file.close() except Exception as e: - print(e) + print(e) self._fileOpened = False return True diff --git a/src/fenrirscreenreader/core/dynamicVoiceMenu.py b/src/fenrirscreenreader/core/dynamicVoiceMenu.py index 19610aa6..bdd2c101 100644 --- a/src/fenrirscreenreader/core/dynamicVoiceMenu.py +++ b/src/fenrirscreenreader/core/dynamicVoiceMenu.py @@ -4,155 +4,193 @@ import subprocess import importlib.util import os import time +from fenrirscreenreader.core import debug + class DynamicVoiceCommand: """Dynamic command class for voice selection""" + def __init__(self, module, voice, env): self.module = module self.voice = voice self.env = env self.testMessage = "This is a voice test. The quick brown fox jumps over the lazy dog." - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return f"Select voice: {self.voice}" - + def run(self): try: - self.env['runtime']['outputManager'].presentText(f"Testing voice {self.voice} from {self.module}. Please wait.", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"Testing voice { + self.voice} from { + self.module}. Please wait.", + interrupt=True) + # Brief pause before testing to avoid speech overlap time.sleep(0.5) - + # Test voice testResult, errorMsg = self.testVoice() if testResult: - self.env['runtime']['outputManager'].presentText("Voice test completed successfully. Navigate to Apply Tested Voice to use this voice.", interrupt=False, flush=False) - - # Store for confirmation (use same variables as apply_tested_voice.py) + self.env['runtime']['outputManager'].presentText( + "Voice test completed successfully. Navigate to Apply Tested Voice to use this voice.", + interrupt=False, + flush=False) + + # Store for confirmation (use same variables as + # apply_tested_voice.py) self.env['commandBuffer']['lastTestedModule'] = self.module self.env['commandBuffer']['lastTestedVoice'] = self.voice self.env['commandBuffer']['pendingVoiceModule'] = self.module self.env['commandBuffer']['pendingVoiceVoice'] = self.voice self.env['commandBuffer']['voiceTestCompleted'] = True else: - self.env['runtime']['outputManager'].presentText(f"Voice test failed: {errorMsg}", interrupt=False, flush=False) - + self.env['runtime']['outputManager'].presentText( + f"Voice test failed: {errorMsg}", interrupt=False, flush=False) + except Exception as e: - self.env['runtime']['outputManager'].presentText(f"Voice selection error: {str(e)}", interrupt=False, flush=False) - + self.env['runtime']['outputManager'].presentText( + f"Voice selection error: {str(e)}", interrupt=False, flush=False) + def testVoice(self): """Test voice with spd-say""" try: - cmd = ['spd-say', '-C', '-w', '-o', self.module, '-y', self.voice, self.testMessage] - result = subprocess.run(cmd, timeout=8, capture_output=True, text=True) + cmd = [ + 'spd-say', + '-C', + '-w', + '-o', + self.module, + '-y', + self.voice, + self.testMessage] + result = subprocess.run( + cmd, timeout=8, capture_output=True, text=True) if result.returncode == 0: return True, "Voice test successful" else: - error_msg = result.stderr.strip() if result.stderr else f"Command failed with return code {result.returncode}" + error_msg = result.stderr.strip( + ) if result.stderr else f"Command failed with return code {result.returncode}" return False, error_msg except subprocess.TimeoutExpired: return False, "Voice test timed out" except Exception as e: return False, f"Error running voice test: {str(e)}" - + def setCallback(self, callback): pass + class DynamicApplyVoiceCommand: """Command to apply the tested voice""" + def __init__(self, env): self.env = env - + def initialize(self, environment): self.env = environment - + def shutdown(self): pass - + def getDescription(self): return "Apply tested voice to Fenrir" - + def run(self): try: if not self.env['commandBuffer'].get('voiceTestCompleted', False): - self.env['runtime']['outputManager'].presentText("No voice has been tested yet", interrupt=True) + self.env['runtime']['outputManager'].presentText( + "No voice has been tested yet", interrupt=True) return - + module = self.env['commandBuffer']['pendingVoiceModule'] voice = self.env['commandBuffer']['pendingVoiceVoice'] - - self.env['runtime']['outputManager'].presentText(f"Applying {voice} from {module}", interrupt=True) - + + self.env['runtime']['outputManager'].presentText( + f"Applying {voice} from {module}", interrupt=True) + # Debug: Show current settings settingsManager = self.env['runtime']['settingsManager'] currentModule = settingsManager.getSetting('speech', 'module') currentVoice = settingsManager.getSetting('speech', 'voice') - self.env['runtime']['outputManager'].presentText(f"Current: {currentVoice} from {currentModule}", interrupt=False, flush=False) - + self.env['runtime']['outputManager'].presentText( + f"Current: {currentVoice} from {currentModule}", interrupt=False, flush=False) + # Apply to runtime settings with fallback settingsManager = self.env['runtime']['settingsManager'] - + # Store old values for safety oldDriver = settingsManager.getSetting('speech', 'driver') oldModule = settingsManager.getSetting('speech', 'module') oldVoice = settingsManager.getSetting('speech', 'voice') - + try: - # Apply new settings to runtime only (use setSetting to update settingArgDict) + # Apply new settings to runtime only (use setSetting to update + # settingArgDict) settingsManager.setSetting('speech', 'driver', 'speechdDriver') settingsManager.setSetting('speech', 'module', module) settingsManager.setSetting('speech', 'voice', voice) - + # Apply settings to speech driver directly if 'speechDriver' in self.env['runtime']: speechDriver = self.env['runtime']['speechDriver'] - + # Get current module to see if we're changing modules - currentModule = settingsManager.getSetting('speech', 'module') + currentModule = settingsManager.getSetting( + 'speech', 'module') moduleChanging = (currentModule != module) - + # Set module and voice on driver instance first speechDriver.setModule(module) speechDriver.setVoice(voice) - + if moduleChanging: - # Module change requires reinitializing the speech driver - self.env['runtime']['outputManager'].presentText(f"Switching from {currentModule} to {module} module", interrupt=True) + # Module change requires reinitializing the speech + # driver + self.env['runtime']['outputManager'].presentText( + f"Switching from {currentModule} to {module} module", interrupt=True) speechDriver.shutdown() speechDriver.initialize(self.env) # Re-set after initialization speechDriver.setModule(module) speechDriver.setVoice(voice) - self.env['runtime']['outputManager'].presentText("Speech driver reinitialized", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + "Speech driver reinitialized", interrupt=True) + # Debug: verify what was actually set - self.env['runtime']['outputManager'].presentText(f"Speech driver now has module: {speechDriver.module}, voice: {speechDriver.voice}", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + f"Speech driver now has module: { + speechDriver.module}, voice: { + speechDriver.voice}", interrupt=True) + # Force application by speaking a test message - self.env['runtime']['outputManager'].presentText("Voice applied successfully! You should hear this in the new voice.", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + "Voice applied successfully! You should hear this in the new voice.", interrupt=True) + # Brief pause then more speech to test time.sleep(1) - self.env['runtime']['outputManager'].presentText("Use save settings to make permanent", interrupt=True) - + self.env['runtime']['outputManager'].presentText( + "Use save settings to make permanent", interrupt=True) + # Clear pending state self.env['commandBuffer']['voiceTestCompleted'] = False - + # Exit vmenu after successful application self.env['runtime']['vmenuManager'].setActive(False) - + except Exception as e: # Revert on failure settingsManager.settings['speech']['driver'] = oldDriver settingsManager.settings['speech']['module'] = oldModule settingsManager.settings['speech']['voice'] = oldVoice - + # Try to reinitialize with old settings if 'speechDriver' in self.env['runtime']: try: @@ -160,75 +198,89 @@ class DynamicApplyVoiceCommand: speechDriver.shutdown() speechDriver.initialize(self.env) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('dynamicVoiceMenu: Error reinitializing speech driver: ' + str(e), debug.debugLevel.ERROR) - - self.env['runtime']['outputManager'].presentText(f"Failed to apply voice, reverted: {str(e)}", interrupt=False, flush=False) - + self.env['runtime']['debug'].writeDebugOut( + 'dynamicVoiceMenu: Error reinitializing speech driver: ' + str(e), + debug.debugLevel.ERROR) + + self.env['runtime']['outputManager'].presentText( + f"Failed to apply voice, reverted: { + str(e)}", interrupt=False, flush=False) + except Exception as e: - self.env['runtime']['outputManager'].presentText(f"Apply voice error: {str(e)}", interrupt=False, flush=False) - + self.env['runtime']['outputManager'].presentText( + f"Apply voice error: {str(e)}", interrupt=False, flush=False) + def setCallback(self, callback): pass + def addDynamicVoiceMenus(vmenuManager): """Add dynamic voice menus to vmenu system""" try: env = vmenuManager.env - + # Get speech modules modules = getSpeechdModules() if not modules: return - + # Create voice browser submenu voiceBrowserMenu = {} - + # Add apply voice command applyCommand = DynamicApplyVoiceCommand(env) voiceBrowserMenu['Apply Tested Voice Action'] = applyCommand - + # Add modules as submenus for module in modules[:8]: # Limit to 8 modules to keep menu manageable moduleMenu = {} - + # Get voices for this module voices = getModuleVoices(module) if voices: - + # Add voice commands for voice in voices: voiceCommand = DynamicVoiceCommand(module, voice, env) moduleMenu[f"{voice} Action"] = voiceCommand else: - moduleMenu['No voices available Action'] = createInfoCommand(f"No voices found for {module}", env) - + moduleMenu['No voices available Action'] = createInfoCommand( + f"No voices found for {module}", env) + voiceBrowserMenu[f"{module} Menu"] = moduleMenu - + # Add to main menu dict vmenuManager.menuDict['Voice Browser Menu'] = voiceBrowserMenu - + except Exception as e: print(f"Error creating dynamic voice menus: {e}") + def createInfoCommand(message, env): """Create a simple info command""" class InfoCommand: def __init__(self, message, env): self.message = message self.env = env + def initialize(self, environment): pass def shutdown(self): pass def getDescription(self): return self.message - def run(self): - self.env['runtime']['outputManager'].presentText(self.message, interrupt=True) + + def run(self): + self.env['runtime']['outputManager'].presentText( + self.message, interrupt=True) + def setCallback(self, callback): pass - + return InfoCommand(message, env) + def getSpeechdModules(): """Get available speech modules""" try: - result = subprocess.run(['spd-say', '-O'], capture_output=True, text=True, timeout=5) + result = subprocess.run( + ['spd-say', '-O'], capture_output=True, text=True, timeout=5) if result.returncode == 0: lines = result.stdout.strip().split('\n') return [line.strip() for line in lines[1:] if line.strip()] @@ -236,10 +288,12 @@ def getSpeechdModules(): pass return [] + def getModuleVoices(module): """Get voices for a module""" try: - result = subprocess.run(['spd-say', '-o', module, '-L'], capture_output=True, text=True, timeout=8) + result = subprocess.run( + ['spd-say', '-o', module, '-L'], capture_output=True, text=True, timeout=8) if result.returncode == 0: lines = result.stdout.strip().split('\n') voices = [] @@ -257,6 +311,7 @@ def getModuleVoices(module): pass return [] + def processEspeakVoice(voiceLine): """Process espeak voice format""" try: @@ -267,4 +322,4 @@ def processEspeakVoice(voiceLine): variant = parts[-1].lower() return f"{langCode}+{variant}" if variant and variant != 'none' else langCode except Exception: - return None \ No newline at end of file + return None diff --git a/src/fenrirscreenreader/core/environment.py b/src/fenrirscreenreader/core/environment.py index 27f356d9..4108350c 100644 --- a/src/fenrirscreenreader/core/environment.py +++ b/src/fenrirscreenreader/core/environment.py @@ -15,16 +15,16 @@ from fenrirscreenreader.core.inputData import inputData from fenrirscreenreader.core.punctuationData import punctuationData environment = { -'screen': screenData, -'runtime': runtimeData, -'general': generalData, -'settings': settingsData, -'commandInfo': commandData.commandInfo, -'commandBuffer': commandData.commandBuffer, -'input': inputData, -'punctuation': punctuationData, -'output': outputData, -'soundIcons': {}, -'bindings': {}, -'rawBindings': {}, + 'screen': screenData, + 'runtime': runtimeData, + 'general': generalData, + 'settings': settingsData, + 'commandInfo': commandData.commandInfo, + 'commandBuffer': commandData.commandBuffer, + 'input': inputData, + 'punctuation': punctuationData, + 'output': outputData, + 'soundIcons': {}, + 'bindings': {}, + 'rawBindings': {}, } diff --git a/src/fenrirscreenreader/core/eventData.py b/src/fenrirscreenreader/core/eventData.py index 0dafeeca..9227f31a 100644 --- a/src/fenrirscreenreader/core/eventData.py +++ b/src/fenrirscreenreader/core/eventData.py @@ -7,6 +7,7 @@ from fenrirscreenreader.core import debug from enum import Enum + class fenrirEventType(Enum): Ignore = 0 StopMainLoop = 1 @@ -18,7 +19,9 @@ class fenrirEventType(Enum): ExecuteCommand = 7 ByteInput = 8 RemoteIncomming = 9 + def __int__(self): return self.value + def __str__(self): return self.name diff --git a/src/fenrirscreenreader/core/eventManager.py b/src/fenrirscreenreader/core/eventManager.py index 94ae82cc..937863cb 100644 --- a/src/fenrirscreenreader/core/eventManager.py +++ b/src/fenrirscreenreader/core/eventManager.py @@ -12,23 +12,29 @@ from multiprocessing import Queue from multiprocessing.sharedctypes import Value from ctypes import c_bool + class eventManager(): def __init__(self): - self.running = Value(c_bool, True) - self._eventQueue = Queue(maxsize=100) # Bounded queue to prevent memory exhaustion + self.running = Value(c_bool, True) + # Bounded queue to prevent memory exhaustion + self._eventQueue = Queue(maxsize=100) self.cleanEventQueue() + def initialize(self, environment): self.env = environment + def shutdown(self): - self.cleanEventQueue() + self.cleanEventQueue() def proceedEventLoop(self): event = self._eventQueue.get() st = time.time() self.eventDispatcher(event) - #print('NET loop ' + str(time.time() - st)) + # print('NET loop ' + str(time.time() - st)) + def eventDispatcher(self, event): - self.env['runtime']['debug'].writeDebugOut('eventManager:eventDispatcher:start: event: ' + str(event['Type']),debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'eventManager:eventDispatcher:start: event: ' + str(event['Type']), debug.debugLevel.INFO) if not event: return @@ -54,18 +60,23 @@ class eventManager(): self.env['runtime']['fenrirManager'].handleByteInput(event) elif event['Type'] == fenrirEventType.RemoteIncomming: self.env['runtime']['fenrirManager'].handleRemoteIncomming(event) + def isMainEventLoopRunning(self): return self.running.value == 1 + def startMainEventLoop(self): self.running.value = 1 - while( self.isMainEventLoopRunning()): + while (self.isMainEventLoopRunning()): self.proceedEventLoop() def handleStopMainLoop(self, event): - self.running.value = 0 + self.running.value = 0 time.sleep(0.1) + def stopMainEventLoop(self): - self._eventQueue.put({"Type":fenrirEventType.StopMainLoop,"Data":None}) + self._eventQueue.put( + {"Type": fenrirEventType.StopMainLoop, "Data": None}) + def cleanEventQueue(self): if self._eventQueue.empty(): return @@ -74,27 +85,36 @@ class eventManager(): self._eventQueue.get_nowait() except Empty: pass + def getEventQueue(self): return self._eventQueue + def getRunning(self): return self.running + def getEventQueueSize(self): return self._eventQueue.qsize() - def putToEventQueue(self,event, data): + + def putToEventQueue(self, event, data): if not isinstance(event, fenrirEventType): return False if event == fenrirEventType.Ignore: return False - # Use bounded queue - if full, this will block briefly or drop older events + # Use bounded queue - if full, this will block briefly or drop older + # events try: - self._eventQueue.put({"Type":event,"Data":data}, timeout=0.1) + self._eventQueue.put({"Type": event, "Data": data}, timeout=0.1) except Exception as e: - # Queue full - drop oldest event and add new one for critical events - if event in [fenrirEventType.ScreenUpdate, fenrirEventType.KeyboardInput]: + # Queue full - drop oldest event and add new one for critical + # events + if event in [ + fenrirEventType.ScreenUpdate, + fenrirEventType.KeyboardInput]: try: self._eventQueue.get_nowait() # Remove oldest - self._eventQueue.put({"Type":event,"Data":data}, timeout=0.1) - except: + self._eventQueue.put( + {"Type": event, "Data": data}, timeout=0.1) + except BaseException: pass # If still can't add, drop the event # For non-critical events, just drop them if queue is full return True diff --git a/src/fenrirscreenreader/core/fenrirManager.py b/src/fenrirscreenreader/core/fenrirManager.py index 9f320a9c..bf8374f2 100644 --- a/src/fenrirscreenreader/core/fenrirManager.py +++ b/src/fenrirscreenreader/core/fenrirManager.py @@ -9,22 +9,25 @@ import time import os import sys -from fenrirscreenreader.core import i18n +from fenrirscreenreader.core.i18n import _ from fenrirscreenreader.core import settingsManager from fenrirscreenreader.core import debug from fenrirscreenreader.core.eventData import fenrirEventType + class fenrirManager(): def __init__(self, cliArgs): self.isInitialized = False try: self.environment = settingsManager.settingsManager().initFenrirConfig(cliArgs, self) if not self.environment: - raise RuntimeError('Cannot Initialize. Maybe the configfile is not available or not parseable') + raise RuntimeError( + 'Cannot Initialize. Maybe the configfile is not available or not parseable') except RuntimeError: raise - self.environment['runtime']['outputManager'].presentText(_("Start Fenrir"), soundIcon='ScreenReaderOn', interrupt=True) + self.environment['runtime']['outputManager'].presentText( + _("Start Fenrir"), soundIcon='ScreenReaderOn', interrupt=True) signal.signal(signal.SIGINT, self.captureSignal) signal.signal(signal.SIGTERM, self.captureSignal) @@ -41,26 +44,30 @@ class fenrirManager(): self.shutdown() def handleInput(self, event): - self.environment['runtime']['debug'].writeDebugOut('DEBUG INPUT fenrirMan:' + str(event), debug.debugLevel.INFO) + self.environment['runtime']['debug'].writeDebugOut( + 'DEBUG INPUT fenrirMan:' + str(event), debug.debugLevel.INFO) if not event['Data']: event['Data'] = self.environment['runtime']['inputManager'].getInputEvent() if event['Data']: - event['Data']['EventName'] = self.environment['runtime']['inputManager'].convertEventName(event['Data']['EventName']) - self.environment['runtime']['inputManager'].handleInputEvent(event['Data']) + event['Data']['EventName'] = self.environment['runtime']['inputManager'].convertEventName( + event['Data']['EventName']) + self.environment['runtime']['inputManager'].handleInputEvent( + event['Data']) else: return - if self.environment['runtime']['inputManager'].noKeyPressed(): + if self.environment['runtime']['inputManager'].noKeyPressed(): self.environment['runtime']['inputManager'].clearLastDeepInput() if self.environment['runtime']['screenManager'].isIgnoredScreen(): self.environment['runtime']['inputManager'].writeEventBuffer() - else: + else: if self.environment['runtime']['helpManager'].isTutorialMode(): self.environment['runtime']['inputManager'].clearEventBuffer() - self.environment['runtime']['inputManager'].keyEcho(event['Data']) + self.environment['runtime']['inputManager'].keyEcho( + event['Data']) if self.environment['runtime']['vmenuManager'].getActive(): self.environment['runtime']['inputManager'].clearEventBuffer() @@ -68,10 +75,10 @@ class fenrirManager(): self.detectShortcutCommand() if self.modifierInput: - self.environment['runtime']['inputManager'].clearEventBuffer() + self.environment['runtime']['inputManager'].clearEventBuffer() if self.singleKeyCommand: if self.environment['runtime']['inputManager'].noKeyPressed(): - self.environment['runtime']['inputManager'].clearEventBuffer() + self.environment['runtime']['inputManager'].clearEventBuffer() else: self.environment['runtime']['inputManager'].writeEventBuffer() @@ -84,13 +91,16 @@ class fenrirManager(): if self.environment['input']['keyForeward'] > 0: self.environment['input']['keyForeward'] -= 1 - self.environment['runtime']['commandManager'].executeDefaultTrigger('onKeyInput') + self.environment['runtime']['commandManager'].executeDefaultTrigger( + 'onKeyInput') def handleByteInput(self, event): if not event['Data'] or event['Data'] == b'': return - self.environment['runtime']['byteManager'].handleByteInput(event['Data']) - self.environment['runtime']['commandManager'].executeDefaultTrigger('onByteInput') + self.environment['runtime']['byteManager'].handleByteInput( + event['Data']) + self.environment['runtime']['commandManager'].executeDefaultTrigger( + 'onByteInput') def handleExecuteCommand(self, event): if not event['Data'] or event['Data'] == '': @@ -99,71 +109,96 @@ class fenrirManager(): # special modes if self.environment['runtime']['helpManager'].isTutorialMode(): - if self.environment['runtime']['commandManager'].commandExists(currentCommand, 'help'): - self.environment['runtime']['commandManager'].executeCommand(currentCommand, 'help') + if self.environment['runtime']['commandManager'].commandExists( + currentCommand, 'help'): + self.environment['runtime']['commandManager'].executeCommand( + currentCommand, 'help') return elif self.environment['runtime']['vmenuManager'].getActive(): - if self.environment['runtime']['commandManager'].commandExists(currentCommand, 'vmenu-navigation'): - self.environment['runtime']['commandManager'].executeCommand(currentCommand, 'vmenu-navigation') + if self.environment['runtime']['commandManager'].commandExists( + currentCommand, 'vmenu-navigation'): + self.environment['runtime']['commandManager'].executeCommand( + currentCommand, 'vmenu-navigation') return # default - self.environment['runtime']['commandManager'].executeCommand(currentCommand, 'commands') + self.environment['runtime']['commandManager'].executeCommand( + currentCommand, 'commands') def handleRemoteIncomming(self, event): if not event['Data']: return - self.environment['runtime']['remoteManager'].handleRemoteIncomming(event['Data']) + self.environment['runtime']['remoteManager'].handleRemoteIncomming( + event['Data']) def handleScreenChange(self, event): - self.environment['runtime']['screenManager'].handleScreenChange(event['Data']) + self.environment['runtime']['screenManager'].handleScreenChange( + event['Data']) if self.environment['runtime']['vmenuManager'].getActive(): return - self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenChanged') + self.environment['runtime']['commandManager'].executeDefaultTrigger( + 'onScreenChanged') self.environment['runtime']['screenDriver'].getCurrScreen() def handleScreenUpdate(self, event): - self.environment['runtime']['screenManager'].handleScreenUpdate(event['Data']) + self.environment['runtime']['screenManager'].handleScreenUpdate( + event['Data']) - if time.time() - self.environment['runtime']['inputManager'].getLastInputTime() >= 0.3: + if time.time() - \ + self.environment['runtime']['inputManager'].getLastInputTime() >= 0.3: self.environment['runtime']['inputManager'].clearLastDeepInput() - if (self.environment['runtime']['cursorManager'].isCursorVerticalMove() or - self.environment['runtime']['cursorManager'].isCursorHorizontalMove()): - self.environment['runtime']['commandManager'].executeDefaultTrigger('onCursorChange') + if (self.environment['runtime']['cursorManager'].isCursorVerticalMove( + ) or self.environment['runtime']['cursorManager'].isCursorHorizontalMove()): + self.environment['runtime']['commandManager'].executeDefaultTrigger( + 'onCursorChange') - self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenUpdate') + self.environment['runtime']['commandManager'].executeDefaultTrigger( + 'onScreenUpdate') self.environment['runtime']['inputManager'].clearLastDeepInput() def handlePlugInputDevice(self, event): try: - self.environment['runtime']['inputManager'].setLastDetectedDevices(event['Data']) + self.environment['runtime']['inputManager'].setLastDetectedDevices( + event['Data']) except Exception as e: - self.environment['runtime']['debug'].writeDebugOut('handlePlugInputDevice: Error setting last detected devices: ' + str(e), debug.debugLevel.ERROR) - self.environment['runtime']['inputManager'].handlePlugInputDevice(event['Data']) - self.environment['runtime']['commandManager'].executeDefaultTrigger('onPlugInputDevice', force=True) - self.environment['runtime']['inputManager'].setLastDetectedDevices(None) + self.environment['runtime']['debug'].writeDebugOut( + 'handlePlugInputDevice: Error setting last detected devices: ' + str(e), + debug.debugLevel.ERROR) + self.environment['runtime']['inputManager'].handlePlugInputDevice( + event['Data']) + self.environment['runtime']['commandManager'].executeDefaultTrigger( + 'onPlugInputDevice', force=True) + self.environment['runtime']['inputManager'].setLastDetectedDevices( + None) def handleHeartBeat(self, event): - self.environment['runtime']['commandManager'].executeDefaultTrigger('onHeartBeat', force=True) + self.environment['runtime']['commandManager'].executeDefaultTrigger( + 'onHeartBeat', force=True) def detectShortcutCommand(self): if self.environment['input']['keyForeward'] > 0: return - if len(self.environment['input']['prevInput']) > len(self.environment['input']['currInput']): + if len(self.environment['input']['prevInput']) > len( + self.environment['input']['currInput']): return if self.environment['runtime']['inputManager'].isKeyPress(): - self.modifierInput = self.environment['runtime']['inputManager'].currKeyIsModifier() + self.modifierInput = self.environment['runtime']['inputManager'].currKeyIsModifier( + ) else: if not self.environment['runtime']['inputManager'].noKeyPressed(): if self.singleKeyCommand: - self.singleKeyCommand = len(self.environment['input']['currInput']) == 1 + self.singleKeyCommand = len( + self.environment['input']['currInput']) == 1 - if not(self.singleKeyCommand and self.environment['runtime']['inputManager'].noKeyPressed()): - currentShortcut = self.environment['runtime']['inputManager'].getCurrShortcut() - self.command = self.environment['runtime']['inputManager'].getCommandForShortcut(currentShortcut) + if not ( + self.singleKeyCommand and self.environment['runtime']['inputManager'].noKeyPressed()): + currentShortcut = self.environment['runtime']['inputManager'].getCurrShortcut( + ) + self.command = self.environment['runtime']['inputManager'].getCommandForShortcut( + currentShortcut) if not self.modifierInput: if self.environment['runtime']['inputManager'].isKeyPress(): @@ -176,11 +211,13 @@ class fenrirManager(): # fire event if self.command != '': if self.modifierInput: - self.environment['runtime']['eventManager'].putToEventQueue(fenrirEventType.ExecuteCommand, self.command) + self.environment['runtime']['eventManager'].putToEventQueue( + fenrirEventType.ExecuteCommand, self.command) self.command = '' else: if self.singleKeyCommand: - self.environment['runtime']['eventManager'].putToEventQueue(fenrirEventType.ExecuteCommand, self.command) + self.environment['runtime']['eventManager'].putToEventQueue( + fenrirEventType.ExecuteCommand, self.command) self.command = '' def setProcessName(self, name='fenrir'): @@ -201,7 +238,8 @@ class fenrirManager(): libc.prctl(15, byref(stringBuffer), 0, 0, 0) return True except Exception as e: - self.environment['runtime']['debug'].writeDebugOut('setProcName: Error setting process name: ' + str(e), debug.debugLevel.ERROR) + self.environment['runtime']['debug'].writeDebugOut( + 'setProcName: Error setting process name: ' + str(e), debug.debugLevel.ERROR) return False @@ -209,7 +247,9 @@ class fenrirManager(): try: self.environment['runtime']['eventManager'].stopMainEventLoop() except Exception as e: - self.environment['runtime']['debug'].writeDebugOut('shutdownRequest: Error stopping main event loop: ' + str(e), debug.debugLevel.ERROR) + self.environment['runtime']['debug'].writeDebugOut( + 'shutdownRequest: Error stopping main event loop: ' + str(e), + debug.debugLevel.ERROR) def captureSignal(self, sigInit, frame): self.shutdownRequest() @@ -217,7 +257,8 @@ class fenrirManager(): def shutdown(self): self.environment['runtime']['inputManager'].ungrabAllDevices() self.environment['runtime']['eventManager'].stopMainEventLoop() - self.environment['runtime']['outputManager'].presentText(_("Quit Fenrir"), soundIcon='ScreenReaderOff', interrupt=True) + self.environment['runtime']['outputManager'].presentText( + _("Quit Fenrir"), soundIcon='ScreenReaderOff', interrupt=True) self.environment['runtime']['eventManager'].cleanEventQueue() time.sleep(0.6) diff --git a/src/fenrirscreenreader/core/generalData.py b/src/fenrirscreenreader/core/generalData.py index b7d75a3b..091682dd 100644 --- a/src/fenrirscreenreader/core/generalData.py +++ b/src/fenrirscreenreader/core/generalData.py @@ -7,12 +7,37 @@ from fenrirscreenreader.core import debug generalData = { -'args': None, -'tutorialMode': False, -'currUser':'', -'prevUser':'', -'managerList':[ 'attributeManager','punctuationManager', 'byteManager', 'cursorManager', 'applicationManager', 'commandManager' - , 'screenManager', 'inputManager','outputManager', 'helpManager', 'memoryManager', 'eventManager','processManager', 'debug'], -'commandFolderList':['commands','onKeyInput', 'onByteInput', 'onCursorChange', 'onScreenUpdate','onScreenChanged','onHeartBeat', 'onPlugInputDevice' - ,'onApplicationChange','onSwitchApplicationProfile','help','vmenu-navigation',], + 'args': None, + 'tutorialMode': False, + 'currUser': '', + 'prevUser': '', + 'managerList': [ + 'attributeManager', + 'punctuationManager', + 'byteManager', + 'cursorManager', + 'applicationManager', + 'commandManager', + 'screenManager', + 'inputManager', + 'outputManager', + 'helpManager', + 'memoryManager', + 'eventManager', + 'processManager', + 'debug'], + 'commandFolderList': [ + 'commands', + 'onKeyInput', + 'onByteInput', + 'onCursorChange', + 'onScreenUpdate', + 'onScreenChanged', + 'onHeartBeat', + 'onPlugInputDevice', + 'onApplicationChange', + 'onSwitchApplicationProfile', + 'help', + 'vmenu-navigation', + ], } diff --git a/src/fenrirscreenreader/core/helpManager.py b/src/fenrirscreenreader/core/helpManager.py index e28b5671..e9273dbd 100755 --- a/src/fenrirscreenreader/core/helpManager.py +++ b/src/fenrirscreenreader/core/helpManager.py @@ -5,47 +5,65 @@ # By Chrys, Storm Dragon, and contributers. from fenrirscreenreader.core import debug +from fenrirscreenreader.core.i18n import _ class helpManager(): def __init__(self): self.helpDict = {} self.tutorialListIndex = None + def initialize(self, environment): self.env = environment + def shutdown(self): - pass + pass + def toggleTutorialMode(self): self.setTutorialMode(not self.env['general']['tutorialMode']) + def setTutorialMode(self, newTutorialMode): if self.env['runtime']['vmenuManager'].getActive(): return self.env['general']['tutorialMode'] = newTutorialMode if newTutorialMode: self.createHelpDict() - self.env['bindings'][str([1, ['KEY_ESC']])] = 'TOGGLE_TUTORIAL_MODE' + self.env['bindings'][str([1, ['KEY_ESC']]) + ] = 'TOGGLE_TUTORIAL_MODE' self.env['bindings'][str([1, ['KEY_UP']])] = 'PREV_HELP' self.env['bindings'][str([1, ['KEY_DOWN']])] = 'NEXT_HELP' self.env['bindings'][str([1, ['KEY_SPACE']])] = 'CURR_HELP' else: try: - self.env['bindings'] = self.env['runtime']['settingsManager'].getBindingBackup() + self.env['bindings'] = self.env['runtime']['settingsManager'].getBindingBackup( + ) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('helpManager setTutorialMode: Error restoring binding backup: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'helpManager setTutorialMode: Error restoring binding backup: ' + str(e), + debug.debugLevel.ERROR) + def isTutorialMode(self): return self.env['general']['tutorialMode'] + def getFormattedShortcutForCommand(self, command): shortcut = [] rawShortcut = [] try: - rawShortcut = list(self.env['bindings'].keys())[list(self.env['bindings'].values()).index(command)] + rawShortcut = list(self.env['bindings'].keys())[ + list(self.env['bindings'].values()).index(command)] rawShortcut = self.env['rawBindings'][rawShortcut] # prefer numbers for multitap if rawShortcut[0] in range(2, 9): - formattedKey = str(rawShortcut[0]) +' times ' + formattedKey = str(rawShortcut[0]) + ' times ' shortcut.append(formattedKey) # prefer metha keys - for k in ['KEY_FENRIR', 'KEY_SCRIPT', 'KEY_CTRL', 'KEY_SHIFT', 'KEY_ALT', 'KEY_META']: + for k in [ + 'KEY_FENRIR', + 'KEY_SCRIPT', + 'KEY_CTRL', + 'KEY_SHIFT', + 'KEY_ALT', + 'KEY_META']: if k in rawShortcut[1]: formattedKey = k formattedKey = formattedKey.lower() @@ -63,48 +81,55 @@ class helpManager(): except Exception as e: return '' shortcut = str(shortcut) - shortcut = shortcut.replace('[','') - shortcut = shortcut.replace(']','') - shortcut = shortcut.replace("'",'') + shortcut = shortcut.replace('[', '') + shortcut = shortcut.replace(']', '') + shortcut = shortcut.replace("'", '') return shortcut - def getCommandHelpText(self, command, section = 'commands'): + def getCommandHelpText(self, command, section='commands'): commandName = command.lower() commandName = commandName.split('__-__')[0] - commandName = commandName.replace('_',' ') - commandName = commandName.replace('_',' ') + commandName = commandName.replace('_', ' ') + commandName = commandName.replace('_', ' ') if command == 'TOGGLE_TUTORIAL_MODE': commandDescription = _('toggles the tutorial mode') else: - commandDescription = self.env['runtime']['commandManager'].getCommandDescription(command, section = 'commands') + commandDescription = self.env['runtime']['commandManager'].getCommandDescription( + command, section='commands') if commandDescription == '': commandDescription = 'no Description available' commandShortcut = self.getFormattedShortcutForCommand(command) if commandShortcut == '': commandShortcut = 'unbound' - helptext = commandName + ', Shortcut ' + commandShortcut + ', Description ' + commandDescription + helptext = commandName + ', Shortcut ' + \ + commandShortcut + ', Description ' + commandDescription return helptext - def createHelpDict(self, section = 'commands'): + + def createHelpDict(self, section='commands'): self.helpDict = {} for command in sorted(self.env['commands'][section].keys()): - self.helpDict[len(self.helpDict)] = self.getCommandHelpText(command, section) + self.helpDict[len(self.helpDict)] = self.getCommandHelpText( + command, section) if len(self.helpDict) > 0: self.tutorialListIndex = 0 else: self.tutorialListIndex = None + def getHelpForCurrentIndex(self): - if self.tutorialListIndex == None: - return '' + if self.tutorialListIndex is None: + return '' return self.helpDict[self.tutorialListIndex] + def nextIndex(self): - if self.tutorialListIndex == None: - return + if self.tutorialListIndex is None: + return self.tutorialListIndex += 1 if self.tutorialListIndex >= len(self.helpDict): - self.tutorialListIndex = 0 + self.tutorialListIndex = 0 + def prevIndex(self): - if self.tutorialListIndex == None: - return + if self.tutorialListIndex is None: + return self.tutorialListIndex -= 1 if self.tutorialListIndex < 0: - self.tutorialListIndex = len(self.helpDict) - 1 + self.tutorialListIndex = len(self.helpDict) - 1 diff --git a/src/fenrirscreenreader/core/i18n.py b/src/fenrirscreenreader/core/i18n.py index 5493d371..d7636c12 100644 --- a/src/fenrirscreenreader/core/i18n.py +++ b/src/fenrirscreenreader/core/i18n.py @@ -6,6 +6,11 @@ import gettext import locale +import builtins -# the only function we really need to call here is gettext.install. Python3 has simplified this. +# the only function we really need to call here is gettext.install. +# Python3 has simplified this. gettext.install("fenrir") + +# Make _ available for import to satisfy static analysis tools +_ = builtins._ diff --git a/src/fenrirscreenreader/core/inputData.py b/src/fenrirscreenreader/core/inputData.py index e3bd87e4..05104a88 100644 --- a/src/fenrirscreenreader/core/inputData.py +++ b/src/fenrirscreenreader/core/inputData.py @@ -8,29 +8,593 @@ from fenrirscreenreader.core import debug import time inputData = { -'currInput': [], -'prevDeepestInput': [], -'eventBuffer': [], -'shortcutRepeat': 0, -'fenrirKey': [], -'scriptKey': [], -'keyForeward': 0, -'lastInputTime':time.time(), -'oldNumLock': True, -'newNumLock':True, -'oldScrollLock': True, -'newScrollLock':True, -'oldCapsLock':False, -'newCapsLock':False + 'currInput': [], + 'prevDeepestInput': [], + 'eventBuffer': [], + 'shortcutRepeat': 0, + 'fenrirKey': [], + 'scriptKey': [], + 'keyForeward': 0, + 'lastInputTime': time.time(), + 'oldNumLock': True, + 'newNumLock': True, + 'oldScrollLock': True, + 'newScrollLock': True, + 'oldCapsLock': False, + 'newCapsLock': False } inputEvent = { -'EventName': '', -'EventValue': '', -'EventSec': 0, -'EventUsec': 0, -'EventState': 0, + 'EventName': '', + 'EventValue': '', + 'EventSec': 0, + 'EventUsec': 0, + 'EventState': 0, } -keyNames = ['KEY_RESERVED', 'KEY_ESC', 'KEY_1', 'KEY_2', 'KEY_3', 'KEY_4', 'KEY_5', 'KEY_6', 'KEY_7', 'KEY_8', 'KEY_9', 'KEY_0', 'KEY_MINUS', 'KEY_EQUAL', 'KEY_BACKSPACE', 'KEY_TAB', 'KEY_Q', 'KEY_W', 'KEY_E', 'KEY_R', 'KEY_T', 'KEY_Y', 'KEY_U', 'KEY_I', 'KEY_O', 'KEY_P', 'KEY_LEFTBRACE', 'KEY_RIGHTBRACE', 'KEY_ENTER', 'KEY_LEFTCTRL', 'KEY_A', 'KEY_S', 'KEY_D', 'KEY_F', 'KEY_G', 'KEY_H', 'KEY_J', 'KEY_K', 'KEY_L', 'KEY_SEMICOLON', 'KEY_APOSTROPHE', 'KEY_GRAVE', 'KEY_LEFTSHIFT', 'KEY_BACKSLASH', 'KEY_Z', 'KEY_X', 'KEY_C', 'KEY_V', 'KEY_B', 'KEY_N', 'KEY_M', 'KEY_COMMA', 'KEY_DOT', 'KEY_SLASH', 'KEY_RIGHTSHIFT', 'KEY_KPASTERISK', 'KEY_LEFTALT', 'KEY_SPACE', 'KEY_CAPSLOCK', 'KEY_F1', 'KEY_F2', 'KEY_F3', 'KEY_F4', 'KEY_F5', 'KEY_F6', 'KEY_F7', 'KEY_F8', 'KEY_F9', 'KEY_F10', 'KEY_NUMLOCK', 'KEY_SCROLLLOCK', 'KEY_KP7', 'KEY_KP8', 'KEY_KP9', 'KEY_KPMINUS', 'KEY_KP4', 'KEY_KP5', 'KEY_KP6', 'KEY_KPPLUS', 'KEY_KP1', 'KEY_KP2', 'KEY_KP3', 'KEY_KP0', 'KEY_KPDOT', 'KEY_ZENKAKUHANKAKU', 'KEY_102ND', 'KEY_F11', 'KEY_F12', 'KEY_RO', 'KEY_KATAKANA', 'KEY_HIRAGANA', 'KEY_HENKAN', 'KEY_KATAKANAHIRAGANA', 'KEY_MUHENKAN', 'KEY_KPJPCOMMA', 'KEY_KPENTER', 'KEY_RIGHTCTRL', 'KEY_KPSLASH', 'KEY_SYSRQ', 'KEY_RIGHTALT', 'KEY_LINEFEED', 'KEY_HOME', 'KEY_UP', 'KEY_PAGEUP', 'KEY_LEFT', 'KEY_RIGHT', 'KEY_END', 'KEY_DOWN', 'KEY_PAGEDOWN', 'KEY_INSERT', 'KEY_DELETE', 'KEY_MACRO', 'KEY_MIN_INTERESTING', 'KEY_MUTE', 'KEY_VOLUMEDOWN', 'KEY_VOLUMEUP', 'KEY_POWER', 'KEY_KPEQUAL', 'KEY_KPPLUSMINUS', 'KEY_PAUSE', 'KEY_SCALE', 'KEY_KPCOMMA', 'KEY_HANGEUL', 'KEY_HANGUEL', 'KEY_HANJA', 'KEY_YEN', 'KEY_LEFTMETA', 'KEY_RIGHTMETA', 'KEY_COMPOSE', 'KEY_STOP', 'KEY_AGAIN', 'KEY_PROPS', 'KEY_UNDO', 'KEY_FRONT', 'KEY_COPY', 'KEY_OPEN', 'KEY_PASTE', 'KEY_FIND', 'KEY_CUT', 'KEY_HELP', 'KEY_MENU', 'KEY_CALC', 'KEY_SETUP', 'KEY_SLEEP', 'KEY_WAKEUP', 'KEY_FILE', 'KEY_SENDFILE', 'KEY_DELETEFILE', 'KEY_XFER', 'KEY_PROG1', 'KEY_PROG2', 'KEY_WWW', 'KEY_MSDOS', 'KEY_COFFEE', 'KEY_SCREENLOCK', 'KEY_DIRECTION', 'KEY_ROTATE_DISPLAY', 'KEY_CYCLEWINDOWS', 'KEY_MAIL', 'KEY_BOOKMARKS', 'KEY_COMPUTER', 'KEY_BACK', 'KEY_FORWARD', 'KEY_CLOSECD', 'KEY_EJECTCD', 'KEY_EJECTCLOSECD', 'KEY_NEXTSONG', 'KEY_PLAYPAUSE', 'KEY_PREVIOUSSONG', 'KEY_STOPCD', 'KEY_RECORD', 'KEY_REWIND', 'KEY_PHONE', 'KEY_ISO', 'KEY_CONFIG', 'KEY_HOMEPAGE', 'KEY_REFRESH', 'KEY_EXIT', 'KEY_MOVE', 'KEY_EDIT', 'KEY_SCROLLUP', 'KEY_SCROLLDOWN', 'KEY_KPLEFTPAREN', 'KEY_KPRIGHTPAREN', 'KEY_NEW', 'KEY_REDO', 'KEY_F13', 'KEY_F14', 'KEY_F15', 'KEY_F16', 'KEY_F17', 'KEY_F18', 'KEY_F19', 'KEY_F20', 'KEY_F21', 'KEY_F22', 'KEY_F23', 'KEY_F24', 'KEY_PLAYCD', 'KEY_PAUSECD', 'KEY_PROG3', 'KEY_PROG4', 'KEY_DASHBOARD', 'KEY_SUSPEND', 'KEY_CLOSE', 'KEY_PLAY', 'KEY_FASTFORWARD', 'KEY_BASSBOOST', 'KEY_PRINT', 'KEY_HP', 'KEY_CAMERA', 'KEY_SOUND', 'KEY_QUESTION', 'KEY_EMAIL', 'KEY_CHAT', 'KEY_SEARCH', 'KEY_CONNECT', 'KEY_FINANCE', 'KEY_SPORT', 'KEY_SHOP', 'KEY_ALTERASE', 'KEY_CANCEL', 'KEY_BRIGHTNESSDOWN', 'KEY_BRIGHTNESSUP', 'KEY_MEDIA', 'KEY_SWITCHVIDEOMODE', 'KEY_KBDILLUMTOGGLE', 'KEY_KBDILLUMDOWN', 'KEY_KBDILLUMUP', 'KEY_SEND', 'KEY_REPLY', 'KEY_FORWARDMAIL', 'KEY_SAVE', 'KEY_DOCUMENTS', 'KEY_BATTERY', 'KEY_BLUETOOTH', 'KEY_WLAN', 'KEY_UWB', 'KEY_UNKNOWN', 'KEY_VIDEO_NEXT', 'KEY_VIDEO_PREV', 'KEY_BRIGHTNESS_CYCLE', 'KEY_BRIGHTNESS_AUTO', 'KEY_BRIGHTNESS_ZERO', 'KEY_DISPLAY_OFF', 'KEY_WIMAX', 'KEY_WWAN', 'KEY_RFKILL', 'KEY_MICMUTE', 'BTN_0', 'BTN_MISC', 'BTN_1', 'BTN_2', 'BTN_3', 'BTN_4', 'BTN_5', 'BTN_6', 'BTN_7', 'BTN_8', 'BTN_9', 'BTN_LEFT', 'BTN_MOUSE', 'BTN_RIGHT', 'BTN_MIDDLE', 'BTN_SIDE', 'BTN_EXTRA', 'BTN_FORWARD', 'BTN_BACK', 'BTN_TASK', 'BTN_JOYSTICK', 'BTN_TRIGGER', 'BTN_THUMB', 'BTN_THUMB2', 'BTN_TOP', 'BTN_TOP2', 'BTN_PINKIE', 'BTN_BASE', 'BTN_BASE2', 'BTN_BASE3', 'BTN_BASE4', 'BTN_BASE5', 'BTN_BASE6', 'BTN_DEAD', 'BTN_A', 'BTN_GAMEPAD', 'BTN_SOUTH', 'BTN_B', 'BTN_EAST', 'BTN_C', 'BTN_NORTH', 'BTN_X', 'BTN_WEST', 'BTN_Y', 'BTN_Z', 'BTN_TL', 'BTN_TR', 'BTN_TL2', 'BTN_TR2', 'BTN_SELECT', 'BTN_START', 'BTN_MODE', 'BTN_THUMBL', 'BTN_THUMBR', 'BTN_DIGI', 'BTN_TOOL_PEN', 'BTN_TOOL_RUBBER', 'BTN_TOOL_BRUSH', 'BTN_TOOL_PENCIL', 'BTN_TOOL_AIRBRUSH', 'BTN_TOOL_FINGER', 'BTN_TOOL_MOUSE', 'BTN_TOOL_LENS', 'BTN_TOOL_QUINTTAP', 'BTN_TOUCH', 'BTN_STYLUS', 'BTN_STYLUS2', 'BTN_TOOL_DOUBLETAP', 'BTN_TOOL_TRIPLETAP', 'BTN_TOOL_QUADTAP', 'BTN_GEAR_DOWN', 'BTN_WHEEL', 'BTN_GEAR_UP', 'KEY_OK', 'KEY_SELECT', 'KEY_GOTO', 'KEY_CLEAR', 'KEY_POWER2', 'KEY_OPTION', 'KEY_INFO', 'KEY_TIME', 'KEY_VENDOR', 'KEY_ARCHIVE', 'KEY_PROGRAM', 'KEY_CHANNEL', 'KEY_FAVORITES', 'KEY_EPG', 'KEY_PVR', 'KEY_MHP', 'KEY_LANGUAGE', 'KEY_TITLE', 'KEY_SUBTITLE', 'KEY_ANGLE', 'KEY_ZOOM', 'KEY_MODE', 'KEY_KEYBOARD', 'KEY_SCREEN', 'KEY_PC', 'KEY_TV', 'KEY_TV2', 'KEY_VCR', 'KEY_VCR2', 'KEY_SAT', 'KEY_SAT2', 'KEY_CD', 'KEY_TAPE', 'KEY_RADIO', 'KEY_TUNER', 'KEY_PLAYER', 'KEY_TEXT', 'KEY_DVD', 'KEY_AUX', 'KEY_MP3', 'KEY_AUDIO', 'KEY_VIDEO', 'KEY_DIRECTORY', 'KEY_LIST', 'KEY_MEMO', 'KEY_CALENDAR', 'KEY_RED', 'KEY_GREEN', 'KEY_YELLOW', 'KEY_BLUE', 'KEY_CHANNELUP', 'KEY_CHANNELDOWN', 'KEY_FIRST', 'KEY_LAST', 'KEY_AB', 'KEY_NEXT', 'KEY_RESTART', 'KEY_SLOW', 'KEY_SHUFFLE', 'KEY_BREAK', 'KEY_PREVIOUS', 'KEY_DIGITS', 'KEY_TEEN', 'KEY_TWEN', 'KEY_VIDEOPHONE', 'KEY_GAMES', 'KEY_ZOOMIN', 'KEY_ZOOMOUT', 'KEY_ZOOMRESET', 'KEY_WORDPROCESSOR', 'KEY_EDITOR', 'KEY_SPREADSHEET', 'KEY_GRAPHICSEDITOR', 'KEY_PRESENTATION', 'KEY_DATABASE', 'KEY_NEWS', 'KEY_VOICEMAIL', 'KEY_ADDRESSBOOK', 'KEY_MESSENGER', 'KEY_BRIGHTNESS_TOGGLE', 'KEY_DISPLAYTOGGLE', 'KEY_SPELLCHECK', 'KEY_LOGOFF', 'KEY_DOLLAR', 'KEY_EURO', 'KEY_FRAMEBACK', 'KEY_FRAMEFORWARD', 'KEY_CONTEXT_MENU', 'KEY_MEDIA_REPEAT', 'KEY_10CHANNELSUP', 'KEY_10CHANNELSDOWN', 'KEY_IMAGES', 'KEY_DEL_EOL', 'KEY_DEL_EOS', 'KEY_INS_LINE', 'KEY_DEL_LINE', 'KEY_FN', 'KEY_FN_ESC', 'KEY_FN_F1', 'KEY_FN_F2', 'KEY_FN_F3', 'KEY_FN_F4', 'KEY_FN_F5', 'KEY_FN_F6', 'KEY_FN_F7', 'KEY_FN_F8', 'KEY_FN_F9', 'KEY_FN_F10', 'KEY_FN_F11', 'KEY_FN_F12', 'KEY_FN_1', 'KEY_FN_2', 'KEY_FN_D', 'KEY_FN_E', 'KEY_FN_F', 'KEY_FN_S', 'KEY_FN_B', 'KEY_BRL_DOT1', 'KEY_BRL_DOT2', 'KEY_BRL_DOT3', 'KEY_BRL_DOT4', 'KEY_BRL_DOT5', 'KEY_BRL_DOT6', 'KEY_BRL_DOT7', 'KEY_BRL_DOT8', 'KEY_BRL_DOT9', 'KEY_BRL_DOT10', 'KEY_NUMERIC_0', 'KEY_NUMERIC_1', 'KEY_NUMERIC_2', 'KEY_NUMERIC_3', 'KEY_NUMERIC_4', 'KEY_NUMERIC_5', 'KEY_NUMERIC_6', 'KEY_NUMERIC_7', 'KEY_NUMERIC_8', 'KEY_NUMERIC_9', 'KEY_NUMERIC_STAR', 'KEY_NUMERIC_POUND', 'KEY_NUMERIC_A', 'KEY_NUMERIC_B', 'KEY_NUMERIC_C', 'KEY_NUMERIC_D', 'KEY_CAMERA_FOCUS', 'KEY_WPS_BUTTON', 'KEY_TOUCHPAD_TOGGLE', 'KEY_TOUCHPAD_ON', 'KEY_TOUCHPAD_OFF', 'KEY_CAMERA_ZOOMIN', 'KEY_CAMERA_ZOOMOUT', 'KEY_CAMERA_UP', 'KEY_CAMERA_DOWN', 'KEY_CAMERA_LEFT', 'KEY_CAMERA_RIGHT', 'KEY_ATTENDANT_ON', 'KEY_ATTENDANT_OFF', 'KEY_ATTENDANT_TOGGLE', 'KEY_LIGHTS_TOGGLE', 'BTN_DPAD_UP', 'BTN_DPAD_DOWN', 'BTN_DPAD_LEFT', 'BTN_DPAD_RIGHT', 'KEY_ALS_TOGGLE', 'KEY_BUTTONCONFIG', 'KEY_TASKMANAGER', 'KEY_JOURNAL', 'KEY_CONTROLPANEL', 'KEY_APPSELECT', 'KEY_SCREENSAVER', 'KEY_VOICECOMMAND', 'KEY_BRIGHTNESS_MIN', 'KEY_BRIGHTNESS_MAX', 'KEY_KBDINPUTASSIST_PREV', 'KEY_KBDINPUTASSIST_NEXT', 'KEY_KBDINPUTASSIST_PREVGROUP', 'KEY_KBDINPUTASSIST_NEXTGROUP', 'KEY_KBDINPUTASSIST_ACCEPT', 'KEY_KBDINPUTASSIST_CANCEL', 'KEY_RIGHT_UP', 'KEY_RIGHT_DOWN', 'KEY_LEFT_UP', 'KEY_LEFT_DOWN', 'KEY_ROOT_MENU', 'KEY_MEDIA_TOP_MENU', 'KEY_NUMERIC_11', 'KEY_NUMERIC_12', 'KEY_AUDIO_DESC', 'KEY_3D_MODE', 'KEY_NEXT_FAVORITE', 'KEY_STOP_RECORD', 'KEY_PAUSE_RECORD', 'KEY_VOD', 'KEY_UNMUTE', 'KEY_DATA', 'KEY_FASTREVERSE', 'KEY_SLOWREVERSE', 'BTN_TRIGGER_HAPPY', 'BTN_TRIGGER_HAPPY1', 'BTN_TRIGGER_HAPPY2', 'BTN_TRIGGER_HAPPY3', 'BTN_TRIGGER_HAPPY4', 'BTN_TRIGGER_HAPPY5', 'BTN_TRIGGER_HAPPY6', 'BTN_TRIGGER_HAPPY7', 'BTN_TRIGGER_HAPPY8', 'BTN_TRIGGER_HAPPY9', 'BTN_TRIGGER_HAPPY10', 'BTN_TRIGGER_HAPPY11', 'BTN_TRIGGER_HAPPY12', 'BTN_TRIGGER_HAPPY13', 'BTN_TRIGGER_HAPPY14', 'BTN_TRIGGER_HAPPY15', 'BTN_TRIGGER_HAPPY16', 'BTN_TRIGGER_HAPPY17', 'BTN_TRIGGER_HAPPY18', 'BTN_TRIGGER_HAPPY19', 'BTN_TRIGGER_HAPPY20', 'BTN_TRIGGER_HAPPY21', 'BTN_TRIGGER_HAPPY22', 'BTN_TRIGGER_HAPPY23', 'BTN_TRIGGER_HAPPY24', 'BTN_TRIGGER_HAPPY25', 'BTN_TRIGGER_HAPPY26', 'BTN_TRIGGER_HAPPY27', 'BTN_TRIGGER_HAPPY28', 'BTN_TRIGGER_HAPPY29', 'BTN_TRIGGER_HAPPY30', 'BTN_TRIGGER_HAPPY31', 'BTN_TRIGGER_HAPPY32', 'BTN_TRIGGER_HAPPY33', 'BTN_TRIGGER_HAPPY34', 'BTN_TRIGGER_HAPPY35', 'BTN_TRIGGER_HAPPY36', 'BTN_TRIGGER_HAPPY37', 'BTN_TRIGGER_HAPPY38', 'BTN_TRIGGER_HAPPY39', 'BTN_TRIGGER_HAPPY40', 'KEY_FENRIR', 'KEY_SCRIPT', 'KEY_ALT', 'KEY_CTRL', 'KEY_META', 'KEY_SHIFT'] - +keyNames = [ + 'KEY_RESERVED', + 'KEY_ESC', + 'KEY_1', + 'KEY_2', + 'KEY_3', + 'KEY_4', + 'KEY_5', + 'KEY_6', + 'KEY_7', + 'KEY_8', + 'KEY_9', + 'KEY_0', + 'KEY_MINUS', + 'KEY_EQUAL', + 'KEY_BACKSPACE', + 'KEY_TAB', + 'KEY_Q', + 'KEY_W', + 'KEY_E', + 'KEY_R', + 'KEY_T', + 'KEY_Y', + 'KEY_U', + 'KEY_I', + 'KEY_O', + 'KEY_P', + 'KEY_LEFTBRACE', + 'KEY_RIGHTBRACE', + 'KEY_ENTER', + 'KEY_LEFTCTRL', + 'KEY_A', + 'KEY_S', + 'KEY_D', + 'KEY_F', + 'KEY_G', + 'KEY_H', + 'KEY_J', + 'KEY_K', + 'KEY_L', + 'KEY_SEMICOLON', + 'KEY_APOSTROPHE', + 'KEY_GRAVE', + 'KEY_LEFTSHIFT', + 'KEY_BACKSLASH', + 'KEY_Z', + 'KEY_X', + 'KEY_C', + 'KEY_V', + 'KEY_B', + 'KEY_N', + 'KEY_M', + 'KEY_COMMA', + 'KEY_DOT', + 'KEY_SLASH', + 'KEY_RIGHTSHIFT', + 'KEY_KPASTERISK', + 'KEY_LEFTALT', + 'KEY_SPACE', + 'KEY_CAPSLOCK', + 'KEY_F1', + 'KEY_F2', + 'KEY_F3', + 'KEY_F4', + 'KEY_F5', + 'KEY_F6', + 'KEY_F7', + 'KEY_F8', + 'KEY_F9', + 'KEY_F10', + 'KEY_NUMLOCK', + 'KEY_SCROLLLOCK', + 'KEY_KP7', + 'KEY_KP8', + 'KEY_KP9', + 'KEY_KPMINUS', + 'KEY_KP4', + 'KEY_KP5', + 'KEY_KP6', + 'KEY_KPPLUS', + 'KEY_KP1', + 'KEY_KP2', + 'KEY_KP3', + 'KEY_KP0', + 'KEY_KPDOT', + 'KEY_ZENKAKUHANKAKU', + 'KEY_102ND', + 'KEY_F11', + 'KEY_F12', + 'KEY_RO', + 'KEY_KATAKANA', + 'KEY_HIRAGANA', + 'KEY_HENKAN', + 'KEY_KATAKANAHIRAGANA', + 'KEY_MUHENKAN', + 'KEY_KPJPCOMMA', + 'KEY_KPENTER', + 'KEY_RIGHTCTRL', + 'KEY_KPSLASH', + 'KEY_SYSRQ', + 'KEY_RIGHTALT', + 'KEY_LINEFEED', + 'KEY_HOME', + 'KEY_UP', + 'KEY_PAGEUP', + 'KEY_LEFT', + 'KEY_RIGHT', + 'KEY_END', + 'KEY_DOWN', + 'KEY_PAGEDOWN', + 'KEY_INSERT', + 'KEY_DELETE', + 'KEY_MACRO', + 'KEY_MIN_INTERESTING', + 'KEY_MUTE', + 'KEY_VOLUMEDOWN', + 'KEY_VOLUMEUP', + 'KEY_POWER', + 'KEY_KPEQUAL', + 'KEY_KPPLUSMINUS', + 'KEY_PAUSE', + 'KEY_SCALE', + 'KEY_KPCOMMA', + 'KEY_HANGEUL', + 'KEY_HANGUEL', + 'KEY_HANJA', + 'KEY_YEN', + 'KEY_LEFTMETA', + 'KEY_RIGHTMETA', + 'KEY_COMPOSE', + 'KEY_STOP', + 'KEY_AGAIN', + 'KEY_PROPS', + 'KEY_UNDO', + 'KEY_FRONT', + 'KEY_COPY', + 'KEY_OPEN', + 'KEY_PASTE', + 'KEY_FIND', + 'KEY_CUT', + 'KEY_HELP', + 'KEY_MENU', + 'KEY_CALC', + 'KEY_SETUP', + 'KEY_SLEEP', + 'KEY_WAKEUP', + 'KEY_FILE', + 'KEY_SENDFILE', + 'KEY_DELETEFILE', + 'KEY_XFER', + 'KEY_PROG1', + 'KEY_PROG2', + 'KEY_WWW', + 'KEY_MSDOS', + 'KEY_COFFEE', + 'KEY_SCREENLOCK', + 'KEY_DIRECTION', + 'KEY_ROTATE_DISPLAY', + 'KEY_CYCLEWINDOWS', + 'KEY_MAIL', + 'KEY_BOOKMARKS', + 'KEY_COMPUTER', + 'KEY_BACK', + 'KEY_FORWARD', + 'KEY_CLOSECD', + 'KEY_EJECTCD', + 'KEY_EJECTCLOSECD', + 'KEY_NEXTSONG', + 'KEY_PLAYPAUSE', + 'KEY_PREVIOUSSONG', + 'KEY_STOPCD', + 'KEY_RECORD', + 'KEY_REWIND', + 'KEY_PHONE', + 'KEY_ISO', + 'KEY_CONFIG', + 'KEY_HOMEPAGE', + 'KEY_REFRESH', + 'KEY_EXIT', + 'KEY_MOVE', + 'KEY_EDIT', + 'KEY_SCROLLUP', + 'KEY_SCROLLDOWN', + 'KEY_KPLEFTPAREN', + 'KEY_KPRIGHTPAREN', + 'KEY_NEW', + 'KEY_REDO', + 'KEY_F13', + 'KEY_F14', + 'KEY_F15', + 'KEY_F16', + 'KEY_F17', + 'KEY_F18', + 'KEY_F19', + 'KEY_F20', + 'KEY_F21', + 'KEY_F22', + 'KEY_F23', + 'KEY_F24', + 'KEY_PLAYCD', + 'KEY_PAUSECD', + 'KEY_PROG3', + 'KEY_PROG4', + 'KEY_DASHBOARD', + 'KEY_SUSPEND', + 'KEY_CLOSE', + 'KEY_PLAY', + 'KEY_FASTFORWARD', + 'KEY_BASSBOOST', + 'KEY_PRINT', + 'KEY_HP', + 'KEY_CAMERA', + 'KEY_SOUND', + 'KEY_QUESTION', + 'KEY_EMAIL', + 'KEY_CHAT', + 'KEY_SEARCH', + 'KEY_CONNECT', + 'KEY_FINANCE', + 'KEY_SPORT', + 'KEY_SHOP', + 'KEY_ALTERASE', + 'KEY_CANCEL', + 'KEY_BRIGHTNESSDOWN', + 'KEY_BRIGHTNESSUP', + 'KEY_MEDIA', + 'KEY_SWITCHVIDEOMODE', + 'KEY_KBDILLUMTOGGLE', + 'KEY_KBDILLUMDOWN', + 'KEY_KBDILLUMUP', + 'KEY_SEND', + 'KEY_REPLY', + 'KEY_FORWARDMAIL', + 'KEY_SAVE', + 'KEY_DOCUMENTS', + 'KEY_BATTERY', + 'KEY_BLUETOOTH', + 'KEY_WLAN', + 'KEY_UWB', + 'KEY_UNKNOWN', + 'KEY_VIDEO_NEXT', + 'KEY_VIDEO_PREV', + 'KEY_BRIGHTNESS_CYCLE', + 'KEY_BRIGHTNESS_AUTO', + 'KEY_BRIGHTNESS_ZERO', + 'KEY_DISPLAY_OFF', + 'KEY_WIMAX', + 'KEY_WWAN', + 'KEY_RFKILL', + 'KEY_MICMUTE', + 'BTN_0', + 'BTN_MISC', + 'BTN_1', + 'BTN_2', + 'BTN_3', + 'BTN_4', + 'BTN_5', + 'BTN_6', + 'BTN_7', + 'BTN_8', + 'BTN_9', + 'BTN_LEFT', + 'BTN_MOUSE', + 'BTN_RIGHT', + 'BTN_MIDDLE', + 'BTN_SIDE', + 'BTN_EXTRA', + 'BTN_FORWARD', + 'BTN_BACK', + 'BTN_TASK', + 'BTN_JOYSTICK', + 'BTN_TRIGGER', + 'BTN_THUMB', + 'BTN_THUMB2', + 'BTN_TOP', + 'BTN_TOP2', + 'BTN_PINKIE', + 'BTN_BASE', + 'BTN_BASE2', + 'BTN_BASE3', + 'BTN_BASE4', + 'BTN_BASE5', + 'BTN_BASE6', + 'BTN_DEAD', + 'BTN_A', + 'BTN_GAMEPAD', + 'BTN_SOUTH', + 'BTN_B', + 'BTN_EAST', + 'BTN_C', + 'BTN_NORTH', + 'BTN_X', + 'BTN_WEST', + 'BTN_Y', + 'BTN_Z', + 'BTN_TL', + 'BTN_TR', + 'BTN_TL2', + 'BTN_TR2', + 'BTN_SELECT', + 'BTN_START', + 'BTN_MODE', + 'BTN_THUMBL', + 'BTN_THUMBR', + 'BTN_DIGI', + 'BTN_TOOL_PEN', + 'BTN_TOOL_RUBBER', + 'BTN_TOOL_BRUSH', + 'BTN_TOOL_PENCIL', + 'BTN_TOOL_AIRBRUSH', + 'BTN_TOOL_FINGER', + 'BTN_TOOL_MOUSE', + 'BTN_TOOL_LENS', + 'BTN_TOOL_QUINTTAP', + 'BTN_TOUCH', + 'BTN_STYLUS', + 'BTN_STYLUS2', + 'BTN_TOOL_DOUBLETAP', + 'BTN_TOOL_TRIPLETAP', + 'BTN_TOOL_QUADTAP', + 'BTN_GEAR_DOWN', + 'BTN_WHEEL', + 'BTN_GEAR_UP', + 'KEY_OK', + 'KEY_SELECT', + 'KEY_GOTO', + 'KEY_CLEAR', + 'KEY_POWER2', + 'KEY_OPTION', + 'KEY_INFO', + 'KEY_TIME', + 'KEY_VENDOR', + 'KEY_ARCHIVE', + 'KEY_PROGRAM', + 'KEY_CHANNEL', + 'KEY_FAVORITES', + 'KEY_EPG', + 'KEY_PVR', + 'KEY_MHP', + 'KEY_LANGUAGE', + 'KEY_TITLE', + 'KEY_SUBTITLE', + 'KEY_ANGLE', + 'KEY_ZOOM', + 'KEY_MODE', + 'KEY_KEYBOARD', + 'KEY_SCREEN', + 'KEY_PC', + 'KEY_TV', + 'KEY_TV2', + 'KEY_VCR', + 'KEY_VCR2', + 'KEY_SAT', + 'KEY_SAT2', + 'KEY_CD', + 'KEY_TAPE', + 'KEY_RADIO', + 'KEY_TUNER', + 'KEY_PLAYER', + 'KEY_TEXT', + 'KEY_DVD', + 'KEY_AUX', + 'KEY_MP3', + 'KEY_AUDIO', + 'KEY_VIDEO', + 'KEY_DIRECTORY', + 'KEY_LIST', + 'KEY_MEMO', + 'KEY_CALENDAR', + 'KEY_RED', + 'KEY_GREEN', + 'KEY_YELLOW', + 'KEY_BLUE', + 'KEY_CHANNELUP', + 'KEY_CHANNELDOWN', + 'KEY_FIRST', + 'KEY_LAST', + 'KEY_AB', + 'KEY_NEXT', + 'KEY_RESTART', + 'KEY_SLOW', + 'KEY_SHUFFLE', + 'KEY_BREAK', + 'KEY_PREVIOUS', + 'KEY_DIGITS', + 'KEY_TEEN', + 'KEY_TWEN', + 'KEY_VIDEOPHONE', + 'KEY_GAMES', + 'KEY_ZOOMIN', + 'KEY_ZOOMOUT', + 'KEY_ZOOMRESET', + 'KEY_WORDPROCESSOR', + 'KEY_EDITOR', + 'KEY_SPREADSHEET', + 'KEY_GRAPHICSEDITOR', + 'KEY_PRESENTATION', + 'KEY_DATABASE', + 'KEY_NEWS', + 'KEY_VOICEMAIL', + 'KEY_ADDRESSBOOK', + 'KEY_MESSENGER', + 'KEY_BRIGHTNESS_TOGGLE', + 'KEY_DISPLAYTOGGLE', + 'KEY_SPELLCHECK', + 'KEY_LOGOFF', + 'KEY_DOLLAR', + 'KEY_EURO', + 'KEY_FRAMEBACK', + 'KEY_FRAMEFORWARD', + 'KEY_CONTEXT_MENU', + 'KEY_MEDIA_REPEAT', + 'KEY_10CHANNELSUP', + 'KEY_10CHANNELSDOWN', + 'KEY_IMAGES', + 'KEY_DEL_EOL', + 'KEY_DEL_EOS', + 'KEY_INS_LINE', + 'KEY_DEL_LINE', + 'KEY_FN', + 'KEY_FN_ESC', + 'KEY_FN_F1', + 'KEY_FN_F2', + 'KEY_FN_F3', + 'KEY_FN_F4', + 'KEY_FN_F5', + 'KEY_FN_F6', + 'KEY_FN_F7', + 'KEY_FN_F8', + 'KEY_FN_F9', + 'KEY_FN_F10', + 'KEY_FN_F11', + 'KEY_FN_F12', + 'KEY_FN_1', + 'KEY_FN_2', + 'KEY_FN_D', + 'KEY_FN_E', + 'KEY_FN_F', + 'KEY_FN_S', + 'KEY_FN_B', + 'KEY_BRL_DOT1', + 'KEY_BRL_DOT2', + 'KEY_BRL_DOT3', + 'KEY_BRL_DOT4', + 'KEY_BRL_DOT5', + 'KEY_BRL_DOT6', + 'KEY_BRL_DOT7', + 'KEY_BRL_DOT8', + 'KEY_BRL_DOT9', + 'KEY_BRL_DOT10', + 'KEY_NUMERIC_0', + 'KEY_NUMERIC_1', + 'KEY_NUMERIC_2', + 'KEY_NUMERIC_3', + 'KEY_NUMERIC_4', + 'KEY_NUMERIC_5', + 'KEY_NUMERIC_6', + 'KEY_NUMERIC_7', + 'KEY_NUMERIC_8', + 'KEY_NUMERIC_9', + 'KEY_NUMERIC_STAR', + 'KEY_NUMERIC_POUND', + 'KEY_NUMERIC_A', + 'KEY_NUMERIC_B', + 'KEY_NUMERIC_C', + 'KEY_NUMERIC_D', + 'KEY_CAMERA_FOCUS', + 'KEY_WPS_BUTTON', + 'KEY_TOUCHPAD_TOGGLE', + 'KEY_TOUCHPAD_ON', + 'KEY_TOUCHPAD_OFF', + 'KEY_CAMERA_ZOOMIN', + 'KEY_CAMERA_ZOOMOUT', + 'KEY_CAMERA_UP', + 'KEY_CAMERA_DOWN', + 'KEY_CAMERA_LEFT', + 'KEY_CAMERA_RIGHT', + 'KEY_ATTENDANT_ON', + 'KEY_ATTENDANT_OFF', + 'KEY_ATTENDANT_TOGGLE', + 'KEY_LIGHTS_TOGGLE', + 'BTN_DPAD_UP', + 'BTN_DPAD_DOWN', + 'BTN_DPAD_LEFT', + 'BTN_DPAD_RIGHT', + 'KEY_ALS_TOGGLE', + 'KEY_BUTTONCONFIG', + 'KEY_TASKMANAGER', + 'KEY_JOURNAL', + 'KEY_CONTROLPANEL', + 'KEY_APPSELECT', + 'KEY_SCREENSAVER', + 'KEY_VOICECOMMAND', + 'KEY_BRIGHTNESS_MIN', + 'KEY_BRIGHTNESS_MAX', + 'KEY_KBDINPUTASSIST_PREV', + 'KEY_KBDINPUTASSIST_NEXT', + 'KEY_KBDINPUTASSIST_PREVGROUP', + 'KEY_KBDINPUTASSIST_NEXTGROUP', + 'KEY_KBDINPUTASSIST_ACCEPT', + 'KEY_KBDINPUTASSIST_CANCEL', + 'KEY_RIGHT_UP', + 'KEY_RIGHT_DOWN', + 'KEY_LEFT_UP', + 'KEY_LEFT_DOWN', + 'KEY_ROOT_MENU', + 'KEY_MEDIA_TOP_MENU', + 'KEY_NUMERIC_11', + 'KEY_NUMERIC_12', + 'KEY_AUDIO_DESC', + 'KEY_3D_MODE', + 'KEY_NEXT_FAVORITE', + 'KEY_STOP_RECORD', + 'KEY_PAUSE_RECORD', + 'KEY_VOD', + 'KEY_UNMUTE', + 'KEY_DATA', + 'KEY_FASTREVERSE', + 'KEY_SLOWREVERSE', + 'BTN_TRIGGER_HAPPY', + 'BTN_TRIGGER_HAPPY1', + 'BTN_TRIGGER_HAPPY2', + 'BTN_TRIGGER_HAPPY3', + 'BTN_TRIGGER_HAPPY4', + 'BTN_TRIGGER_HAPPY5', + 'BTN_TRIGGER_HAPPY6', + 'BTN_TRIGGER_HAPPY7', + 'BTN_TRIGGER_HAPPY8', + 'BTN_TRIGGER_HAPPY9', + 'BTN_TRIGGER_HAPPY10', + 'BTN_TRIGGER_HAPPY11', + 'BTN_TRIGGER_HAPPY12', + 'BTN_TRIGGER_HAPPY13', + 'BTN_TRIGGER_HAPPY14', + 'BTN_TRIGGER_HAPPY15', + 'BTN_TRIGGER_HAPPY16', + 'BTN_TRIGGER_HAPPY17', + 'BTN_TRIGGER_HAPPY18', + 'BTN_TRIGGER_HAPPY19', + 'BTN_TRIGGER_HAPPY20', + 'BTN_TRIGGER_HAPPY21', + 'BTN_TRIGGER_HAPPY22', + 'BTN_TRIGGER_HAPPY23', + 'BTN_TRIGGER_HAPPY24', + 'BTN_TRIGGER_HAPPY25', + 'BTN_TRIGGER_HAPPY26', + 'BTN_TRIGGER_HAPPY27', + 'BTN_TRIGGER_HAPPY28', + 'BTN_TRIGGER_HAPPY29', + 'BTN_TRIGGER_HAPPY30', + 'BTN_TRIGGER_HAPPY31', + 'BTN_TRIGGER_HAPPY32', + 'BTN_TRIGGER_HAPPY33', + 'BTN_TRIGGER_HAPPY34', + 'BTN_TRIGGER_HAPPY35', + 'BTN_TRIGGER_HAPPY36', + 'BTN_TRIGGER_HAPPY37', + 'BTN_TRIGGER_HAPPY38', + 'BTN_TRIGGER_HAPPY39', + 'BTN_TRIGGER_HAPPY40', + 'KEY_FENRIR', + 'KEY_SCRIPT', + 'KEY_ALT', + 'KEY_CTRL', + 'KEY_META', + 'KEY_SHIFT'] diff --git a/src/fenrirscreenreader/core/inputDriver.py b/src/fenrirscreenreader/core/inputDriver.py index 9f9c5460..f9730cb6 100644 --- a/src/fenrirscreenreader/core/inputDriver.py +++ b/src/fenrirscreenreader/core/inputDriver.py @@ -4,40 +4,51 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +import time from fenrirscreenreader.core import debug + class inputDriver(): def __init__(self): self._initialized = False + def initialize(self, environment): self.env = environment self.env['runtime']['inputManager'].setShortcutType('KEY') self._isInitialized = True + def shutdown(self): if self._initialized: self.removeAllDevices() self._isInitialized = False + def getInputEvent(self): time.sleep(0.1) return None + def clearEventBuffer(self): if not self._initialized: return del self.env['input']['eventBuffer'][:] - def updateInputDevices(self, newDevices = None, init = False): + + def updateInputDevices(self, newDevices=None, init=False): if not self._initialized: return - def getLedState(self, led = 0): + + def getLedState(self, led=0): if not self._initialized: return False return False - def toggleLedState(self, led = 0): + + def toggleLedState(self, led=0): if not self._initialized: return + def grabAllDevices(self): if not self._initialized: return True return True + def ungrabAllDevices(self): if not self._initialized: return True @@ -52,9 +63,11 @@ class inputDriver(): return self.ungrabAllDevices() except Exception as e: # Just log the failure and inform the user - if hasattr(self, 'env') and 'runtime' in self.env and 'debug' in self.env['runtime']: + if hasattr( + self, + 'env') and 'runtime' in self.env and 'debug' in self.env['runtime']: self.env['runtime']['debug'].writeDebugOut( - f"Emergency device release failed: {str(e)}", + f"Emergency device release failed: {str(e)}", debug.debugLevel.ERROR ) else: @@ -65,12 +78,15 @@ class inputDriver(): if not self._initialized: return False return True + def removeAllDevices(self): if not self._initialized: return + def sendKey(self): if not self._initialized: return + def __del__(self): if not self._initialized: return diff --git a/src/fenrirscreenreader/core/inputManager.py b/src/fenrirscreenreader/core/inputManager.py index fef1e300..90c801c1 100644 --- a/src/fenrirscreenreader/core/inputManager.py +++ b/src/fenrirscreenreader/core/inputManager.py @@ -5,52 +5,72 @@ # By Chrys, Storm Dragon, and contributers. from fenrirscreenreader.core import debug +from fenrirscreenreader.core.i18n import _ from fenrirscreenreader.core import inputData -import os, inspect, time, traceback -currentdir = os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe())))) +import os +import inspect +import time +import traceback +currentdir = os.path.dirname( + os.path.realpath( + os.path.abspath( + inspect.getfile( + inspect.currentframe())))) fenrirPath = os.path.dirname(currentdir) + class inputManager(): def __init__(self): self.shortcutType = 'KEY' self.executeDeviceGrab = False self.lastDetectedDevices = None - def setShortcutType(self, shortcutType = 'KEY'): + + def setShortcutType(self, shortcutType='KEY'): if shortcutType in ['KEY', 'BYTE']: self.shortcutType = shortcutType + def getShortcutType(self): return self.shortcutType + def initialize(self, environment): self.env = environment - self.env['runtime']['settingsManager'].loadDriver(\ - self.env['runtime']['settingsManager'].getSetting('keyboard', 'driver'), 'inputDriver') + self.env['runtime']['settingsManager'].loadDriver( + self.env['runtime']['settingsManager'].getSetting( + 'keyboard', 'driver'), 'inputDriver') self.updateInputDevices() # init LEDs with current state self.env['input']['newNumLock'] = self.env['runtime']['inputDriver'].getLedState() self.env['input']['oldNumLock'] = self.env['input']['newNumLock'] - self.env['input']['newCapsLock'] = self.env['runtime']['inputDriver'].getLedState(1) + self.env['input']['newCapsLock'] = self.env['runtime']['inputDriver'].getLedState( + 1) self.env['input']['oldCapsLock'] = self.env['input']['newCapsLock'] - self.env['input']['newScrollLock'] = self.env['runtime']['inputDriver'].getLedState(2) + self.env['input']['newScrollLock'] = self.env['runtime']['inputDriver'].getLedState( + 2) self.env['input']['oldScrollLock'] = self.env['input']['newScrollLock'] self.lastDeepestInput = [] self.lastEvent = None self.env['input']['shortcutRepeat'] = 1 self.lastInputTime = time.time() + def shutdown(self): self.removeAllDevices() self.env['runtime']['settingsManager'].shutdownDriver('inputDriver') - def getInputEvent(self): - event = None + + def getInputEvent(self): + event = None try: event = self.env['runtime']['inputDriver'].getInputEvent() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('inputManager getInputEvent: Error getting input event: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'inputManager getInputEvent: Error getting input event: ' + str(e), + debug.debugLevel.ERROR) return event - def setExecuteDeviceGrab(self, newExecuteDeviceGrab = True): + + def setExecuteDeviceGrab(self, newExecuteDeviceGrab=True): self.executeDeviceGrab = newExecuteDeviceGrab - def handleDeviceGrab(self, force = False): + def handleDeviceGrab(self, force=False): if force: self.setExecuteDeviceGrab() if not self.executeDeviceGrab: @@ -59,7 +79,8 @@ class inputManager(): return if not self.noKeyPressed(): return - if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'keyboard', 'grabDevices'): self.executeDeviceGrab = False return @@ -72,25 +93,35 @@ class inputManager(): if self.env['runtime']['screenManager'].getCurrScreenIgnored(): while not self.ungrabAllDevices(): retryCount += 1 - if retryCount >= maxRetries or (time.time() - startTime) > grabTimeout: - self.env['runtime']['debug'].writeDebugOut("Failed to ungrab devices after multiple attempts", debug.debugLevel.ERROR) - # Force a release of devices if possible through alternative means + if retryCount >= maxRetries or ( + time.time() - startTime) > grabTimeout: + self.env['runtime']['debug'].writeDebugOut( + "Failed to ungrab devices after multiple attempts", debug.debugLevel.ERROR) + # Force a release of devices if possible through + # alternative means try: self.env['runtime']['inputDriver'].forceUngrab() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('inputManager handleDeviceGrab: Error forcing ungrab: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'inputManager handleDeviceGrab: Error forcing ungrab: ' + str(e), + debug.debugLevel.ERROR) break time.sleep(0.25) - self.env['runtime']['debug'].writeDebugOut(f"retry ungrabAllDevices {retryCount}/{maxRetries}", debug.debugLevel.WARNING) + self.env['runtime']['debug'].writeDebugOut( + f"retry ungrabAllDevices {retryCount}/{maxRetries}", debug.debugLevel.WARNING) else: while not self.grabAllDevices(): retryCount += 1 - if retryCount >= maxRetries or (time.time() - startTime) > grabTimeout: - self.env['runtime']['debug'].writeDebugOut("Failed to grab devices after multiple attempts", debug.debugLevel.ERROR) - # Continue without grabbing input - limited functionality but not locked + if retryCount >= maxRetries or ( + time.time() - startTime) > grabTimeout: + self.env['runtime']['debug'].writeDebugOut( + "Failed to grab devices after multiple attempts", debug.debugLevel.ERROR) + # Continue without grabbing input - limited functionality + # but not locked break time.sleep(0.25) - self.env['runtime']['debug'].writeDebugOut(f"retry grabAllDevices {retryCount}/{maxRetries}", debug.debugLevel.WARNING) + self.env['runtime']['debug'].writeDebugOut( + f"retry grabAllDevices {retryCount}/{maxRetries}", debug.debugLevel.WARNING) self.executeDeviceGrab = False @@ -112,8 +143,10 @@ class inputManager(): time.sleep(value) else: self.env['runtime']['inputDriver'].sendKey(key, value) + def getLastEvent(self): return self.lastEvent + def handleInputEvent(self, eventData): if not eventData: return @@ -129,34 +162,43 @@ class inputManager(): if eventData['EventName'] in self.env['input']['currInput']: self.env['input']['currInput'].remove(eventData['EventName']) if len(self.env['input']['currInput']) > 1: - self.env['input']['currInput'] = sorted(self.env['input']['currInput']) + self.env['input']['currInput'] = sorted( + self.env['input']['currInput']) elif len(self.env['input']['currInput']) == 0: - self.env['input']['shortcutRepeat'] = 1 + self.env['input']['shortcutRepeat'] = 1 self.lastInputTime = time.time() elif eventData['EventState'] == 1: if not eventData['EventName'] in self.env['input']['currInput']: self.env['input']['currInput'].append(eventData['EventName']) if len(self.env['input']['currInput']) > 1: - self.env['input']['currInput'] = sorted(self.env['input']['currInput']) - if len(self.lastDeepestInput) < len(self.env['input']['currInput']): - self.setLastDeepestInput( self.env['input']['currInput'].copy()) + self.env['input']['currInput'] = sorted( + self.env['input']['currInput']) + if len( + self.lastDeepestInput) < len( + self.env['input']['currInput']): + self.setLastDeepestInput( + self.env['input']['currInput'].copy()) elif self.lastDeepestInput == self.env['input']['currInput']: - if time.time() - self.lastInputTime <= self.env['runtime']['settingsManager'].getSettingAsFloat('keyboard','doubleTapTimeout'): + if time.time() - self.lastInputTime <= self.env['runtime']['settingsManager'].getSettingAsFloat( + 'keyboard', 'doubleTapTimeout'): self.env['input']['shortcutRepeat'] += 1 else: self.env['input']['shortcutRepeat'] = 1 self.handleLedStates(eventData) self.lastInputTime = time.time() elif eventData['EventState'] == 2: - self.lastInputTime = time.time() + self.lastInputTime = time.time() self.env['input']['oldNumLock'] = self.env['input']['newNumLock'] self.env['input']['newNumLock'] = self.env['runtime']['inputDriver'].getLedState() - self.env['input']['oldCapsLock'] = self.env['input']['newCapsLock'] - self.env['input']['newCapsLock'] = self.env['runtime']['inputDriver'].getLedState(1) - self.env['input']['oldScrollLock'] = self.env['input']['newScrollLock'] - self.env['input']['newScrollLock'] = self.env['runtime']['inputDriver'].getLedState(2) - self.env['runtime']['debug'].writeDebugOut("currInput " + str(self.env['input']['currInput'] ) ,debug.debugLevel.INFO) + self.env['input']['oldCapsLock'] = self.env['input']['newCapsLock'] + self.env['input']['newCapsLock'] = self.env['runtime']['inputDriver'].getLedState( + 1) + self.env['input']['oldScrollLock'] = self.env['input']['newScrollLock'] + self.env['input']['newScrollLock'] = self.env['runtime']['inputDriver'].getLedState( + 2) + self.env['runtime']['debug'].writeDebugOut( + "currInput " + str(self.env['input']['currInput']), debug.debugLevel.INFO) if self.noKeyPressed(): self.env['input']['prevInput'] = [] @@ -171,39 +213,54 @@ class inputManager(): elif mEvent['EventName'] == 'KEY_SCROLLLOCK': self.env['runtime']['inputDriver'].toggleLedState(2) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('inputManager handleLedStates: Error toggling LED state: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'inputManager handleLedStates: Error toggling LED state: ' + str(e), + debug.debugLevel.ERROR) + def grabAllDevices(self): - if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'): + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'keyboard', 'grabDevices'): try: return self.env['runtime']['inputDriver'].grabAllDevices() except Exception as e: return False return True + def ungrabAllDevices(self): - if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'): + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'keyboard', 'grabDevices'): try: return self.env['runtime']['inputDriver'].ungrabAllDevices() except Exception as e: return False return True + def handlePlugInputDevice(self, eventData): for deviceEntry in eventData: self.updateInputDevices(deviceEntry['device']) - def updateInputDevices(self, newDevice = None): + + def updateInputDevices(self, newDevice=None): try: self.env['runtime']['inputDriver'].updateInputDevices(newDevice) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('inputManager updateInputDevices: Error updating input devices: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'inputManager updateInputDevices: Error updating input devices: ' + str(e), + debug.debugLevel.ERROR) try: if self.env['runtime']['screenManager']: - self.handleDeviceGrab(force = True) + self.handleDeviceGrab(force=True) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('inputManager updateInputDevices: Error handling device grab: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'inputManager updateInputDevices: Error handling device grab: ' + str(e), + debug.debugLevel.ERROR) + def removeAllDevices(self): try: self.env['runtime']['inputDriver'].removeAllDevices() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('inputManager removeAllDevices: Error removing devices: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'inputManager removeAllDevices: Error removing devices: ' + str(e), + debug.debugLevel.ERROR) def convertEventName(self, eventName): if not eventName: @@ -238,27 +295,39 @@ class inputManager(): self.env['runtime']['inputDriver'].clearEventBuffer() except Exception as e: pass + def setLastDeepestInput(self, currentDeepestInput): self.lastDeepestInput = currentDeepestInput + def clearLastDeepInput(self): self.lastDeepestInput = [] + def getLastInputTime(self): return self.lastInputTime + def getLastDeepestInput(self): - return self.lastDeepestInput + return self.lastDeepestInput + def writeEventBuffer(self): try: - if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'): + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'keyboard', 'grabDevices'): self.env['runtime']['inputDriver'].writeEventBuffer() self.clearEventBuffer() except Exception as e: - self.env['runtime']['debug'].writeDebugOut("Error while writeUInput",debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "Error while writeUInput", debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) def noKeyPressed(self): return self.env['input']['currInput'] == [] + def isKeyPress(self): - return (self.env['input']['prevInput'] == []) and (self.env['input']['currInput'] != []) + return ( + self.env['input']['prevInput'] == []) and ( + self.env['input']['currInput'] != []) + def getPrevDeepestShortcut(self): shortcut = [] shortcut.append(self.env['input']['shortcutRepeat']) @@ -271,48 +340,72 @@ class inputManager(): shortcut.append(self.env['input']['prevInput']) return str(shortcut) - def getCurrShortcut(self, inputSequence = None): + def getCurrShortcut(self, inputSequence=None): shortcut = [] shortcut.append(self.env['input']['shortcutRepeat']) - numpadKeys = ['KEY_KP0', 'KEY_KP1', 'KEY_KP2', 'KEY_KP3', 'KEY_KP4', - 'KEY_KP5', 'KEY_KP6', 'KEY_KP7', 'KEY_KP8', 'KEY_KP9', - 'KEY_KPDOT', 'KEY_KPPLUS', 'KEY_KPMINUS', 'KEY_KPASTERISK', - 'KEY_KPSLASH', 'KEY_KPENTER', 'KEY_KPEQUAL'] + numpadKeys = [ + 'KEY_KP0', + 'KEY_KP1', + 'KEY_KP2', + 'KEY_KP3', + 'KEY_KP4', + 'KEY_KP5', + 'KEY_KP6', + 'KEY_KP7', + 'KEY_KP8', + 'KEY_KP9', + 'KEY_KPDOT', + 'KEY_KPPLUS', + 'KEY_KPMINUS', + 'KEY_KPASTERISK', + 'KEY_KPSLASH', + 'KEY_KPENTER', + 'KEY_KPEQUAL'] if inputSequence: # Check if any key in the sequence is a numpad key and numlock is ON - # If numlock is ON and any key in the sequence is a numpad key, return an empty shortcut - if not self.env['runtime']['cursorManager'].shouldProcessNumpadCommands(): + # If numlock is ON and any key in the sequence is a numpad key, + # return an empty shortcut + if not self.env['runtime']['cursorManager'].shouldProcessNumpadCommands( + ): for key in inputSequence: if key in numpadKeys: - # Return an empty/invalid shortcut that won't match any command + # Return an empty/invalid shortcut that won't match any + # command return "[]" shortcut.append(inputSequence) else: # Same check for current input - if not self.env['runtime']['cursorManager'].shouldProcessNumpadCommands(): + if not self.env['runtime']['cursorManager'].shouldProcessNumpadCommands( + ): for key in self.env['input']['currInput']: if key in numpadKeys: - # Return an empty/invalid shortcut that won't match any command + # Return an empty/invalid shortcut that won't match any + # command return "[]" shortcut.append(self.env['input']['currInput']) - if len(self.env['input']['prevInput']) < len(self.env['input']['currInput']): - if self.env['input']['shortcutRepeat'] > 1 and not self.shortcutExists(str(shortcut)): + if len( + self.env['input']['prevInput']) < len( + self.env['input']['currInput']): + if self.env['input']['shortcutRepeat'] > 1 and not self.shortcutExists( + str(shortcut)): shortcut = [] self.env['input']['shortcutRepeat'] = 1 shortcut.append(self.env['input']['shortcutRepeat']) shortcut.append(self.env['input']['currInput']) - self.env['runtime']['debug'].writeDebugOut("currShortcut " + str(shortcut), debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "currShortcut " + str(shortcut), debug.debugLevel.INFO) return str(shortcut) def currKeyIsModifier(self): if len(self.getLastDeepestInput()) != 1: return False - return (self.env['input']['currInput'][0] =='KEY_FENRIR') or (self.env['input']['currInput'][0] == 'KEY_SCRIPT') + return (self.env['input']['currInput'][0] == 'KEY_FENRIR') or ( + self.env['input']['currInput'][0] == 'KEY_SCRIPT') def isFenrirKey(self, eventName): return eventName in self.env['input']['fenrirKey'] @@ -322,9 +415,10 @@ class inputManager(): def getCommandForShortcut(self, shortcut): if not self.shortcutExists(shortcut): - return '' + return '' return self.env['bindings'][shortcut] - def keyEcho(self, eventData = None): + + def keyEcho(self, eventData=None): if not eventData: eventData = self.getLastEvent() if not eventData: @@ -334,29 +428,32 @@ class inputManager(): keyName = eventData['EventName'].lower() if keyName.startswith('key_'): keyName = keyName[4:] - self.env['runtime']['outputManager'].presentText(_(keyName), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _(keyName), interrupt=True) def shortcutExists(self, shortcut): - return(shortcut in self.env['bindings']) - def loadShortcuts(self, kbConfigPath=fenrirPath + '/../../config/keyboard/desktop.conf'): - kbConfig = open(kbConfigPath,"r") - while(True): + return (shortcut in self.env['bindings']) + + def loadShortcuts(self, kbConfigPath=fenrirPath + + '/../../config/keyboard/desktop.conf'): + kbConfig = open(kbConfigPath, "r") + while (True): invalid = False line = kbConfig.readline() if not line: break - line = line.replace('\n','') - if line.replace(" ","") == '': + line = line.replace('\n', '') + if line.replace(" ", "") == '': continue - if line.replace(" ","").startswith("#"): + if line.replace(" ", "").startswith("#"): continue if line.count("=") != 1: continue sepLine = line.split('=') commandName = sepLine[1].upper() - sepLine[0] = sepLine[0].replace(" ","") - sepLine[0] = sepLine[0].replace("'","") - sepLine[0] = sepLine[0].replace('"',"") + sepLine[0] = sepLine[0].replace(" ", "") + sepLine[0] = sepLine[0].replace("'", "") + sepLine[0] = sepLine[0].replace('"', "") keys = sepLine[0].split(',') shortcutKeys = [] shortcutRepeat = 1 @@ -366,38 +463,57 @@ class inputManager(): shortcutRepeat = int(key) except Exception as e: if not self.isValidKey(key.upper()): - self.env['runtime']['debug'].writeDebugOut("invalid key : "+ key.upper() + ' command:' +commandName ,debug.debugLevel.WARNING) + self.env['runtime']['debug'].writeDebugOut( + "invalid key : " + key.upper() + ' command:' + commandName, + debug.debugLevel.WARNING) invalid = True break - shortcutKeys.append(key.upper()) + shortcutKeys.append(key.upper()) if invalid: continue shortcut.append(shortcutRepeat) shortcut.append(sorted(shortcutKeys)) - if len(shortcutKeys) != 1 and not 'KEY_FENRIR' in shortcutKeys: - self.env['runtime']['debug'].writeDebugOut("invalid shortcut (missing KEY_FENRIR): "+ str(shortcut) + ' command:' +commandName ,debug.debugLevel.ERROR) + if len(shortcutKeys) != 1 and 'KEY_FENRIR' not in shortcutKeys: + self.env['runtime']['debug'].writeDebugOut( + "invalid shortcut (missing KEY_FENRIR): " + + str(shortcut) + + ' command:' + + commandName, + debug.debugLevel.ERROR) continue - self.env['runtime']['debug'].writeDebugOut("Shortcut: "+ str(shortcut) + ' command:' +commandName ,debug.debugLevel.INFO, onAnyLevel=True) + self.env['runtime']['debug'].writeDebugOut( + "Shortcut: " + + str(shortcut) + + ' command:' + + commandName, + debug.debugLevel.INFO, + onAnyLevel=True) self.env['bindings'][str(shortcut)] = commandName self.env['rawBindings'][str(shortcut)] = shortcut kbConfig.close() - # fix bindings - self.env['bindings'][str([1, ['KEY_F1', 'KEY_FENRIR']])] = 'TOGGLE_TUTORIAL_MODE' + # fix bindings + self.env['bindings'][str( + [1, ['KEY_F1', 'KEY_FENRIR']])] = 'TOGGLE_TUTORIAL_MODE' + def isValidKey(self, key): return key in inputData.keyNames + def setLastDetectedDevices(self, devices): - self.lastDetectedDevices =devices + self.lastDetectedDevices = devices + def getLastDetectedDevices(self): return self.lastDetectedDevices + def reloadShortcuts(self): """Reload keyboard shortcuts from current layout setting""" # Clear existing bindings self.env['bindings'].clear() self.env['rawBindings'].clear() - + # Get current layout path - layout_setting = self.env['runtime']['settingsManager'].getSetting('keyboard', 'keyboardLayout') - + layout_setting = self.env['runtime']['settingsManager'].getSetting( + 'keyboard', 'keyboardLayout') + # Resolve full path if needed if not os.path.exists(layout_setting): settingsRoot = '/etc/fenrirscreenreader/' @@ -405,19 +521,19 @@ class inputManager(): import fenrirscreenreader fenrirPath = os.path.dirname(fenrirscreenreader.__file__) settingsRoot = fenrirPath + '/../../config/' - + layout_path = settingsRoot + 'keyboard/' + layout_setting + '.conf' if not os.path.exists(layout_path): # Fallback to default if layout not found layout_path = settingsRoot + 'keyboard/desktop.conf' else: layout_path = layout_setting - + # Reload shortcuts self.loadShortcuts(layout_path) - + self.env['runtime']['debug'].writeDebugOut( - "Reloaded shortcuts from: " + layout_path, - debug.debugLevel.INFO, + "Reloaded shortcuts from: " + layout_path, + debug.debugLevel.INFO, onAnyLevel=True ) diff --git a/src/fenrirscreenreader/core/memoryManager.py b/src/fenrirscreenreader/core/memoryManager.py index b6c21f5e..220228c5 100644 --- a/src/fenrirscreenreader/core/memoryManager.py +++ b/src/fenrirscreenreader/core/memoryManager.py @@ -7,120 +7,151 @@ import time from fenrirscreenreader.core import debug + class memoryManager(): def __init__(self): self.listStorage = {} + def initialize(self, environment): self.env = environment + def shutdown(self): pass - def listStorageValid(self,name, checkIndex = False): + + def listStorageValid(self, name, checkIndex=False): try: if checkIndex: index = self.listStorage[name]['index'] if index == -1: - return self.listStorage[name]['list'] == [] - return self.listStorage[name]['list'][index] != None + return self.listStorage[name]['list'] == [] + return self.listStorage[name]['list'][index] is not None else: - return isinstance(self.listStorage[name]['list'],list) + return isinstance(self.listStorage[name]['list'], list) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("listStorageValid " + str(e),debug.debugLevel.ERROR) - return False + self.env['runtime']['debug'].writeDebugOut( + "listStorageValid " + str(e), debug.debugLevel.ERROR) + return False + def addValueToFirstIndex(self, name, value): if not self.listStorageValid(name): return - if self.listStorage[name]['maxLength'] == None: + if self.listStorage[name]['maxLength'] is None: # Fallback: if maxLength is still None, apply default limit of 1000 - self.listStorage[name]['list'] = [value] + self.listStorage[name]['list'][:999] - else: - self.listStorage[name]['list'] = [value] + self.listStorage[name]['list'][:self.listStorage[name]['maxLength'] -1] + self.listStorage[name]['list'] = [value] + \ + self.listStorage[name]['list'][:999] + else: + self.listStorage[name]['list'] = [ + value] + self.listStorage[name]['list'][:self.listStorage[name]['maxLength'] - 1] self.listStorage[name]['index'] = 0 - def addIndexList(self, name, maxLength = 1000, currList = [], currIndex = -1): + + def addIndexList(self, name, maxLength=1000, currList=[], currIndex=-1): if len(currList) != 0 and (currIndex == -1): currIndex = 0 - self.listStorage[name] = {'list': currList, 'index': currIndex, 'maxLength': maxLength} + self.listStorage[name] = { + 'list': currList, + 'index': currIndex, + 'maxLength': maxLength} + def isLastIndex(self, name): if not self.listStorageValid(name): - return False - return self.listStorage[name]['index'] == len(self.listStorage[name]['list']) - 1 + return False + return self.listStorage[name]['index'] == len( + self.listStorage[name]['list']) - 1 + def isFirstIndex(self, name): if not self.listStorageValid(name): - return False - return self.listStorage[name]['index'] == 0 + return False + return self.listStorage[name]['index'] == 0 + def getNextIndex(self, name): if not self.listStorageValid(name): - return False + return False if self.isIndexListEmpty(name): self.listStorage[name]['index'] = -1 return False self.listStorage[name]['index'] += 1 - if self.listStorage[name]['index'] > len(self.listStorage[name]['list']) -1: + if self.listStorage[name]['index'] > len( + self.listStorage[name]['list']) - 1: self.listStorage[name]['index'] = 0 - return True + return True + def setPrefIndex(self, name): if not self.listStorageValid(name): - return False + return False if self.isIndexListEmpty(name): self.listStorage[name]['index'] = -1 return False self.listStorage[name]['index'] -= 1 if self.listStorage[name]['index'] < 0: - self.listStorage[name]['index'] = len(self.listStorage[name]['list']) -1 + self.listStorage[name]['index'] = len( + self.listStorage[name]['list']) - 1 return True + def setFirstIndex(self, name): if not self.listStorageValid(name): - return False + return False if self.isIndexListEmpty(name): self.listStorage[name]['index'] = -1 return False self.listStorage[name]['index'] = 0 return True + def getIndexListLen(self, name): if not self.listStorageValid(name): - return 0 + return 0 if self.isIndexListEmpty(name): self.listStorage[name]['index'] = -1 - return 0 + return 0 return len(self.listStorage[name]) + def setLastIndex(self, name): if not self.listStorageValid(name): - return False + return False if self.isIndexListEmpty(name): self.listStorage[name]['index'] = -1 return False - self.listStorage[name]['index'] = len(self.listStorage[name]['list']) -1 - return True + self.listStorage[name]['index'] = len( + self.listStorage[name]['list']) - 1 + return True + def clearCurrentIndexList(self, name): if not self.listStorageValid(name): - return False + return False self.listStorage[name]['list'] = [] self.listStorage[name]['index'] = -1 - def getCurrentIndex(self,name): + + def getCurrentIndex(self, name): if not self.listStorageValid(name): - return False + return False if self.isIndexListEmpty(name): self.listStorage[name]['index'] = -1 - return False - try: - return self.listStorage[name]['index'] + return False + try: + return self.listStorage[name]['index'] except Exception as e: - self.env['runtime']['debug'].writeDebugOut('memoryManager getCurrentIndex: Error accessing index for ' + name + ': ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'memoryManager getCurrentIndex: Error accessing index for ' + name + ': ' + str(e), + debug.debugLevel.ERROR) return -1 + def isIndexListEmpty(self, name): if not self.listStorageValid(name): - return False + return False return len(self.listStorage[name]['list']) == 0 + def getIndexListElement(self, name): if not self.listStorageValid(name): - return None + return None if self.isIndexListEmpty(name): self.listStorage[name]['index'] = -1 - return None + return None currIndex = self.getCurrentIndex(name) if currIndex == -1: return None - try: + try: return self.listStorage[name]['list'][currIndex] except Exception as e: - self.env['runtime']['debug'].writeDebugOut('memoryManager getIndexListElement: Error accessing element for ' + name + ': ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'memoryManager getIndexListElement: Error accessing element for ' + name + ': ' + str(e), + debug.debugLevel.ERROR) return None diff --git a/src/fenrirscreenreader/core/outputData.py b/src/fenrirscreenreader/core/outputData.py index ca1729f6..cb5d89dd 100644 --- a/src/fenrirscreenreader/core/outputData.py +++ b/src/fenrirscreenreader/core/outputData.py @@ -8,8 +8,8 @@ import time from fenrirscreenreader.core import debug outputData = { -'nextFlush': time.time(), -'messageText': '', -'messageOffset': None, -'cursorOffset': None, + 'nextFlush': time.time(), + 'messageText': '', + 'messageOffset': None, + 'cursorOffset': None, } diff --git a/src/fenrirscreenreader/core/outputManager.py b/src/fenrirscreenreader/core/outputManager.py index 87a9868c..522b72fd 100644 --- a/src/fenrirscreenreader/core/outputManager.py +++ b/src/fenrirscreenreader/core/outputManager.py @@ -5,8 +5,12 @@ # By Chrys, Storm Dragon, and contributors. from fenrirscreenreader.core import debug +from fenrirscreenreader.core.i18n import _ from fenrirscreenreader.utils import line_utils -import string, time, re +import string +import time +import re + class outputManager(): def __init__(self): @@ -15,22 +19,38 @@ class outputManager(): def initialize(self, environment): self.env = environment self.env['runtime']['settingsManager'].loadDriver( - self.env['runtime']['settingsManager'].getSetting('speech', 'driver'), 'speechDriver') + self.env['runtime']['settingsManager'].getSetting( + 'speech', 'driver'), 'speechDriver') self.env['runtime']['settingsManager'].loadDriver( - self.env['runtime']['settingsManager'].getSetting('sound', 'driver'), 'soundDriver') + self.env['runtime']['settingsManager'].getSetting( + 'sound', 'driver'), 'soundDriver') def shutdown(self): self.env['runtime']['settingsManager'].shutdownDriver('soundDriver') self.env['runtime']['settingsManager'].shutdownDriver('speechDriver') - def presentText(self, text, interrupt=True, soundIcon='', ignorePunctuation=False, announceCapital=False, flush=True): + def presentText( + self, + text, + interrupt=True, + soundIcon='', + ignorePunctuation=False, + announceCapital=False, + flush=True): if text == '': return - if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'readNumbersAsDigits') and len(text.strip()) > 1: + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'speech', 'readNumbersAsDigits') and len(text.strip()) > 1: text = re.sub(r"(\d)", r"\1 ", text).rstrip() - self.env['runtime']['debug'].writeDebugOut("presentText:\nsoundIcon:'"+soundIcon+"'\nText:\n" + text, debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "presentText:\nsoundIcon:'" + + soundIcon + + "'\nText:\n" + + text, + debug.debugLevel.INFO) if self.playSoundIcon(soundIcon, interrupt): - self.env['runtime']['debug'].writeDebugOut("soundIcon found", debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "soundIcon found", debug.debugLevel.INFO) return if (len(text) > 1) and (text.strip(string.whitespace) == ''): return @@ -44,151 +64,230 @@ class outputManager(): def getLastEcho(self): return self.lastEcho - def speakText(self, text, interrupt=True, ignorePunctuation=False, announceCapital=False): - if not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled'): - self.env['runtime']['debug'].writeDebugOut("Speech disabled in outputManager.speakText", debug.debugLevel.INFO) + def speakText( + self, + text, + interrupt=True, + ignorePunctuation=False, + announceCapital=False): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'speech', 'enabled'): + self.env['runtime']['debug'].writeDebugOut( + "Speech disabled in outputManager.speakText", debug.debugLevel.INFO) return - if self.env['runtime']['speechDriver'] == None: - self.env['runtime']['debug'].writeDebugOut("No speechDriver in outputManager.speakText", debug.debugLevel.ERROR) + if self.env['runtime']['speechDriver'] is None: + self.env['runtime']['debug'].writeDebugOut( + "No speechDriver in outputManager.speakText", debug.debugLevel.ERROR) return if interrupt: self.interruptOutput() try: - self.env['runtime']['speechDriver'].setLanguage(self.env['runtime']['settingsManager'].getSetting('speech', 'language')) + self.env['runtime']['speechDriver'].setLanguage( + self.env['runtime']['settingsManager'].getSetting( + 'speech', 'language')) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("setting speech language in outputManager.speakText", debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "setting speech language in outputManager.speakText", debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) try: - self.env['runtime']['speechDriver'].setVoice(self.env['runtime']['settingsManager'].getSetting('speech', 'voice')) + self.env['runtime']['speechDriver'].setVoice( + self.env['runtime']['settingsManager'].getSetting( + 'speech', 'voice')) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("Error while setting speech voice in outputManager.speakText", debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "Error while setting speech voice in outputManager.speakText", + debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) try: if announceCapital: - self.env['runtime']['speechDriver'].setPitch(self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'capitalPitch')) + self.env['runtime']['speechDriver'].setPitch( + self.env['runtime']['settingsManager'].getSettingAsFloat( + 'speech', 'capitalPitch')) else: - self.env['runtime']['speechDriver'].setPitch(self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'pitch')) + self.env['runtime']['speechDriver'].setPitch( + self.env['runtime']['settingsManager'].getSettingAsFloat( + 'speech', 'pitch')) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("setting speech pitch in outputManager.speakText", debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "setting speech pitch in outputManager.speakText", debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) try: - self.env['runtime']['speechDriver'].setRate(self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'rate')) + self.env['runtime']['speechDriver'].setRate( + self.env['runtime']['settingsManager'].getSettingAsFloat( + 'speech', 'rate')) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("setting speech rate in outputManager.speakText", debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "setting speech rate in outputManager.speakText", debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) try: - self.env['runtime']['speechDriver'].setModule(self.env['runtime']['settingsManager'].getSetting('speech', 'module')) + self.env['runtime']['speechDriver'].setModule( + self.env['runtime']['settingsManager'].getSetting( + 'speech', 'module')) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("setting speech module in outputManager.speakText", debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "setting speech module in outputManager.speakText", debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) try: - self.env['runtime']['speechDriver'].setVolume(self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'volume')) + self.env['runtime']['speechDriver'].setVolume( + self.env['runtime']['settingsManager'].getSettingAsFloat( + 'speech', 'volume')) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("setting speech volume in outputManager.speakText ", debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "setting speech volume in outputManager.speakText ", debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) try: - if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'newLinePause'): + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'newLinePause'): cleanText = text.replace('\n', ' , ') else: cleanText = text.replace('\n', ' ') - cleanText = self.env['runtime']['textManager'].replaceHeadLines(cleanText) - cleanText = self.env['runtime']['punctuationManager'].proceedPunctuation(cleanText, ignorePunctuation) - cleanText = re.sub(' +$', ' ', cleanText) - self.env['runtime']['speechDriver'].speak(cleanText, True, ignorePunctuation) - self.env['runtime']['debug'].writeDebugOut("Speak: "+ cleanText, debug.debugLevel.INFO) + cleanText = self.env['runtime']['textManager'].replaceHeadLines( + cleanText) + cleanText = self.env['runtime']['punctuationManager'].proceedPunctuation( + cleanText, ignorePunctuation) + cleanText = re.sub(' +$', ' ', cleanText) + self.env['runtime']['speechDriver'].speak( + cleanText, True, ignorePunctuation) + self.env['runtime']['debug'].writeDebugOut( + "Speak: " + cleanText, debug.debugLevel.INFO) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("\"speak\" in outputManager.speakText ", debug.debugLevel.ERROR) - self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "\"speak\" in outputManager.speakText ", debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) def interruptOutput(self): try: self.env['runtime']['speechDriver'].cancel() - self.env['runtime']['debug'].writeDebugOut("Interrupt speech", debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "Interrupt speech", debug.debugLevel.INFO) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('outputManager interruptOutput: Error canceling speech: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'outputManager interruptOutput: Error canceling speech: ' + str(e), + debug.debugLevel.ERROR) def playSoundIcon(self, soundIcon='', interrupt=True): if soundIcon == '': return False soundIcon = soundIcon.upper() - if not self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled'): - self.env['runtime']['debug'].writeDebugOut("Sound disabled in outputManager.playSoundIcon", debug.debugLevel.INFO) - return False + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'sound', 'enabled'): + self.env['runtime']['debug'].writeDebugOut( + "Sound disabled in outputManager.playSoundIcon", debug.debugLevel.INFO) + return False try: e = self.env['soundIcons'][soundIcon] except Exception as e: - self.env['runtime']['debug'].writeDebugOut('outputManager playSoundIcon: SoundIcon does not exist ' + soundIcon + ': ' + str(e), debug.debugLevel.WARNING) + self.env['runtime']['debug'].writeDebugOut( + 'outputManager playSoundIcon: SoundIcon does not exist ' + soundIcon + ': ' + str(e), + debug.debugLevel.WARNING) return False - if self.env['runtime']['soundDriver'] == None: - self.env['runtime']['debug'].writeDebugOut("No soundDriver in outputManager.playSoundIcon: soundDriver not loaded", debug.debugLevel.ERROR) + if self.env['runtime']['soundDriver'] is None: + self.env['runtime']['debug'].writeDebugOut( + "No soundDriver in outputManager.playSoundIcon: soundDriver not loaded", + debug.debugLevel.ERROR) return False try: - self.env['runtime']['soundDriver'].setVolume(self.env['runtime']['settingsManager'].getSettingAsFloat('sound', 'volume')) + self.env['runtime']['soundDriver'].setVolume( + self.env['runtime']['settingsManager'].getSettingAsFloat( + 'sound', 'volume')) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::setVolume: " + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "outputManager.playSoundIcon::setVolume: " + str(e), debug.debugLevel.ERROR) try: - self.env['runtime']['soundDriver'].playSoundFile(self.env['soundIcons'][soundIcon], interrupt) + self.env['runtime']['soundDriver'].playSoundFile( + self.env['soundIcons'][soundIcon], interrupt) return True except Exception as e: - self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::playSoundFile: " + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "outputManager.playSoundIcon::playSoundFile: " + str(e), + debug.debugLevel.ERROR) return False return False def playFrequence(self, frequence, duration, interrupt=True): - if not self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled'): - self.env['runtime']['debug'].writeDebugOut("Sound disabled in outputManager.playFrequence", debug.debugLevel.INFO) + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'sound', 'enabled'): + self.env['runtime']['debug'].writeDebugOut( + "Sound disabled in outputManager.playFrequence", debug.debugLevel.INFO) return False if frequence < 1 or frequence > 20000: - self.env['runtime']['debug'].writeDebugOut("outputManager.playFrequence::Filefrequence is out of range:" + str(frequence), debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "outputManager.playFrequence::Filefrequence is out of range:" + + str(frequence), + debug.debugLevel.INFO) return False - if self.env['runtime']['soundDriver'] == None: - self.env['runtime']['debug'].writeDebugOut("No soundDriver in outputManager.playFrequence: soundDriver not loaded", debug.debugLevel.ERROR) + if self.env['runtime']['soundDriver'] is None: + self.env['runtime']['debug'].writeDebugOut( + "No soundDriver in outputManager.playFrequence: soundDriver not loaded", + debug.debugLevel.ERROR) return False try: - self.env['runtime']['soundDriver'].setVolume(self.env['runtime']['settingsManager'].getSettingAsFloat('sound', 'volume')) + self.env['runtime']['soundDriver'].setVolume( + self.env['runtime']['settingsManager'].getSettingAsFloat( + 'sound', 'volume')) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::setVolume: " + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "outputManager.playSoundIcon::setVolume: " + str(e), debug.debugLevel.ERROR) adjustVolume = 0.0 try: adjustVolume = 1.0 - (frequence / 20000) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('outputManager playFrequence: Error calculating adjust volume: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'outputManager playFrequence: Error calculating adjust volume: ' + str(e), + debug.debugLevel.ERROR) if adjustVolume > 9.0: adjustVolume = 9.0 try: - self.env['runtime']['soundDriver'].playFrequence(frequence, duration, adjustVolume, interrupt) + self.env['runtime']['soundDriver'].playFrequence( + frequence, duration, adjustVolume, interrupt) return True except Exception as e: - self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::playSoundFile: " + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "outputManager.playSoundIcon::playSoundFile: " + str(e), + debug.debugLevel.ERROR) return False return False def tempDisableSpeech(self): - if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled'): - self.presentText(_("speech temporary disabled"), soundIcon='SpeechOff', interrupt=True) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'speech', 'enabled'): + self.presentText( + _("speech temporary disabled"), + soundIcon='SpeechOff', + interrupt=True) self.env['commandBuffer']['enableSpeechOnKeypress'] = True # Also enable prompt watching for automatic speech restoration if 'silenceUntilPrompt' not in self.env['commandBuffer']: self.env['commandBuffer']['silenceUntilPrompt'] = False self.env['commandBuffer']['silenceUntilPrompt'] = True - self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', str(not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled'))) + self.env['runtime']['settingsManager'].setSetting( + 'speech', 'enabled', str( + not self.env['runtime']['settingsManager'].getSettingAsBool( + 'speech', 'enabled'))) self.interruptOutput() def announceActiveCursor(self, interrupt_p=False): @@ -202,6 +301,8 @@ class outputManager(): if 'speechDriver' in self.env['runtime'] and self.env['runtime']['speechDriver']: try: self.env['runtime']['speechDriver'].reset() - self.env['runtime']['debug'].writeDebugOut("Speech driver reset successfully", debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "Speech driver reset successfully", debug.debugLevel.INFO) except Exception as e: - self.env['runtime']['debug'].writeDebugOut(f"resetSpeechDriver error: {e}", debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + f"resetSpeechDriver error: {e}", debug.debugLevel.ERROR) diff --git a/src/fenrirscreenreader/core/processManager.py b/src/fenrirscreenreader/core/processManager.py index c75eee78..d7c2b93f 100644 --- a/src/fenrirscreenreader/core/processManager.py +++ b/src/fenrirscreenreader/core/processManager.py @@ -6,61 +6,102 @@ from fenrirscreenreader.core import debug from fenrirscreenreader.core.eventData import fenrirEventType -import time, signal +import time +import signal from threading import Thread from multiprocessing import Process + class processManager(): def __init__(self): self._Processes = [] - self._Threads = [] + self._Threads = [] + def initialize(self, environment): - self.env = environment + self.env = environment self.running = self.env['runtime']['eventManager'].getRunning() - self.addSimpleEventThread(fenrirEventType.HeartBeat, self.heartBeatTimer, multiprocess=True) + self.addSimpleEventThread( + fenrirEventType.HeartBeat, + self.heartBeatTimer, + multiprocess=True) + def shutdown(self): self.terminateAllProcesses() def terminateAllProcesses(self): for proc in self._Processes: - #try: + # try: # proc.terminate() - #except KeyboardInterrupt: + # except KeyboardInterrupt: # pass - #except: + # except: # pass proc.join(timeout=5.0) # Timeout to prevent hanging shutdown for t in self._Threads: t.join(timeout=5.0) # Timeout to prevent hanging shutdown + def heartBeatTimer(self, active): try: time.sleep(0.5) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('processManager heartBeatTimer: Error during sleep: ' + str(e), debug.debugLevel.ERROR) - return time.time() - def addCustomEventThread(self, function, pargs = None, multiprocess = False, runOnce = False): + self.env['runtime']['debug'].writeDebugOut( + 'processManager heartBeatTimer: Error during sleep: ' + str(e), + debug.debugLevel.ERROR) + return time.time() + + def addCustomEventThread( + self, + function, + pargs=None, + multiprocess=False, + runOnce=False): eventQueue = self.env['runtime']['eventManager'].getEventQueue() - original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) - if multiprocess: - t = Process(target=self.customEventWorkerThread, args=(eventQueue, function, pargs, runOnce)) - self._Processes.append(t) - else:# thread not implemented yet - t = Thread(target=self.customEventWorkerThread, args=(eventQueue, function, pargs, runOnce)) - self._Threads.append(t) - t.start() - signal.signal(signal.SIGINT, original_sigint_handler) - def addSimpleEventThread(self, event, function, pargs = None, multiprocess = False, runOnce = False): - original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) + original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) if multiprocess: - t = Process(target=self.simpleEventWorkerThread, args=(event, function, pargs, runOnce)) - self._Processes.append(t) - else: - t = Thread(target=self.simpleEventWorkerThread, args=(event, function, pargs, runOnce)) - self._Threads.append(t) + t = Process( + target=self.customEventWorkerThread, args=( + eventQueue, function, pargs, runOnce)) + self._Processes.append(t) + else: # thread not implemented yet + t = Thread( + target=self.customEventWorkerThread, + args=( + eventQueue, + function, + pargs, + runOnce)) + self._Threads.append(t) t.start() - signal.signal(signal.SIGINT, original_sigint_handler) - def customEventWorkerThread(self, eventQueue, function, pargs = None, runOnce = False): - #if not isinstance(eventQueue, Queue): + signal.signal(signal.SIGINT, original_sigint_handler) + + def addSimpleEventThread( + self, + event, + function, + pargs=None, + multiprocess=False, + runOnce=False): + original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) + if multiprocess: + t = Process( + target=self.simpleEventWorkerThread, args=( + event, function, pargs, runOnce)) + self._Processes.append(t) + else: + t = Thread( + target=self.simpleEventWorkerThread, args=( + event, function, pargs, runOnce)) + self._Threads.append(t) + t.start() + signal.signal(signal.SIGINT, original_sigint_handler) + + def customEventWorkerThread( + self, + eventQueue, + function, + pargs=None, + runOnce=False): + # if not isinstance(eventQueue, Queue): # return if not callable(function): return @@ -71,11 +112,21 @@ class processManager(): else: function(self.running, eventQueue) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('processManager:customEventWorkerThread:function('+str(function)+'):' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'processManager:customEventWorkerThread:function(' + + str(function) + + '):' + + str(e), + debug.debugLevel.ERROR) if runOnce: break - def simpleEventWorkerThread(self, event, function, pargs = None, runOnce = False): + def simpleEventWorkerThread( + self, + event, + function, + pargs=None, + runOnce=False): if not isinstance(event, fenrirEventType): return if not callable(function): @@ -84,11 +135,16 @@ class processManager(): Data = None try: if pargs: - Data = function(self.running, pargs) + Data = function(self.running, pargs) else: Data = function(self.running) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('processManager:simpleEventWorkerThread:function('+str(function)+'):' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'processManager:simpleEventWorkerThread:function(' + + str(function) + + '):' + + str(e), + debug.debugLevel.ERROR) self.env['runtime']['eventManager'].putToEventQueue(event, Data) if runOnce: break diff --git a/src/fenrirscreenreader/core/punctuationData.py b/src/fenrirscreenreader/core/punctuationData.py index cb633fff..289caa85 100644 --- a/src/fenrirscreenreader/core/punctuationData.py +++ b/src/fenrirscreenreader/core/punctuationData.py @@ -9,14 +9,14 @@ import string from collections import OrderedDict punctuationData = { -'LEVELDICT':{ - 'none': '', - 'some': '#-$~+*-/\\@', - 'most': '.,:-$~ +*-/\\@!#%^&*()[]}{<>;', - 'all': string.punctuation + ' §', - }, -'PUNCTDICT':{ - }, -'CUSTOMDICT':OrderedDict(), -'EMOTICONDICT':OrderedDict(), + 'LEVELDICT': { + 'none': '', + 'some': '#-$~+*-/\\@', + 'most': '.,:-$~ +*-/\\@!#%^&*()[]}{<>;', + 'all': string.punctuation + ' §', + }, + 'PUNCTDICT': { + }, + 'CUSTOMDICT': OrderedDict(), + 'EMOTICONDICT': OrderedDict(), } diff --git a/src/fenrirscreenreader/core/punctuationManager.py b/src/fenrirscreenreader/core/punctuationManager.py index 8f351ffe..420c2c91 100644 --- a/src/fenrirscreenreader/core/punctuationManager.py +++ b/src/fenrirscreenreader/core/punctuationManager.py @@ -6,26 +6,45 @@ import string from fenrirscreenreader.core import debug -import os, inspect, re -currentdir = os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe())))) +import os +import inspect +import re +currentdir = os.path.dirname( + os.path.realpath( + os.path.abspath( + inspect.getfile( + inspect.currentframe())))) fenrirPath = os.path.dirname(currentdir) + class punctuationManager(): def __init__(self): pass + def initialize(self, environment): self.env = environment - self.allPunctNone = dict.fromkeys(map(ord, string.punctuation +"§ "), ' ') - # replace with None: + self.allPunctNone = dict.fromkeys( + map(ord, string.punctuation + "§ "), ' ') + # replace with None: # dot, comma, grave, apostrophe - #for char in [ord('`'),ord("'")]: + # for char in [ord('`'),ord("'")]: # self.allPunctNone[char] = None # dont restore the following (for announce correct pause) - for char in [ord("'"),ord('.'), ord(','), ord(';'), ord(':'), ord('?'), ord('!'), ord('-')]: + for char in [ + ord("'"), + ord('.'), + ord(','), + ord(';'), + ord(':'), + ord('?'), + ord('!'), + ord('-')]: self.allPunctNone[char] = chr(char) + def shutdown(self): pass - def removeUnused(self, text, currLevel = ''): + + def removeUnused(self, text, currLevel=''): # dont translate dot and comma because they create a pause currAllPunctNone = self.allPunctNone.copy() for char in currLevel: @@ -34,84 +53,112 @@ class punctuationManager(): except Exception as e: pass return text.translate(currAllPunctNone) + def useCustomDict(self, text, customDict, seperator=''): resultText = str(text) if customDict: - for key,item in customDict.items(): + for key, item in customDict.items(): try: regexLbl = 'REGEX;' if key.upper().startswith(regexLbl) and (len(key) > len(regexLbl)): - resultText = re.sub(str(key[len(regexLbl):]), seperator + str(item) + seperator, resultText) + resultText = re.sub( + str(key[len(regexLbl):]), seperator + str(item) + seperator, resultText) else: - resultText = resultText.replace(str(key),seperator + str(item) + seperator) + resultText = resultText.replace( + str(key), seperator + str(item) + seperator) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("useCustomDict replace:'" + key + "' with '" + item +"' failed:" + str(e),debug.debugLevel.ERROR, onAnyLevel=False) + self.env['runtime']['debug'].writeDebugOut( + "useCustomDict replace:'" + + key + + "' with '" + + item + + "' failed:" + + str(e), + debug.debugLevel.ERROR, + onAnyLevel=False) return resultText + def usePunctuationDict(self, text, punctuationDict, punctuation): resultText = str(text) if punctuationDict and punctuation and punctuation != '': if ' ' in punctuation: - resultText = resultText.replace(' ',' ' + punctuationDict[' '] + ' ') - for key,item in punctuationDict.items(): + resultText = resultText.replace( + ' ', ' ' + punctuationDict[' '] + ' ') + for key, item in punctuationDict.items(): if (punctuation != '' and key in punctuation) and key not in ' ': - if self.env['runtime']['settingsManager'].getSetting('general', 'respectPunctuationPause') and \ - len(key) == 1 and \ - key in "',.;:?!": - resultText = resultText.replace(str(key),' ' +str(item) + str(key) + ' ') + if self.env['runtime']['settingsManager'].getSetting( + 'general', 'respectPunctuationPause') and len(key) == 1 and key in "',.;:?!": + resultText = resultText.replace( + str(key), ' ' + str(item) + str(key) + ' ') else: - resultText = resultText.replace(str(key),' ' +str(item) + ' ') + resultText = resultText.replace( + str(key), ' ' + str(item) + ' ') return resultText + def isPuctuation(self, char): return char in self.env['punctuation']['PUNCTDICT'] + def proceedPunctuation(self, text, ignorePunctuation=False): if ignorePunctuation: return text resultText = text - resultText = self.useCustomDict(resultText, self.env['punctuation']['CUSTOMDICT']) - if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'emoticons'): - resultText = self.useCustomDict(resultText, self.env['punctuation']['EMOTICONDICT'], ' ') + resultText = self.useCustomDict( + resultText, self.env['punctuation']['CUSTOMDICT']) + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'general', 'emoticons'): + resultText = self.useCustomDict( + resultText, self.env['punctuation']['EMOTICONDICT'], ' ') currPunctLevel = '' - if self.env['runtime']['settingsManager'].getSetting('general', 'punctuationLevel').lower() in self.env['punctuation']['LEVELDICT']: - currPunctLevel = self.env['punctuation']['LEVELDICT'][self.env['runtime']['settingsManager'].getSetting('general', 'punctuationLevel').lower()] + if self.env['runtime']['settingsManager'].getSetting( + 'general', 'punctuationLevel').lower() in self.env['punctuation']['LEVELDICT']: + currPunctLevel = self.env['punctuation']['LEVELDICT'][self.env['runtime'][ + 'settingsManager'].getSetting('general', 'punctuationLevel').lower()] else: - currPunctLevel = string.punctuation +' §' - resultText = self.usePunctuationDict(resultText, self.env['punctuation']['PUNCTDICT'], currPunctLevel) + currPunctLevel = string.punctuation + ' §' + resultText = self.usePunctuationDict( + resultText, self.env['punctuation']['PUNCTDICT'], currPunctLevel) resultText = self.removeUnused(resultText, currPunctLevel) return resultText def cyclePunctuation(self): punctList = list(self.env['punctuation']['LEVELDICT'].keys()) try: - currIndex = punctList.index(self.env['runtime']['settingsManager'].getSetting('general', 'punctuationLevel').lower()) # curr punctuation + currIndex = punctList.index( + self.env['runtime']['settingsManager'].getSetting( + 'general', 'punctuationLevel').lower()) # curr punctuation except Exception as e: return False currIndex += 1 if currIndex >= len(punctList): currIndex = 0 currLevel = punctList[currIndex] - self.env['runtime']['settingsManager'].setSetting('general', 'punctuationLevel', currLevel.lower()) + self.env['runtime']['settingsManager'].setSetting( + 'general', 'punctuationLevel', currLevel.lower()) return True - def loadDicts(self, dictConfigPath=fenrirPath + '/../../config/punctuation/default.conf'): - dictConfig = open(dictConfigPath,"r") + + def loadDicts(self, dictConfigPath=fenrirPath + + '/../../config/punctuation/default.conf'): + dictConfig = open(dictConfigPath, "r") currDictName = '' - while(True): + while (True): line = dictConfig.readline() if not line: break - line = line.replace('\n','') - if line.replace(" ","") == '': + line = line.replace('\n', '') + if line.replace(" ", "") == '': continue - if line.replace(" ","").startswith("#"): - if not line.replace(" ","").startswith("#:===:"): + if line.replace(" ", "").startswith("#"): + if not line.replace(" ", "").startswith("#:===:"): continue - if line.replace(" ","").upper().startswith("[") and \ - line.replace(" ","").upper().endswith("DICT]"): - currDictName = line[line.find('[') + 1 :line.upper().find('DICT]') + 4].upper() + if line.replace(" ", "").upper().startswith("[") and \ + line.replace(" ", "").upper().endswith("DICT]"): + currDictName = line[line.find( + '[') + 1:line.upper().find('DICT]') + 4].upper() else: if currDictName == '': continue - if not ":===:" in line: + if ":===:" not in line: continue sepLine = line.split(':===:') if len(sepLine) == 1: @@ -121,5 +168,9 @@ class punctuationManager(): elif len(sepLine) > 2: sepLine[1] = ':===:' self.env['punctuation'][currDictName][sepLine[0]] = sepLine[1] - self.env['runtime']['debug'].writeDebugOut("Punctuation: " + currDictName + '.' + str(sepLine[0]) + ' :' + sepLine[1] ,debug.debugLevel.INFO, onAnyLevel=True) + self.env['runtime']['debug'].writeDebugOut( + "Punctuation: " + currDictName + '.' + str( + sepLine[0]) + ' :' + sepLine[1], + debug.debugLevel.INFO, + onAnyLevel=True) dictConfig.close() diff --git a/src/fenrirscreenreader/core/quickMenuManager.py b/src/fenrirscreenreader/core/quickMenuManager.py index da924d9c..d2656393 100644 --- a/src/fenrirscreenreader/core/quickMenuManager.py +++ b/src/fenrirscreenreader/core/quickMenuManager.py @@ -5,8 +5,10 @@ # By Chrys, Storm Dragon, and contributers. from fenrirscreenreader.core import debug +from fenrirscreenreader.core.i18n import _ from fenrirscreenreader.core.settingsData import settingsData + class quickMenuManager(): def __init__(self): self.position = 0 @@ -15,9 +17,13 @@ class quickMenuManager(): def initialize(self, environment): self.env = environment - self.loadMenu(self.env['runtime']['settingsManager'].getSetting('menu', 'quickMenu')) + self.loadMenu( + self.env['runtime']['settingsManager'].getSetting( + 'menu', 'quickMenu')) + def shutdown(self): pass + def loadMenu(self, menuString): self.position = 0 self.quickMenu = [] @@ -31,10 +37,13 @@ class quickMenuManager(): try: t = self.settings[entry[0]][entry[1]] except Exception as e: - self.env['runtime']['debug'].writeDebugOut('quickMenuManager loadMenu: Setting not found ' + str(entry) + ': ' + str(e), debug.debugLevel.ERROR) - print(entry[0],entry[1], 'not found') + self.env['runtime']['debug'].writeDebugOut( + 'quickMenuManager loadMenu: Setting not found ' + str(entry) + ': ' + str(e), + debug.debugLevel.ERROR) + print(entry[0], entry[1], 'not found') continue self.quickMenu.append({'section': entry[0], 'setting': entry[1]}) + def nextEntry(self): if len(self.quickMenu) == 0: return False @@ -42,6 +51,7 @@ class quickMenuManager(): if self.position >= len(self.quickMenu): self.position = 0 return True + def prevEntry(self): if len(self.quickMenu) == 0: return False @@ -49,6 +59,7 @@ class quickMenuManager(): if self.position < 0: self.position = len(self.quickMenu) - 1 return True + def nextValue(self): if len(self.quickMenu) == 0: return False @@ -56,9 +67,12 @@ class quickMenuManager(): setting = self.quickMenu[self.position]['setting'] valueString = '' try: - valueString = self.env['runtime']['settingsManager'].getSetting(section, setting) + valueString = self.env['runtime']['settingsManager'].getSetting( + section, setting) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('quickMenuManager nextValue: Error getting setting value: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'quickMenuManager nextValue: Error getting setting value: ' + str(e), + debug.debugLevel.ERROR) return False try: @@ -66,23 +80,27 @@ class quickMenuManager(): value = str(valueString) return False elif isinstance(self.settings[section][setting], bool): - if not valueString in ['True','False']: + if valueString not in ['True', 'False']: return False value = not value - self.env['runtime']['settingsManager'].setSetting(section, setting, str(value)) + self.env['runtime']['settingsManager'].setSetting( + section, setting, str(value)) elif isinstance(self.settings[section][setting], int): value = int(valueString) value += 1 - self.env['runtime']['settingsManager'].setSetting(section, setting, str(value)) + self.env['runtime']['settingsManager'].setSetting( + section, setting, str(value)) elif isinstance(self.settings[section][setting], float): value = float(valueString) value += 0.05 if value > 1.0: value = 1.0 - self.env['runtime']['settingsManager'].setSetting(section, setting, str(value)[:4]) + self.env['runtime']['settingsManager'].setSetting( + section, setting, str(value)[:4]) except Exception as e: return False return True + def prevValue(self): if len(self.quickMenu) == 0: return False @@ -90,47 +108,61 @@ class quickMenuManager(): setting = self.quickMenu[self.position]['setting'] valueString = '' try: - valueString = self.env['runtime']['settingsManager'].getSetting(section, setting) + valueString = self.env['runtime']['settingsManager'].getSetting( + section, setting) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('quickMenuManager prevValue: Error getting setting value: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'quickMenuManager prevValue: Error getting setting value: ' + str(e), + debug.debugLevel.ERROR) return False try: if isinstance(self.settings[section][setting], str): value = str(valueString) return False elif isinstance(self.settings[section][setting], bool): - if not valueString in ['True','False']: + if valueString not in ['True', 'False']: return False value = not value - self.env['runtime']['settingsManager'].setSetting(section, setting, str(value)) + self.env['runtime']['settingsManager'].setSetting( + section, setting, str(value)) elif isinstance(self.settings[section][setting], int): value = int(valueString) value -= 1 if value < 0: value = 0 - self.env['runtime']['settingsManager'].setSetting(section, setting, str(value)) + self.env['runtime']['settingsManager'].setSetting( + section, setting, str(value)) elif isinstance(self.settings[section][setting], float): value = float(valueString) value -= 0.05 if value < 0.0: value = 0.0 - self.env['runtime']['settingsManager'].setSetting(section, setting, str(value)[:4]) + self.env['runtime']['settingsManager'].setSetting( + section, setting, str(value)[:4]) except Exception as e: return False return True + def getCurrentEntry(self): if len(self.quickMenu) == 0: return '' try: - return _(self.quickMenu[self.position]['section']) + ' ' + _(self.quickMenu[self.position]['setting']) + return _(self.quickMenu[self.position]['section']) + \ + ' ' + _(self.quickMenu[self.position]['setting']) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('quickMenuManager getCurrentEntry: Error formatting entry: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'quickMenuManager getCurrentEntry: Error formatting entry: ' + str(e), + debug.debugLevel.ERROR) return _('setting invalid') + def getCurrentValue(self): if len(self.quickMenu) == 0: return '' try: - return self.env['runtime']['settingsManager'].getSetting(self.quickMenu[self.position]['section'], self.quickMenu[self.position]['setting']) + return self.env['runtime']['settingsManager'].getSetting( + self.quickMenu[self.position]['section'], self.quickMenu[self.position]['setting']) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('quickMenuManager getCurrentValue: Error getting setting value: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'quickMenuManager getCurrentValue: Error getting setting value: ' + str(e), + debug.debugLevel.ERROR) return _('setting value invalid') diff --git a/src/fenrirscreenreader/core/remoteDriver.py b/src/fenrirscreenreader/core/remoteDriver.py index 68a8e6e4..59769de3 100644 --- a/src/fenrirscreenreader/core/remoteDriver.py +++ b/src/fenrirscreenreader/core/remoteDriver.py @@ -6,11 +6,14 @@ from fenrirscreenreader.core import debug + class remoteDriver(): def __init__(self): self._isInitialized = False + def initialize(self, environment): self.env = environment self._isInitialized = True + def shutdown(self): self._isInitialized = False diff --git a/src/fenrirscreenreader/core/remoteManager.py b/src/fenrirscreenreader/core/remoteManager.py index af2850a2..34b79bcb 100644 --- a/src/fenrirscreenreader/core/remoteManager.py +++ b/src/fenrirscreenreader/core/remoteManager.py @@ -27,8 +27,11 @@ command interrupt from fenrirscreenreader.core import debug +from fenrirscreenreader.core.i18n import _ from fenrirscreenreader.core.eventData import fenrirEventType -import time, os +import time +import os + class remoteManager(): def __init__(self): @@ -50,16 +53,22 @@ class remoteManager(): self.saveAsSettingConst = 'SAVEAS ' self.saveSettingConst = 'SAVE' self.resetSettingConst = 'RESET' + def initialize(self, environment): self.env = environment - self.env['runtime']['settingsManager'].loadDriver(\ - self.env['runtime']['settingsManager'].getSetting('remote', 'driver'), 'remoteDriver') + self.env['runtime']['settingsManager'].loadDriver( + self.env['runtime']['settingsManager'].getSetting( + 'remote', 'driver'), 'remoteDriver') + def shutdown(self): self.env['runtime']['settingsManager'].shutdownDriver('remoteDriver') def handleSettingsChangeWithResponse(self, settingsText): - if not self.env['runtime']['settingsManager'].getSettingAsBool('remote', 'enableSettingsRemote'): - return {"success": False, "message": "Settings remote control is disabled"} + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'remote', 'enableSettingsRemote'): + return { + "success": False, + "message": "Settings remote control is disabled"} upperSettingsText = settingsText.upper() try: @@ -67,12 +76,16 @@ class remoteManager(): if upperSettingsText.startswith(self.setSettingConst): parameterText = settingsText[len(self.setSettingConst):] self.setSettings(parameterText) - return {"success": True, "message": f"Setting applied: {parameterText}"} + return { + "success": True, + "message": f"Setting applied: {parameterText}"} # save as setting elif upperSettingsText.startswith(self.saveAsSettingConst): parameterText = settingsText[len(self.saveAsSettingConst):] self.saveSettings(parameterText) - return {"success": True, "message": f"Settings saved to: {parameterText}"} + return { + "success": True, + "message": f"Settings saved to: {parameterText}"} # save setting elif upperSettingsText == self.saveSettingConst: self.saveSettings() @@ -80,14 +93,19 @@ class remoteManager(): # reset setting elif upperSettingsText == self.resetSettingConst: self.resetSettings() - return {"success": True, "message": "Settings reset to defaults"} + return { + "success": True, + "message": "Settings reset to defaults"} else: - return {"success": False, "message": f"Unknown settings command: {settingsText}"} + return { + "success": False, + "message": f"Unknown settings command: {settingsText}"} except Exception as e: return {"success": False, "message": f"Settings error: {str(e)}"} def handleSettingsChange(self, settingsText): - if not self.env['runtime']['settingsManager'].getSettingAsBool('remote', 'enableSettingsRemote'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'remote', 'enableSettingsRemote'): return upperSettingsText = settingsText.upper() @@ -107,8 +125,11 @@ class remoteManager(): self.resetSettings() def handleCommandExecutionWithResponse(self, commandText): - if not self.env['runtime']['settingsManager'].getSettingAsBool('remote', 'enableCommandRemote'): - return {"success": False, "message": "Command remote control is disabled"} + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'remote', 'enableCommandRemote'): + return { + "success": False, + "message": "Command remote control is disabled"} upperCommandText = commandText.upper() @@ -117,7 +138,8 @@ class remoteManager(): if upperCommandText.startswith(self.sayConst): parameterText = commandText[len(self.sayConst):] self.say(parameterText) - return {"success": True, "message": f"Speaking: {parameterText[:50]}{'...' if len(parameterText) > 50 else ''}"} + return {"success": True, + "message": f"Speaking: {parameterText[:50]}{'...' if len(parameterText) > 50 else ''}"} # interrupt elif upperCommandText == self.interruptConst: self.interruptSpeech() @@ -125,12 +147,16 @@ class remoteManager(): # temp disable speech elif upperCommandText == self.tempDisableSpeechConst: self.tempDisableSpeech() - return {"success": True, "message": "Speech temporarily disabled"} + return { + "success": True, + "message": "Speech temporarily disabled"} # set vmenu elif upperCommandText.startswith(self.vmenuConst): parameterText = commandText[len(self.vmenuConst):] self.setVMenu(parameterText) - return {"success": True, "message": f"VMenu set to: {parameterText}"} + return { + "success": True, + "message": f"VMenu set to: {parameterText}"} # reset vmenu elif upperCommandText == self.resetVmenuConst: self.resetVMenu() @@ -143,7 +169,9 @@ class remoteManager(): elif upperCommandText.startswith(self.defineWindowConst): parameterText = commandText[len(self.defineWindowConst):] self.defineWindow(parameterText) - return {"success": True, "message": f"Window defined: {parameterText}"} + return { + "success": True, + "message": f"Window defined: {parameterText}"} # reset window elif upperCommandText == self.resetWindowConst: self.resetWindow() @@ -152,17 +180,23 @@ class remoteManager(): elif upperCommandText.startswith(self.setClipboardConst): parameterText = commandText[len(self.setClipboardConst):] self.setClipboard(parameterText) - return {"success": True, "message": f"Clipboard set: {parameterText[:50]}{'...' if len(parameterText) > 50 else ''}"} + return {"success": True, + "message": f"Clipboard set: {parameterText[:50]}{'...' if len(parameterText) > 50 else ''}"} elif upperCommandText.startswith(self.exportClipboardConst): self.exportClipboard() - return {"success": True, "message": "Clipboard exported to file"} + return { + "success": True, + "message": "Clipboard exported to file"} else: - return {"success": False, "message": f"Unknown command: {commandText}"} + return { + "success": False, + "message": f"Unknown command: {commandText}"} except Exception as e: return {"success": False, "message": f"Command error: {str(e)}"} def handleCommandExecution(self, commandText): - if not self.env['runtime']['settingsManager'].getSettingAsBool('remote', 'enableCommandRemote'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'remote', 'enableCommandRemote'): return upperCommandText = commandText.upper() @@ -200,16 +234,23 @@ class remoteManager(): self.setClipboard(parameterText) elif upperCommandText.startswith(self.exportClipboardConst): self.exportClipboard() + def tempDisableSpeech(self): self.env['runtime']['outputManager'].tempDisableSpeech() - def setVMenu(self, vmenu = ''): + + def setVMenu(self, vmenu=''): self.env['runtime']['vmenuManager'].setCurrMenu(vmenu) + def resetVMenu(self): self.env['runtime']['vmenuManager'].setCurrMenu() - def setClipboard(self, text = ''): - self.env['runtime']['memoryManager'].addValueToFirstIndex('clipboardHistory', text) + + def setClipboard(self, text=''): + self.env['runtime']['memoryManager'].addValueToFirstIndex( + 'clipboardHistory', text) + def quitFenrir(self): self.env['runtime']['eventManager'].stopMainEventLoop() + def defineWindow(self, windowText): start = {} end = {} @@ -222,30 +263,42 @@ class remoteManager(): end['x'] = int(windowList[2]) end['y'] = int(windowList[3]) - self.env['runtime']['cursorManager'].setWindowForApplication(start, end) + self.env['runtime']['cursorManager'].setWindowForApplication( + start, end) except Exception as e: pass + def resetWindow(self): self.env['runtime']['cursorManager'].clearWindowForApplication() + def say(self, text): if not text: return if text == '': return self.env['runtime']['outputManager'].speakText(text) + def interruptSpeech(self): self.env['runtime']['outputManager'].interruptOutput() + def exportClipboard(self): - clipboardFilePath = self.env['runtime']['settingsManager'].getSetting('general', 'clipboardExportPath') - clipboardFilePath = clipboardFilePath.replace('$user',self.env['general']['currUser']) - clipboardFilePath = clipboardFilePath.replace('$USER',self.env['general']['currUser']) - clipboardFilePath = clipboardFilePath.replace('$User',self.env['general']['currUser']) - clipboardFile = open(clipboardFilePath,'w') + clipboardFilePath = self.env['runtime']['settingsManager'].getSetting( + 'general', 'clipboardExportPath') + clipboardFilePath = clipboardFilePath.replace( + '$user', self.env['general']['currUser']) + clipboardFilePath = clipboardFilePath.replace( + '$USER', self.env['general']['currUser']) + clipboardFilePath = clipboardFilePath.replace( + '$User', self.env['general']['currUser']) + clipboardFile = open(clipboardFilePath, 'w') try: - if self.env['runtime']['memoryManager'].isIndexListEmpty('clipboardHistory'): - self.env['runtime']['outputManager'].presentText(_('clipboard empty'), interrupt=True) - return - clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory') + if self.env['runtime']['memoryManager'].isIndexListEmpty( + 'clipboardHistory'): + self.env['runtime']['outputManager'].presentText( + _('clipboard empty'), interrupt=True) + return + clipboard = self.env['runtime']['memoryManager'].getIndexListElement( + 'clipboardHistory') # Fenrir will crash if the clipboard variable is type None if clipboard is not None: clipboardFile.write(clipboard) @@ -253,28 +306,41 @@ class remoteManager(): clipboardFile.write('') clipboardFile.close() os.chmod(clipboardFilePath, 0o644) - self.env['runtime']['outputManager'].presentText(_('clipboard exported to file'), interrupt=True) + self.env['runtime']['outputManager'].presentText( + _('clipboard exported to file'), interrupt=True) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('export_clipboard_to_file:run: Filepath:'+ clipboardFile +' trace:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'export_clipboard_to_file:run: Filepath:' + + clipboardFile + + ' trace:' + + str(e), + debug.debugLevel.ERROR) - def saveSettings(self, settingConfigPath = None): + def saveSettings(self, settingConfigPath=None): if not settingConfigPath: - settingConfigPath = self.env['runtime']['settingsManager'].getSettingsFile() + settingConfigPath = self.env['runtime']['settingsManager'].getSettingsFile( + ) if settingConfigPath == '': return self.env['runtime']['settingsManager'].saveSettings(settingConfigPath) + def resetSettings(self): self.env['runtime']['settingsManager'].resetSettingArgDict() + def setSettings(self, settingsArgs): self.env['runtime']['settingsManager'].parseSettingArgs(settingsArgs) self.env['runtime']['screenManager'].updateScreenIgnored() - self.env['runtime']['inputManager'].handleDeviceGrab(force = True) + self.env['runtime']['inputManager'].handleDeviceGrab(force=True) + def handleRemoteIncommingWithResponse(self, eventData): if not eventData: return {"success": False, "message": "No data received"} - + upperEventData = eventData.upper() - self.env['runtime']['debug'].writeDebugOut('remoteManager:handleRemoteIncommingWithResponse: event: ' + str(eventData),debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'remoteManager:handleRemoteIncommingWithResponse: event: ' + + str(eventData), + debug.debugLevel.INFO) try: if upperEventData.startswith(self.settingConst): @@ -284,15 +350,20 @@ class remoteManager(): commandText = eventData[len(self.commandConst):] return self.handleCommandExecutionWithResponse(commandText) else: - return {"success": False, "message": "Unknown command format. Use 'COMMAND ...' or 'SETTING ...'"} + return { + "success": False, + "message": "Unknown command format. Use 'COMMAND ...' or 'SETTING ...'"} except Exception as e: return {"success": False, "message": f"Exception: {str(e)}"} - + def handleRemoteIncomming(self, eventData): if not eventData: return upperEventData = eventData.upper() - self.env['runtime']['debug'].writeDebugOut('remoteManager:handleRemoteIncomming: event: ' + str(eventData),debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'remoteManager:handleRemoteIncomming: event: ' + + str(eventData), + debug.debugLevel.INFO) if upperEventData.startswith(self.settingConst): settingsText = eventData[len(self.settingConst):] diff --git a/src/fenrirscreenreader/core/runtimeData.py b/src/fenrirscreenreader/core/runtimeData.py index c2677f1d..39c6c6a0 100644 --- a/src/fenrirscreenreader/core/runtimeData.py +++ b/src/fenrirscreenreader/core/runtimeData.py @@ -7,14 +7,14 @@ from fenrirscreenreader.core import debug runtimeData = { -'speechDriver': None, -'screenDriver': None, -'soundDriver': None, -'inputDriver': None, -'remoteDriver': None, -'inputManager': None, -'commandManager': None, -'screenManager': None, -'outputManager': None, -'debug':None, + 'speechDriver': None, + 'screenDriver': None, + 'soundDriver': None, + 'inputDriver': None, + 'remoteDriver': None, + 'inputManager': None, + 'commandManager': None, + 'screenManager': None, + 'outputManager': None, + 'debug': None, } diff --git a/src/fenrirscreenreader/core/sayAllManager.py b/src/fenrirscreenreader/core/sayAllManager.py index 73865c50..3c83a679 100644 --- a/src/fenrirscreenreader/core/sayAllManager.py +++ b/src/fenrirscreenreader/core/sayAllManager.py @@ -6,25 +6,35 @@ from fenrirscreenreader.core import debug + class sayAllManager(): def __init__(self): self.isActive = False self.isActiveLock = None + def initialize(self, environment): - self.env = environment + self.env = environment + def shutdown(self): pass + def setIsActive(self, isActive): pass + def start(self): pass + def isSayAllActive(self): pass + def sayAllWorker(self): pass + def stop(self): pass + def finish(self): pass + def gotoNextPage(self): pass diff --git a/src/fenrirscreenreader/core/screenData.py b/src/fenrirscreenreader/core/screenData.py index d090f26b..0efd22df 100644 --- a/src/fenrirscreenreader/core/screenData.py +++ b/src/fenrirscreenreader/core/screenData.py @@ -8,30 +8,30 @@ from fenrirscreenreader.core import debug import time screenData = { -'columns': 0, -'lines': 0, -'oldDelta': '', -'oldAttribDelta': '', -'oldNegativeDelta': '', -'oldCursorReview':None, -'oldCursorAttrib':None, -'oldCursor':{'x':0,'y':0}, -'oldContentBytes': b'', -'oldContentText': '', -'oldContentAttrib': None, -'oldApplication': '', -'oldTTY':None, -'newDelta': '', -'newNegativeDelta': '', -'newAttribDelta': '', -'newCursorReview':None, -'newCursorAttrib':None, -'newCursor':{'x':0,'y':0}, -'newContentBytes': b'', -'newContentText': '', -'newContentAttrib': None, -'newTTY':'0', -'newApplication': '', -'lastScreenUpdate': time.time(), -'autoIgnoreScreens':[], + 'columns': 0, + 'lines': 0, + 'oldDelta': '', + 'oldAttribDelta': '', + 'oldNegativeDelta': '', + 'oldCursorReview': None, + 'oldCursorAttrib': None, + 'oldCursor': {'x': 0, 'y': 0}, + 'oldContentBytes': b'', + 'oldContentText': '', + 'oldContentAttrib': None, + 'oldApplication': '', + 'oldTTY': None, + 'newDelta': '', + 'newNegativeDelta': '', + 'newAttribDelta': '', + 'newCursorReview': None, + 'newCursorAttrib': None, + 'newCursor': {'x': 0, 'y': 0}, + 'newContentBytes': b'', + 'newContentText': '', + 'newContentAttrib': None, + 'newTTY': '0', + 'newApplication': '', + 'lastScreenUpdate': time.time(), + 'autoIgnoreScreens': [], } diff --git a/src/fenrirscreenreader/core/screenDriver.py b/src/fenrirscreenreader/core/screenDriver.py index df03b90a..7fa741f5 100644 --- a/src/fenrirscreenreader/core/screenDriver.py +++ b/src/fenrirscreenreader/core/screenDriver.py @@ -5,22 +5,54 @@ # By Chrys, Storm Dragon, and contributers. from fenrirscreenreader.core import debug +from fenrirscreenreader.core.i18n import _ + class screenDriver(): def __init__(self): - self._isInitialized = False - self.bgColorNames = {0: _('black'), 1: _('blue'), 2: _('green'), 3: _('cyan'), 4: _('red'), 5: _('Magenta'), 6: _('brown/yellow'), 7: _('white')} - self.fgColorNames = {0: _('Black'), 1: _('Blue'), 2: _('Green'), 3: _('Cyan'), 4: _('Red'), 5: _('Magenta'), 6: _('brown/yellow'), 7: _('Light gray'), 8: _('Dark gray'), 9: _('Light blue'), 10: ('Light green'), 11: _('Light cyan'), 12: _('Light red'), 13: _('Light magenta'), 14: _('Light yellow'), 15: _('White')} + self._isInitialized = False + self.bgColorNames = { + 0: _('black'), + 1: _('blue'), + 2: _('green'), + 3: _('cyan'), + 4: _('red'), + 5: _('Magenta'), + 6: _('brown/yellow'), + 7: _('white')} + self.fgColorNames = { + 0: _('Black'), + 1: _('Blue'), + 2: _('Green'), + 3: _('Cyan'), + 4: _('Red'), + 5: _('Magenta'), + 6: _('brown/yellow'), + 7: _('Light gray'), + 8: _('Dark gray'), + 9: _('Light blue'), + 10: ('Light green'), + 11: _('Light cyan'), + 12: _('Light red'), + 13: _('Light magenta'), + 14: _('Light yellow'), + 15: _('White')} + def initialize(self, environment): self.env = environment self._isInitialized = True + def shutdown(self): self._isInitialized = False + def getCurrScreen(self): pass - def injectTextToScreen(self, text, screen = None): + + def injectTextToScreen(self, text, screen=None): pass + def getCurrApplication(self): pass + def getSessionInformation(self): pass diff --git a/src/fenrirscreenreader/core/screenManager.py b/src/fenrirscreenreader/core/screenManager.py index 92239325..0b035f60 100644 --- a/src/fenrirscreenreader/core/screenManager.py +++ b/src/fenrirscreenreader/core/screenManager.py @@ -6,7 +6,11 @@ from fenrirscreenreader.core import debug from fenrirscreenreader.utils import screen_utils -import time, os, re, difflib +import time +import os +import re +import difflib + class screenManager(): def __init__(self): @@ -18,42 +22,58 @@ class screenManager(): self.colums = None self.rows = None # Compile regex once for better performance - self._space_normalize_regex = re.compile(' +') + self._space_normalize_regex = re.compile(' +') + def getRows(self): return self.rows + def getColumns(self): return self.colums + def initialize(self, environment): self.env = environment - self.env['runtime']['settingsManager'].loadDriver(\ - self.env['runtime']['settingsManager'].getSetting('screen', 'driver'), 'screenDriver') + self.env['runtime']['settingsManager'].loadDriver( + self.env['runtime']['settingsManager'].getSetting( + 'screen', 'driver'), 'screenDriver') self.getCurrScreen() self.getCurrScreen() self.getSessionInformation() self.updateScreenIgnored() self.updateScreenIgnored() + def resetScreenText(self, screenText): self.prevScreenText = '' self.currScreenText = screenText + def setScreenText(self, screenText): self.prevScreenText = self.currScreenText self.currScreenText = screenText + def getScreenText(self): return self.currScreenText + def getCurrScreen(self): try: self.env['runtime']['screenDriver'].getCurrScreen() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('screenManager getCurrScreen: Error getting current screen: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'screenManager getCurrScreen: Error getting current screen: ' + str(e), + debug.debugLevel.ERROR) + def getSessionInformation(self): try: self.env['runtime']['screenDriver'].getSessionInformation() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('screenManager getSessionInformation: Error getting session info: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'screenManager getSessionInformation: Error getting session info: ' + str(e), + debug.debugLevel.ERROR) + def shutdown(self): self.env['runtime']['settingsManager'].shutdownDriver('screenDriver') + def isCurrScreenIgnoredChanged(self): return self.getCurrScreenIgnored() != self.getPrevScreenIgnored() + def handleScreenChange(self, eventData): self.getCurrScreen() self.getSessionInformation() @@ -66,9 +86,10 @@ class screenManager(): self.env['screen']['lastScreenUpdate'] = time.time() else: self.env['runtime']['outputManager'].interruptOutput() + def handleScreenUpdate(self, eventData): - self.env['screen']['oldApplication'] = self.env['screen']['newApplication'] - self.updateScreenIgnored() + self.env['screen']['oldApplication'] = self.env['screen']['newApplication'] + self.updateScreenIgnored() if self.isCurrScreenIgnoredChanged(): self.env['runtime']['inputManager'].setExecuteDeviceGrab() self.env['runtime']['inputManager'].handleDeviceGrab() @@ -77,13 +98,18 @@ class screenManager(): self.env['screen']['lastScreenUpdate'] = time.time() elif self.isCurrScreenIgnoredChanged(): self.env['runtime']['outputManager'].interruptOutput() + def getCurrScreenIgnored(self): return self.currScreenIgnored + def getPrevScreenIgnored(self): return self.prevScreenIgnored + def updateScreenIgnored(self): self.prevScreenIgnored = self.currScreenIgnored - self.currScreenIgnored = self.isIgnoredScreen(self.env['screen']['newTTY']) + self.currScreenIgnored = self.isIgnoredScreen( + self.env['screen']['newTTY']) + def update(self, eventData, trigger='onUpdate'): # set new "old" values self.env['screen']['oldContentBytes'] = self.env['screen']['newContentBytes'] @@ -94,12 +120,14 @@ class screenManager(): self.env['screen']['newContentBytes'] = eventData['bytes'] # get metadata like cursor or screensize - self.env['screen']['lines'] = int( eventData['lines']) - self.env['screen']['columns'] = int( eventData['columns']) - self.colums = int( eventData['columns']) - self.rows = int( eventData['lines']) - self.env['screen']['newCursor']['x'] = int( eventData['textCursor']['x']) - self.env['screen']['newCursor']['y'] = int( eventData['textCursor']['y']) + self.env['screen']['lines'] = int(eventData['lines']) + self.env['screen']['columns'] = int(eventData['columns']) + self.colums = int(eventData['columns']) + self.rows = int(eventData['lines']) + self.env['screen']['newCursor']['x'] = int( + eventData['textCursor']['x']) + self.env['screen']['newCursor']['y'] = int( + eventData['textCursor']['y']) self.env['screen']['newTTY'] = eventData['screen'] self.env['screen']['newContentText'] = eventData['text'] @@ -107,7 +135,8 @@ class screenManager(): if self.isScreenChange(): self.env['screen']['oldContentBytes'] = b'' self.resetScreenText(eventData['text']) - self.env['runtime']['attributeManager'].resetAttributes(eventData['attributes']) + self.env['runtime']['attributeManager'].resetAttributes( + eventData['attributes']) self.env['runtime']['attributeManager'].resetAttributeCursor() self.env['screen']['oldContentText'] = '' self.env['screen']['oldCursor']['x'] = 0 @@ -116,7 +145,8 @@ class screenManager(): self.env['screen']['oldNegativeDelta'] = '' else: self.setScreenText(eventData['text']) - self.env['runtime']['attributeManager'].setAttributes(eventData['attributes']) + self.env['runtime']['attributeManager'].setAttributes( + eventData['attributes']) # initialize current deltas self.env['screen']['newNegativeDelta'] = '' self.env['screen']['newDelta'] = '' @@ -125,148 +155,204 @@ class screenManager(): # Diff generation - critical for screen reader functionality # This code detects and categorizes screen content changes to provide appropriate # speech feedback (typing echo vs incoming text vs screen updates) - - # Track whether this appears to be typing (user input) vs other screen changes + + # Track whether this appears to be typing (user input) vs other screen + # changes typing = False diffList = [] - if (self.env['screen']['oldContentText'] != self.env['screen']['newContentText']): + if (self.env['screen']['oldContentText'] != + self.env['screen']['newContentText']): # Special case: Initial screen content (going from empty to populated) # This handles first screen load or TTY switch scenarios if self.env['screen']['newContentText'] != '' and self.env['screen']['oldContentText'] == '': # Pre-process screen text for comparison - collapse multiple spaces to single space - # This normalization prevents spurious diffs from spacing inconsistencies - oldScreenText = self._space_normalize_regex.sub(' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screen']['oldContentText'])) - newScreenText = self._space_normalize_regex.sub(' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screen']['newContentText'])) + # This normalization prevents spurious diffs from spacing + # inconsistencies + oldScreenText = self._space_normalize_regex.sub( + ' ', self.env['runtime']['screenManager'].getWindowAreaInText( + self.env['screen']['oldContentText'])) + newScreenText = self._space_normalize_regex.sub( + ' ', self.env['runtime']['screenManager'].getWindowAreaInText( + self.env['screen']['newContentText'])) if oldScreenText == '' and\ - newScreenText != '': + newScreenText != '': self.env['screen']['newDelta'] = newScreenText else: # Calculate byte positions for the current cursor's line in the flat text buffer # Formula: (line_number * columns) + line_number accounts for newlines # Each line contributes 'columns' chars + 1 newline char - cursorLineStart = self.env['screen']['newCursor']['y'] * self.env['screen']['columns'] + self.env['screen']['newCursor']['y'] - cursorLineEnd = cursorLineStart + self.env['screen']['columns'] - + cursorLineStart = self.env['screen']['newCursor']['y'] * \ + self.env['screen']['columns'] + self.env['screen']['newCursor']['y'] + cursorLineEnd = cursorLineStart + self.env['screen']['columns'] + # TYPING DETECTION ALGORITHM # Determines if this screen change is likely user typing vs other content changes # All conditions must be met for typing detection: if abs(self.env['screen']['oldCursor']['x'] - self.env['screen']['newCursor']['x']) >= 1 and \ - self.env['screen']['oldCursor']['y'] == self.env['screen']['newCursor']['y'] and \ - self.env['screen']['newContentText'][:cursorLineStart] == self.env['screen']['oldContentText'][:cursorLineStart] and \ - self.env['screen']['newContentText'][cursorLineEnd:] == self.env['screen']['oldContentText'][cursorLineEnd:]: + self.env['screen']['oldCursor']['y'] == self.env['screen']['newCursor']['y'] and \ + self.env['screen']['newContentText'][:cursorLineStart] == self.env['screen']['oldContentText'][:cursorLineStart] and \ + self.env['screen']['newContentText'][cursorLineEnd:] == self.env['screen']['oldContentText'][cursorLineEnd:]: # Condition 1: Cursor moved horizontally by at least 1 position (typical of typing) # Condition 2: Cursor stayed on same line (typing doesn't usually change lines) # Condition 3: Content BEFORE cursor line is unchanged (text above typing area) # Condition 4: Content AFTER cursor line is unchanged (text below typing area) - # Together: only the current line changed, cursor moved horizontally = likely typing - - # Optimize diff calculation for typing by focusing on a small window around cursor + # Together: only the current line changed, cursor moved + # horizontally = likely typing + + # Optimize diff calculation for typing by focusing on a + # small window around cursor cursorLineStartOffset = cursorLineStart cursorLineEndOffset = cursorLineEnd - + # Limit analysis window to avoid processing entire long lines # +3 provides safety buffer beyond cursor position to catch edge cases - if cursorLineEnd > cursorLineStart + self.env['screen']['newCursor']['x'] + 3: - cursorLineEndOffset = cursorLineStart + self.env['screen']['newCursor']['x'] + 3 - - # Extract just the relevant text sections for character-level diff - oldScreenText = self.env['screen']['oldContentText'][cursorLineStartOffset:cursorLineEndOffset] + if cursorLineEnd > cursorLineStart + \ + self.env['screen']['newCursor']['x'] + 3: + cursorLineEndOffset = cursorLineStart + \ + self.env['screen']['newCursor']['x'] + 3 + + # Extract just the relevant text sections for + # character-level diff + oldScreenText = self.env['screen']['oldContentText'][cursorLineStartOffset:cursorLineEndOffset] newScreenText = self.env['screen']['newContentText'][cursorLineStartOffset:cursorLineEndOffset] - - # Character-level diff for typing detection (not line-level) - diff = self.differ.compare(oldScreenText, newScreenText) + + # Character-level diff for typing detection (not + # line-level) + diff = self.differ.compare(oldScreenText, newScreenText) diffList = list(diff) typing = True - - # Validate typing assumption by checking if detected changes match cursor movement - tempNewDelta = ''.join(x[2:] for x in diffList if x[0] == '+') + + # Validate typing assumption by checking if detected + # changes match cursor movement + tempNewDelta = ''.join(x[2:] + for x in diffList if x[0] == '+') if tempNewDelta.strip() != '': # Compare diff result against expected typing pattern - # Expected: characters between old and new cursor positions - expectedTyping = ''.join(newScreenText[self.env['screen']['oldCursor']['x']:self.env['screen']['newCursor']['x']].rstrip()) - - # If diff doesn't match expected typing pattern, treat as general screen change + # Expected: characters between old and new cursor + # positions + expectedTyping = ''.join( + newScreenText[self.env['screen']['oldCursor']['x']:self.env['screen']['newCursor']['x']].rstrip()) + + # If diff doesn't match expected typing pattern, treat + # as general screen change if tempNewDelta != expectedTyping: - # Fallback: treat entire current line as new content - diffList = ['+ ' + self.env['screen']['newContentText'].split('\n')[self.env['screen']['newCursor']['y']] +'\n'] + # Fallback: treat entire current line as new + # content + diffList = [ + '+ ' + + self.env['screen']['newContentText'].split('\n')[ + self.env['screen']['newCursor']['y']] + + '\n'] typing = False else: # GENERAL SCREEN CHANGE DETECTION # Not typing - handle as line-by-line content change - # This catches: incoming messages, screen updates, application output, etc. - + # This catches: incoming messages, screen updates, + # application output, etc. + # Pre-process screen text for comparison - collapse multiple spaces to single space - # This normalization prevents spurious diffs from spacing inconsistencies - oldScreenText = self._space_normalize_regex.sub(' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screen']['oldContentText'])) - newScreenText = self._space_normalize_regex.sub(' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screen']['newContentText'])) - - diff = self.differ.compare(oldScreenText.split('\n'),\ - newScreenText.split('\n')) + # This normalization prevents spurious diffs from spacing + # inconsistencies + oldScreenText = self._space_normalize_regex.sub( + ' ', self.env['runtime']['screenManager'].getWindowAreaInText( + self.env['screen']['oldContentText'])) + newScreenText = self._space_normalize_regex.sub( + ' ', self.env['runtime']['screenManager'].getWindowAreaInText( + self.env['screen']['newContentText'])) + + diff = self.differ.compare(oldScreenText.split('\n'), + newScreenText.split('\n')) diffList = list(diff) # Extract added and removed content from diff results - # Output format depends on whether this was detected as typing or general change + # Output format depends on whether this was detected as typing + # or general change if not typing: - # Line-based changes: join with newlines for proper speech cadence - self.env['screen']['newDelta'] = '\n'.join(x[2:] for x in diffList if x[0] == '+') + # Line-based changes: join with newlines for proper speech + # cadence + self.env['screen']['newDelta'] = '\n'.join( + x[2:] for x in diffList if x[0] == '+') else: - # Character-based changes: no newlines for smooth typing echo - self.env['screen']['newDelta'] = ''.join(x[2:] for x in diffList if x[0] == '+') - - # Negative delta (removed content) - used for backspace/delete detection - self.env['screen']['newNegativeDelta'] = ''.join(x[2:] for x in diffList if x[0] == '-') + # Character-based changes: no newlines for smooth typing + # echo + self.env['screen']['newDelta'] = ''.join( + x[2:] for x in diffList if x[0] == '+') + + # Negative delta (removed content) - used for backspace/delete + # detection + self.env['screen']['newNegativeDelta'] = ''.join( + x[2:] for x in diffList if x[0] == '-') # track highlighted try: if self.env['runtime']['attributeManager'].isAttributeChange(): - if self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'highlight'): - attributeDelta, attributeCursor = self.env['runtime']['attributeManager'].trackHighlights() + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'focus', 'highlight'): + attributeDelta, attributeCursor = self.env['runtime']['attributeManager'].trackHighlights( + ) if attributeCursor: - self.env['runtime']['attributeManager'].setAttributeCursor(attributeCursor) - self.env['runtime']['attributeManager'].setAttributeDelta(attributeDelta) + self.env['runtime']['attributeManager'].setAttributeCursor( + attributeCursor) + self.env['runtime']['attributeManager'].setAttributeDelta( + attributeDelta) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('screenManager:update:highlight: ' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'screenManager:update:highlight: ' + str(e), debug.debugLevel.ERROR) - def isIgnoredScreen(self, screen = None): - if screen == None: + def isIgnoredScreen(self, screen=None): + if screen is None: screen = self.env['screen']['newTTY'] # Check if force all screens flag is set if self.env['runtime'].get('force_all_screens', False): return False ignoreScreens = [] - fixIgnoreScreens = self.env['runtime']['settingsManager'].getSetting('screen', 'ignoreScreen') + fixIgnoreScreens = self.env['runtime']['settingsManager'].getSetting( + 'screen', 'ignoreScreen') if fixIgnoreScreens != '': ignoreScreens.extend(fixIgnoreScreens.split(',')) - if self.env['runtime']['settingsManager'].getSettingAsBool('screen', 'autodetectIgnoreScreen'): + if self.env['runtime']['settingsManager'].getSettingAsBool( + 'screen', 'autodetectIgnoreScreen'): ignoreScreens.extend(self.env['screen']['autoIgnoreScreens']) - self.env['runtime']['debug'].writeDebugOut('screenManager:isIgnoredScreen ignore:' + str(ignoreScreens) + ' current:'+ str(screen ), debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'screenManager:isIgnoredScreen ignore:' + + str(ignoreScreens) + + ' current:' + + str(screen), + debug.debugLevel.INFO) return (screen in ignoreScreens) - + def isScreenChange(self): if not self.env['screen']['oldTTY']: return False return self.env['screen']['newTTY'] != self.env['screen']['oldTTY'] + def isDelta(self, ignoreSpace=False): newDelta = self.env['screen']['newDelta'] if ignoreSpace: newDelta = newDelta.strip() return newDelta != '' + def isNegativeDelta(self): return self.env['screen']['newNegativeDelta'] != '' + def getWindowAreaInText(self, text): if not self.env['runtime']['cursorManager'].isApplicationWindowSet(): return text windowText = '' windowList = text.split('\n') currApp = self.env['runtime']['applicationManager'].getCurrentApplication() - windowList = windowList[self.env['commandBuffer']['windowArea'][currApp]['1']['y']:self.env['commandBuffer']['windowArea'][currApp]['2']['y'] + 1] + windowList = windowList[self.env['commandBuffer']['windowArea'][currApp][ + '1']['y']:self.env['commandBuffer']['windowArea'][currApp]['2']['y'] + 1] for line in windowList: - windowText += line[self.env['commandBuffer']['windowArea'][currApp]['1']['x']:self.env['commandBuffer']['windowArea'][currApp]['2']['x'] + 1] + '\n' + windowText += line[self.env['commandBuffer']['windowArea'][currApp]['1']['x'] + :self.env['commandBuffer']['windowArea'][currApp]['2']['x'] + 1] + '\n' return windowText - def injectTextToScreen(self, text, screen = None): + def injectTextToScreen(self, text, screen=None): try: - self.env['runtime']['screenDriver'].injectTextToScreen(text, screen) + self.env['runtime']['screenDriver'].injectTextToScreen( + text, screen) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('screenManager:injectTextToScreen ' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'screenManager:injectTextToScreen ' + str(e), debug.debugLevel.ERROR) diff --git a/src/fenrirscreenreader/core/settingsData.py b/src/fenrirscreenreader/core/settingsData.py index d5c681e8..9c68ee7d 100644 --- a/src/fenrirscreenreader/core/settingsData.py +++ b/src/fenrirscreenreader/core/settingsData.py @@ -7,118 +7,118 @@ from fenrirscreenreader.core import debug settingsData = { -'sound': { - 'enabled': True, - 'driver': 'genericDriver', - 'theme': 'default', - 'volume': 1.0, - 'genericPlayFileCommand': 'play -q -v fenrirVolume fenrirSoundFile', - 'genericFrequencyCommand': 'play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence' -}, -'speech':{ - 'enabled': True, - 'driver': 'genericDriver', - 'serverPath': '', - 'rate': 0.75, - 'pitch': 0.5, - 'capitalPitch':0.8, - 'volume': 1.0, - 'module': '', - 'voice': 'en-us', - 'language': '', - 'autoReadIncoming': True, - 'readNumbersAsDigits': False, - 'genericSpeechCommand':'espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice "fenrirText"', - 'fenrirMinVolume':0, - 'fenrirMaxVolume':200, - 'fenrirMinPitch':0, - 'fenrirMaxPitch':99, - 'fenrirMinRate':80, - 'fenrirMaxRate':450, -}, -'screen':{ - 'driver': 'vcsaDriver', - 'encoding': 'auto', - 'screenUpdateDelay': 0.1, - 'ignoreScreen': '', - 'autodetectIgnoreScreen': False, -}, -'general':{ - 'debugLevel': debug.debugLevel.DEACTIVE, - 'debugMode': 'FILE', - 'debugFile': '', - 'punctuationProfile':'default', - 'punctuationLevel': 'some', - 'respectPunctuationPause':True, - 'newLinePause':True, - 'numberOfClipboards': 10, - 'emoticons': True, - 'fenrirKeys': 'KEY_KP0,KEY_META', - 'scriptKeys': 'KEY_COMPOSE', - 'timeFormat': '%I:%M%P', - 'dateFormat': '%A, %B %d, %Y', - 'autoSpellCheck': False, - 'spellCheckLanguage': 'en_US', - 'scriptPath': '/usr/share/fenrirscreenreader/scripts', - 'commandPath': '/usr/share/fenrirscreenreader/commands', - 'attributeFormatString': 'Background fenrirBGColor,Foreground fenrirFGColor,fenrirUnderline,fenrirBold,fenrirBlink, Font fenrirFont,Fontsize fenrirFontSize', - 'autoPresentIndent': False, - 'autoPresentIndentMode': 1, - 'hasAttributes': True, - 'shell': '', -}, -'focus':{ - 'cursor': True, - 'highlight': False, -}, -'remote':{ - 'enabled': True, - 'driver': 'unixDriver', - 'port': 22447, - 'socketFile':'', - 'enableSettingsRemote': True, - 'enableCommandRemote': True, -}, -'barrier':{ - 'enabled': True, - 'leftBarriers': '│└┌─', - 'rightBarriers': '│┘┐─', -}, -'review':{ - 'lineBreak': True, - 'endOfScreen': True, - 'leaveReviewOnCursorChange': True, - 'leaveReviewOnScreenChange': True, -}, -'menu':{ - 'vmenuPath': '', - 'quickMenu': 'speech#rate;speech#pitch;speech#volume', -}, -'promote':{ - 'enabled': True, - 'inactiveTimeoutSec': 120, - 'list': '', -}, -'time':{ - 'enabled': False, - 'presentTime': True, - 'presentDate': True, - 'delaySec': 0, - 'onMinutes': '00,30', - 'announce': True, - 'interrupt': False, -}, -'keyboard':{ - 'driver': 'evdev', - 'device': 'all', - 'grabDevices': True, - 'ignoreShortcuts': False, - 'keyboardLayout': "desktop", - 'charEchoMode': 2, # while capslock - 'charDeleteEcho': True, - 'wordEcho': True, - 'interruptOnKeyPress': True, - 'interruptOnKeyPressFilter': '', - 'doubleTapTimeout': 0.2, -} + 'sound': { + 'enabled': True, + 'driver': 'genericDriver', + 'theme': 'default', + 'volume': 1.0, + 'genericPlayFileCommand': 'play -q -v fenrirVolume fenrirSoundFile', + 'genericFrequencyCommand': 'play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence' + }, + 'speech': { + 'enabled': True, + 'driver': 'genericDriver', + 'serverPath': '', + 'rate': 0.75, + 'pitch': 0.5, + 'capitalPitch': 0.8, + 'volume': 1.0, + 'module': '', + 'voice': 'en-us', + 'language': '', + 'autoReadIncoming': True, + 'readNumbersAsDigits': False, + 'genericSpeechCommand': 'espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice "fenrirText"', + 'fenrirMinVolume': 0, + 'fenrirMaxVolume': 200, + 'fenrirMinPitch': 0, + 'fenrirMaxPitch': 99, + 'fenrirMinRate': 80, + 'fenrirMaxRate': 450, + }, + 'screen': { + 'driver': 'vcsaDriver', + 'encoding': 'auto', + 'screenUpdateDelay': 0.1, + 'ignoreScreen': '', + 'autodetectIgnoreScreen': False, + }, + 'general': { + 'debugLevel': debug.debugLevel.DEACTIVE, + 'debugMode': 'FILE', + 'debugFile': '', + 'punctuationProfile': 'default', + 'punctuationLevel': 'some', + 'respectPunctuationPause': True, + 'newLinePause': True, + 'numberOfClipboards': 10, + 'emoticons': True, + 'fenrirKeys': 'KEY_KP0,KEY_META', + 'scriptKeys': 'KEY_COMPOSE', + 'timeFormat': '%I:%M%P', + 'dateFormat': '%A, %B %d, %Y', + 'autoSpellCheck': False, + 'spellCheckLanguage': 'en_US', + 'scriptPath': '/usr/share/fenrirscreenreader/scripts', + 'commandPath': '/usr/share/fenrirscreenreader/commands', + 'attributeFormatString': 'Background fenrirBGColor,Foreground fenrirFGColor,fenrirUnderline,fenrirBold,fenrirBlink, Font fenrirFont,Fontsize fenrirFontSize', + 'autoPresentIndent': False, + 'autoPresentIndentMode': 1, + 'hasAttributes': True, + 'shell': '', + }, + 'focus': { + 'cursor': True, + 'highlight': False, + }, + 'remote': { + 'enabled': True, + 'driver': 'unixDriver', + 'port': 22447, + 'socketFile': '', + 'enableSettingsRemote': True, + 'enableCommandRemote': True, + }, + 'barrier': { + 'enabled': True, + 'leftBarriers': '│└┌─', + 'rightBarriers': '│┘┐─', + }, + 'review': { + 'lineBreak': True, + 'endOfScreen': True, + 'leaveReviewOnCursorChange': True, + 'leaveReviewOnScreenChange': True, + }, + 'menu': { + 'vmenuPath': '', + 'quickMenu': 'speech#rate;speech#pitch;speech#volume', + }, + 'promote': { + 'enabled': True, + 'inactiveTimeoutSec': 120, + 'list': '', + }, + 'time': { + 'enabled': False, + 'presentTime': True, + 'presentDate': True, + 'delaySec': 0, + 'onMinutes': '00,30', + 'announce': True, + 'interrupt': False, + }, + 'keyboard': { + 'driver': 'evdev', + 'device': 'all', + 'grabDevices': True, + 'ignoreShortcuts': False, + 'keyboardLayout': "desktop", + 'charEchoMode': 2, # while capslock + 'charDeleteEcho': True, + 'wordEcho': True, + 'interruptOnKeyPress': True, + 'interruptOnKeyPressFilter': '', + 'doubleTapTimeout': 0.2, + } } diff --git a/src/fenrirscreenreader/core/settingsManager.py b/src/fenrirscreenreader/core/settingsManager.py index 9ae333d0..2fc5c2a9 100644 --- a/src/fenrirscreenreader/core/settingsManager.py +++ b/src/fenrirscreenreader/core/settingsManager.py @@ -4,37 +4,42 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. -import os, inspect +from fenrirscreenreader.core import environment +from fenrirscreenreader.utils import module_utils +from fenrirscreenreader.core import debug +from fenrirscreenreader.core.settingsData import settingsData +from fenrirscreenreader.core import quickMenuManager +from fenrirscreenreader.core import sayAllManager +from fenrirscreenreader.core import remoteManager +from fenrirscreenreader.core import barrierManager +from fenrirscreenreader.core import attributeManager +from fenrirscreenreader.core import byteManager +from fenrirscreenreader.core import tableManager +from fenrirscreenreader.core import textManager +from fenrirscreenreader.core import vmenuManager +from fenrirscreenreader.core import helpManager +from fenrirscreenreader.core import applicationManager +from fenrirscreenreader.core import cursorManager +from fenrirscreenreader.core import punctuationManager +from fenrirscreenreader.core import screenManager +from fenrirscreenreader.core import commandManager +from fenrirscreenreader.core import outputManager +from fenrirscreenreader.core import inputManager +from fenrirscreenreader.core import eventManager +from fenrirscreenreader.core import processManager +from fenrirscreenreader.core import memoryManager +from fenrirscreenreader.core import debugManager +from configparser import ConfigParser +import os +import inspect -currentdir = os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe())))) +currentdir = os.path.dirname( + os.path.realpath( + os.path.abspath( + inspect.getfile( + inspect.currentframe())))) fenrirPath = os.path.dirname(currentdir) -from configparser import ConfigParser -from fenrirscreenreader.core import debugManager -from fenrirscreenreader.core import memoryManager -from fenrirscreenreader.core import processManager -from fenrirscreenreader.core import eventManager -from fenrirscreenreader.core import inputManager -from fenrirscreenreader.core import outputManager -from fenrirscreenreader.core import commandManager -from fenrirscreenreader.core import screenManager -from fenrirscreenreader.core import punctuationManager -from fenrirscreenreader.core import cursorManager -from fenrirscreenreader.core import applicationManager -from fenrirscreenreader.core import helpManager -from fenrirscreenreader.core import vmenuManager -from fenrirscreenreader.core import textManager -from fenrirscreenreader.core import tableManager -from fenrirscreenreader.core import byteManager -from fenrirscreenreader.core import attributeManager -from fenrirscreenreader.core import barrierManager -from fenrirscreenreader.core import remoteManager -from fenrirscreenreader.core import sayAllManager -from fenrirscreenreader.core import quickMenuManager -from fenrirscreenreader.core import environment -from fenrirscreenreader.core.settingsData import settingsData -from fenrirscreenreader.core import debug -from fenrirscreenreader.utils import module_utils class settingsManager(): def __init__(self): @@ -42,30 +47,34 @@ class settingsManager(): self.settingArgDict = {} self.bindingsBackup = None self.settingsFile = '' + def initialize(self, environment): self.env = environment + def shutdown(self): pass + def getBindingBackup(self): return self.bindingsBackup.copy() + def loadSoundIcons(self, soundIconPath): try: with open(soundIconPath + '/soundicons.conf', "r") as siConfig: - while(True): + while (True): line = siConfig.readline() if not line: break - line = line.replace('\n','') - if line.replace(" ","") == '': + line = line.replace('\n', '') + if line.replace(" ", "") == '': continue - if line.replace(" ","").startswith("#"): + if line.replace(" ", "").startswith("#"): continue if line.count("=") != 1: continue Values = line.split('=') soundIcon = Values[0].upper() - Values[1] = Values[1].replace("'","") - Values[1] = Values[1].replace('"',"") + Values[1] = Values[1].replace("'", "") + Values[1] = Values[1].replace('"', "") soundIconFile = '' if os.path.exists(Values[1]): soundIconFile = Values[1] @@ -75,17 +84,28 @@ class settingsManager(): if os.path.exists(soundIconPath + Values[1]): soundIconFile = soundIconPath + Values[1] self.env['soundIcons'][soundIcon] = soundIconFile - self.env['runtime']['debug'].writeDebugOut("SoundIcon: " + soundIcon + '.' + soundIconFile, debug.debugLevel.INFO, onAnyLevel=True) + self.env['runtime']['debug'].writeDebugOut( + "SoundIcon: " + soundIcon + '.' + soundIconFile, + debug.debugLevel.INFO, + onAnyLevel=True) except (IOError, OSError) as e: - self.env['runtime']['debug'].writeDebugOut('loadSoundIcons: failed to load sound icons from ' + soundIconPath + '. Error: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'loadSoundIcons: failed to load sound icons from ' + + soundIconPath + + '. Error: ' + + str(e), + debug.debugLevel.ERROR) + def getSettingsFile(self): return self.settingsFile + def setSettingsFile(self, settingsFile): if not os.path.exists(settingsFile): return if not os.access(settingsFile, os.R_OK): - return + return self.settingsFile = settingsFile + def loadSettings(self, settingConfigPath): if not os.path.exists(settingConfigPath): return False @@ -95,30 +115,39 @@ class settingsManager(): try: self.env['settings'].read(settingConfigPath) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('settingsManager loadSettings: Error reading config file: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'settingsManager loadSettings: Error reading config file: ' + str(e), + debug.debugLevel.ERROR) return False self.setSettingsFile(settingConfigPath) return True + def saveSettings(self, settingConfigPath): # set opt dict here # save file try: - #print('file: ',settingConfigPath) + # print('file: ',settingConfigPath) for section, settings in self.settingArgDict.items(): for setting, value in settings.items(): - #print(section, setting, value) + # print(section, setting, value) self.env['settings'].set(section, setting, value) - #print('full',self.env['settings']) + # print('full',self.env['settings']) configFile = open(settingConfigPath, 'w') self.env['settings'].write(configFile) configFile.close() os.chmod(settingConfigPath, 0o644) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('saveSettings: save settingsfile:' + settingConfigPath + 'failed. Error:' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'saveSettings: save settingsfile:' + + settingConfigPath + + 'failed. Error:' + + str(e), + debug.debugLevel.ERROR) + def setSetting(self, section, setting, value): self.setOptionArgDict(section, setting, value) - #self.env['settings'].set(section, setting, value) + # self.env['settings'].set(section, setting, value) def getSetting(self, section, setting): value = '' @@ -162,7 +191,8 @@ class settingsManager(): def getSettingAsBool(self, section, setting): value = False try: - value = self.settingArgDict[section][setting].upper() in ['1','YES','JA','TRUE'] + value = self.settingArgDict[section][setting].upper() in [ + '1', 'YES', 'JA', 'TRUE'] return value except Exception as e: pass @@ -177,22 +207,34 @@ class settingsManager(): if self.env['runtime'][driverType] is not None: self.env['runtime'][driverType].shutdown(self.env) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('settingsManager loadDriver: Error shutting down driver: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'settingsManager loadDriver: Error shutting down driver: ' + str(e), + debug.debugLevel.ERROR) try: - driver_mod = module_utils.importModule(driverName, - fenrirPath + "/" + driverType + '/' + driverName + '.py') + driver_mod = module_utils.importModule( + driverName, fenrirPath + "/" + driverType + '/' + driverName + '.py') self.env['runtime'][driverType] = driver_mod.driver() self.env['runtime'][driverType].initialize(self.env) - self.env['runtime']['debug'].writeDebugOut('Loading Driver ' + driverType + ' (' + driverName +") OK",debug.debugLevel.INFO, onAnyLevel=True) + self.env['runtime']['debug'].writeDebugOut( + 'Loading Driver ' + driverType + ' (' + driverName + ") OK", + debug.debugLevel.INFO, + onAnyLevel=True) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('Loading Driver ' + driverType + ' (' + driverName +") FAILED:"+ str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'Loading Driver ' + driverType + ' (' + driverName + ") FAILED:" + str(e), + debug.debugLevel.ERROR) try: - driver_mod = module_utils.importModule(driverName, - fenrirPath + "/" + driverType + '/dummyDriver.py') + driver_mod = module_utils.importModule( + driverName, fenrirPath + "/" + driverType + '/dummyDriver.py') self.env['runtime'][driverType] = driver_mod.driver() self.env['runtime'][driverType].initialize(self.env) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('(fallback) Loading Driver ' + driverType + ' (dummyDriver) FAILED:'+ str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + '(fallback) Loading Driver ' + + driverType + + ' (dummyDriver) FAILED:' + + str(e), + debug.debugLevel.ERROR) def shutdownDriver(self, driverType): try: @@ -205,20 +247,23 @@ class settingsManager(): keys = keys.upper() keyList = keys.split(',') for key in keyList: - if not key in self.env['input']['fenrirKey']: + if key not in self.env['input']['fenrirKey']: self.env['input']['fenrirKey'].append(key) + def setScriptKeys(self, keys): keys = keys.upper() keyList = keys.split(',') for key in keyList: - if not key in self.env['input']['scriptKey']: + if key not in self.env['input']['scriptKey']: self.env['input']['scriptKey'].append(key) + def resetSettingArgDict(self): self.settingArgDict = {} self.env['runtime']['outputManager'].resetSpeechDriver() + def setOptionArgDict(self, section, setting, value): - #section = section.lower() - #setting = setting.lower() + # section = section.lower() + # setting = setting.lower() try: e = self.settingArgDict[section] except KeyError: @@ -226,79 +271,102 @@ class settingsManager(): try: t = self.settings[section][setting] except Exception as e: - print(section,setting, 'not found') + print(section, setting, 'not found') return try: if isinstance(self.settings[section][setting], str): v = str(value) elif isinstance(self.settings[section][setting], bool): - if not value in ['True','False']: - raise ValueError('could not convert string to bool: '+ value) + if value not in ['True', 'False']: + raise ValueError( + 'could not convert string to bool: ' + value) v = value == 'True' elif isinstance(self.settings[section][setting], int): v = int(value) elif isinstance(self.settings[section][setting], float): v = float(value) - + # Content validation for critical settings self._validateSettingValue(section, setting, v) - + self.settingArgDict[section][setting] = str(value) except Exception as e: - print('settingsManager:setOptionArgDict:Datatype missmatch: '+ section + '#' + setting + '=' + value + ' Error:' + str(e)) - #self.env['runtime']['debug'].writeDebugOut('settingsManager:setOptionArgDict:Datatype missmatch: '+ section + '#' + setting + '=' + value + ' Error:' + str(e), debug.debugLevel.ERROR) + print('settingsManager:setOptionArgDict:Datatype missmatch: ' + + section + '#' + setting + '=' + value + ' Error:' + str(e)) + # self.env['runtime']['debug'].writeDebugOut('settingsManager:setOptionArgDict:Datatype + # missmatch: '+ section + '#' + setting + '=' + value + ' Error:' + # + str(e), debug.debugLevel.ERROR) return - + def _validateSettingValue(self, section, setting, value): """Validate setting values for critical screen reader functionality. Only validates settings that could cause crashes or accessibility issues. Invalid values raise ValueError which is caught by the calling method.""" - + # Speech settings validation - critical for accessibility if section == 'speech': if setting == 'rate': if not (0.0 <= value <= 3.0): - raise ValueError(f'Speech rate must be between 0.0 and 3.0, got {value}') + raise ValueError( + f'Speech rate must be between 0.0 and 3.0, got {value}') elif setting == 'pitch': if not (0.0 <= value <= 2.0): - raise ValueError(f'Speech pitch must be between 0.0 and 2.0, got {value}') + raise ValueError( + f'Speech pitch must be between 0.0 and 2.0, got {value}') elif setting == 'volume': if not (0.0 <= value <= 1.5): - raise ValueError(f'Speech volume must be between 0.0 and 1.5, got {value}') + raise ValueError( + f'Speech volume must be between 0.0 and 1.5, got {value}') elif setting == 'driver': - valid_drivers = ['speechdDriver', 'genericDriver', 'dummyDriver'] + valid_drivers = [ + 'speechdDriver', + 'genericDriver', + 'dummyDriver'] if value not in valid_drivers: - raise ValueError(f'Invalid speech driver: {value}. Valid options: {valid_drivers}') - + raise ValueError( + f'Invalid speech driver: {value}. Valid options: {valid_drivers}') + # Sound settings validation elif section == 'sound': if setting == 'volume': if not (0.0 <= value <= 1.5): - raise ValueError(f'Sound volume must be between 0.0 and 1.5, got {value}') + raise ValueError( + f'Sound volume must be between 0.0 and 1.5, got {value}') elif setting == 'driver': - valid_drivers = ['genericDriver', 'gstreamerDriver', 'dummyDriver'] + valid_drivers = [ + 'genericDriver', + 'gstreamerDriver', + 'dummyDriver'] if value not in valid_drivers: - raise ValueError(f'Invalid sound driver: {value}. Valid options: {valid_drivers}') - + raise ValueError( + f'Invalid sound driver: {value}. Valid options: {valid_drivers}') + # Screen settings validation elif section == 'screen': if setting == 'driver': - valid_drivers = ['vcsaDriver', 'ptyDriver', 'dummyDriver'] + valid_drivers = ['vcsaDriver', 'ptyDriver', 'dummyDriver'] if value not in valid_drivers: - raise ValueError(f'Invalid screen driver: {value}. Valid options: {valid_drivers}') - + raise ValueError( + f'Invalid screen driver: {value}. Valid options: {valid_drivers}') + # Input settings validation elif section == 'keyboard': if setting == 'driver': - valid_drivers = ['evdevDriver', 'ptyDriver', 'atspiDriver', 'dummyDriver'] + valid_drivers = [ + 'evdevDriver', + 'ptyDriver', + 'atspiDriver', + 'dummyDriver'] if value not in valid_drivers: - raise ValueError(f'Invalid input driver: {value}. Valid options: {valid_drivers}') - - # General settings validation + raise ValueError( + f'Invalid input driver: {value}. Valid options: {valid_drivers}') + + # General settings validation elif section == 'general': if setting == 'debugLevel': if not (0 <= value <= 3): - raise ValueError(f'Debug level must be between 0 and 3, got {value}') + raise ValueError( + f'Debug level must be between 0 and 3, got {value}') def parseSettingArgs(self, settingArgs): for optionElem in settingArgs.split(';'): @@ -307,7 +375,7 @@ class settingsManager(): section = '' option = '' value = '' - settingValList = optionElem.split('=',1) + settingValList = optionElem.split('=', 1) if len(settingValList) != 2: continue if '#' in settingValList[0]: @@ -328,14 +396,18 @@ class settingsManager(): value = str(settingValList[1]) self.setOptionArgDict(section, option, value) - def initFenrirConfig(self, cliArgs, fenrirManager = None, environment = environment.environment): + def initFenrirConfig( + self, + cliArgs, + fenrirManager=None, + environment=environment.environment): settingsRoot = '/etc/fenrirscreenreader/' settingsFile = cliArgs.setting soundRoot = '/usr/share/sounds/fenrirscreenreader/' # get fenrir settings root if not os.path.exists(settingsRoot): - if os.path.exists(fenrirPath +'/../../config/'): - settingsRoot = fenrirPath +'/../../config/' + if os.path.exists(fenrirPath + '/../../config/'): + settingsRoot = fenrirPath + '/../../config/' else: return None # get settings file @@ -349,10 +421,11 @@ class settingsManager(): if os.path.exists(fenrirPath + '/../../config/sound/'): soundRoot = fenrirPath + '/../../config/sound/' - environment['runtime']['settingsManager'] = self + environment['runtime']['settingsManager'] = self environment['runtime']['settingsManager'].initialize(environment) - validConfig = environment['runtime']['settingsManager'].loadSettings(settingsFile) + validConfig = environment['runtime']['settingsManager'].loadSettings( + settingsFile) if not validConfig: return None if cliArgs.options != '': @@ -366,59 +439,108 @@ class settingsManager(): self.setSetting('screen', 'driver', 'ptyDriver') self.setSetting('keyboard', 'driver', 'ptyDriver') # TODO needs cleanup use dict - #self.setOptionArgDict('keyboard', 'keyboardLayout', 'pty') + # self.setOptionArgDict('keyboard', 'keyboardLayout', 'pty') self.setSetting('keyboard', 'keyboardLayout', 'pty') if cliArgs.emulated_evdev: self.setSetting('screen', 'driver', 'ptyDriver') self.setSetting('keyboard', 'driver', 'evdevDriver') - self.setFenrirKeys(self.getSetting('general','fenrirKeys')) - self.setScriptKeys(self.getSetting('general','scriptKeys')) + self.setFenrirKeys(self.getSetting('general', 'fenrirKeys')) + self.setScriptKeys(self.getSetting('general', 'scriptKeys')) - environment['runtime']['debug'] = debugManager.debugManager(self.env['runtime']['settingsManager'].getSetting('general','debugFile')) + environment['runtime']['debug'] = debugManager.debugManager( + self.env['runtime']['settingsManager'].getSetting('general', 'debugFile')) environment['runtime']['debug'].initialize(environment) - + if cliArgs.force_all_screens: environment['runtime']['force_all_screens'] = True - + if cliArgs.ignore_screen: currentIgnoreScreen = self.getSetting('screen', 'ignoreScreen') if currentIgnoreScreen: - ignoreScreens = currentIgnoreScreen.split(',') + cliArgs.ignore_screen + ignoreScreens = currentIgnoreScreen.split( + ',') + cliArgs.ignore_screen else: ignoreScreens = cliArgs.ignore_screen self.setSetting('screen', 'ignoreScreen', ','.join(ignoreScreens)) - if not os.path.exists(self.getSetting('sound','theme') + '/soundicons.conf'): - if os.path.exists(soundRoot + self.getSetting('sound','theme')): - self.setSetting('sound', 'theme', soundRoot + self.getSetting('sound','theme')) - if os.path.exists(self.getSetting('sound','theme') + '/soundicons.conf'): - environment['runtime']['settingsManager'].loadSoundIcons(self.getSetting('sound','theme')) + if not os.path.exists( + self.getSetting( + 'sound', + 'theme') + + '/soundicons.conf'): + if os.path.exists(soundRoot + self.getSetting('sound', 'theme')): + self.setSetting( + 'sound', + 'theme', + soundRoot + + self.getSetting( + 'sound', + 'theme')) + if os.path.exists( + self.getSetting( + 'sound', + 'theme') + + '/soundicons.conf'): + environment['runtime']['settingsManager'].loadSoundIcons( + self.getSetting('sound', 'theme')) else: - environment['runtime']['settingsManager'].loadSoundIcons(self.getSetting('sound','theme')) + environment['runtime']['settingsManager'].loadSoundIcons( + self.getSetting('sound', 'theme')) environment['runtime']['punctuationManager'] = punctuationManager.punctuationManager() - environment['runtime']['punctuationManager'].initialize(environment) + environment['runtime']['punctuationManager'].initialize(environment) environment['runtime']['textManager'] = textManager.textManager() environment['runtime']['textManager'].initialize(environment) - if not os.path.exists(self.getSetting('general','punctuationProfile')): - if os.path.exists(settingsRoot + 'punctuation/' + self.getSetting('general','punctuationProfile')): - self.setSetting('general', 'punctuationProfile', settingsRoot + 'punctuation/' + self.getSetting('general','punctuationProfile')) - environment['runtime']['punctuationManager'].loadDicts(self.getSetting('general','punctuationProfile')) - if os.path.exists(settingsRoot + 'punctuation/' + self.getSetting('general','punctuationProfile') + '.conf'): - self.setSetting('general', 'punctuationProfile', settingsRoot + 'punctuation/' + self.getSetting('general','punctuationProfile') + '.conf') - environment['runtime']['punctuationManager'].loadDicts(self.getSetting('general','punctuationProfile')) + if not os.path.exists( + self.getSetting( + 'general', + 'punctuationProfile')): + if os.path.exists( + settingsRoot + + 'punctuation/' + + self.getSetting( + 'general', + 'punctuationProfile')): + self.setSetting( + 'general', + 'punctuationProfile', + settingsRoot + + 'punctuation/' + + self.getSetting( + 'general', + 'punctuationProfile')) + environment['runtime']['punctuationManager'].loadDicts( + self.getSetting('general', 'punctuationProfile')) + if os.path.exists( + settingsRoot + + 'punctuation/' + + self.getSetting( + 'general', + 'punctuationProfile') + + '.conf'): + self.setSetting( + 'general', + 'punctuationProfile', + settingsRoot + + 'punctuation/' + + self.getSetting( + 'general', + 'punctuationProfile') + + '.conf') + environment['runtime']['punctuationManager'].loadDicts( + self.getSetting('general', 'punctuationProfile')) else: - environment['runtime']['punctuationManager'].loadDicts(self.getSetting('general','punctuationProfile')) - + environment['runtime']['punctuationManager'].loadDicts( + self.getSetting('general', 'punctuationProfile')) if fenrirManager: environment['runtime']['fenrirManager'] = fenrirManager environment['runtime']['memoryManager'] = memoryManager.memoryManager() - environment['runtime']['memoryManager'].initialize(environment) + environment['runtime']['memoryManager'].initialize(environment) environment['runtime']['attributeManager'] = attributeManager.attributeManager() environment['runtime']['attributeManager'].initialize(environment) @@ -426,7 +548,7 @@ class settingsManager(): environment['runtime']['eventManager'] = eventManager.eventManager() environment['runtime']['eventManager'].initialize(environment) - environment['runtime']['processManager'] = processManager.processManager() + environment['runtime']['processManager'] = processManager.processManager() environment['runtime']['processManager'].initialize(environment) environment['runtime']['outputManager'] = outputManager.outputManager() @@ -450,27 +572,90 @@ class settingsManager(): environment['runtime']['remoteManager'] = remoteManager.remoteManager() environment['runtime']['remoteManager'].initialize(environment) - if environment['runtime']['inputManager'].getShortcutType() == 'KEY': - if not os.path.exists(self.getSetting('keyboard','keyboardLayout')): - if os.path.exists(settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout')): - self.setSetting('keyboard', 'keyboardLayout', settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout')) - environment['runtime']['inputManager'].loadShortcuts(self.getSetting('keyboard','keyboardLayout')) - if os.path.exists(settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout') + '.conf'): - self.setSetting('keyboard', 'keyboardLayout', settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout') + '.conf') - environment['runtime']['inputManager'].loadShortcuts(self.getSetting('keyboard','keyboardLayout')) + if not os.path.exists( + self.getSetting( + 'keyboard', + 'keyboardLayout')): + if os.path.exists( + settingsRoot + + 'keyboard/' + + self.getSetting( + 'keyboard', + 'keyboardLayout')): + self.setSetting( + 'keyboard', + 'keyboardLayout', + settingsRoot + + 'keyboard/' + + self.getSetting( + 'keyboard', + 'keyboardLayout')) + environment['runtime']['inputManager'].loadShortcuts( + self.getSetting('keyboard', 'keyboardLayout')) + if os.path.exists( + settingsRoot + + 'keyboard/' + + self.getSetting( + 'keyboard', + 'keyboardLayout') + + '.conf'): + self.setSetting( + 'keyboard', + 'keyboardLayout', + settingsRoot + + 'keyboard/' + + self.getSetting( + 'keyboard', + 'keyboardLayout') + + '.conf') + environment['runtime']['inputManager'].loadShortcuts( + self.getSetting('keyboard', 'keyboardLayout')) else: - environment['runtime']['inputManager'].loadShortcuts(self.getSetting('keyboard','keyboardLayout')) + environment['runtime']['inputManager'].loadShortcuts( + self.getSetting('keyboard', 'keyboardLayout')) elif environment['runtime']['inputManager'].getShortcutType() == 'BYTE': - if not os.path.exists(self.getSetting('keyboard','keyboardLayout')): - if os.path.exists(settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout')): - self.setSetting('keyboard', 'keyboardLayout', settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout')) - environment['runtime']['byteManager'].loadByteShortcuts(self.getSetting('keyboard','keyboardLayout')) - if os.path.exists(settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout') + '.conf'): - self.setSetting('keyboard', 'keyboardLayout', settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout') + '.conf') - environment['runtime']['byteManager'].loadByteShortcuts(self.getSetting('keyboard','keyboardLayout')) + if not os.path.exists( + self.getSetting( + 'keyboard', + 'keyboardLayout')): + if os.path.exists( + settingsRoot + + 'keyboard/' + + self.getSetting( + 'keyboard', + 'keyboardLayout')): + self.setSetting( + 'keyboard', + 'keyboardLayout', + settingsRoot + + 'keyboard/' + + self.getSetting( + 'keyboard', + 'keyboardLayout')) + environment['runtime']['byteManager'].loadByteShortcuts( + self.getSetting('keyboard', 'keyboardLayout')) + if os.path.exists( + settingsRoot + + 'keyboard/' + + self.getSetting( + 'keyboard', + 'keyboardLayout') + + '.conf'): + self.setSetting( + 'keyboard', + 'keyboardLayout', + settingsRoot + + 'keyboard/' + + self.getSetting( + 'keyboard', + 'keyboardLayout') + + '.conf') + environment['runtime']['byteManager'].loadByteShortcuts( + self.getSetting('keyboard', 'keyboardLayout')) else: - environment['runtime']['byteManager'].loadByteShortcuts(self.getSetting('keyboard','keyboardLayout')) + environment['runtime']['byteManager'].loadByteShortcuts( + self.getSetting('keyboard', 'keyboardLayout')) environment['runtime']['cursorManager'] = cursorManager.cursorManager() environment['runtime']['cursorManager'].initialize(environment) @@ -489,16 +674,25 @@ class settingsManager(): environment['runtime']['quickMenuManager'] = quickMenuManager.quickMenuManager() environment['runtime']['quickMenuManager'].initialize(environment) - # only possible after having input and screen managers with clean buffer + # only possible after having input and screen managers with clean + # buffer environment['runtime']['inputManager'].writeEventBuffer() - environment['runtime']['inputManager'].handleDeviceGrab(force = True) + environment['runtime']['inputManager'].handleDeviceGrab(force=True) - environment['runtime']['debug'].writeDebugOut(r'/-------environment-------/',debug.debugLevel.INFO, onAnyLevel=True) - environment['runtime']['debug'].writeDebugOut(str(environment), debug.debugLevel.INFO, onAnyLevel=True) - environment['runtime']['debug'].writeDebugOut(r'/-------settings.conf-------/', debug.debugLevel.INFO, onAnyLevel=True) - environment['runtime']['debug'].writeDebugOut(str(environment['settings']._sections) , debug.debugLevel.INFO, onAnyLevel=True) - environment['runtime']['debug'].writeDebugOut(r'/-------self.settingArgDict-------/',debug.debugLevel.INFO, onAnyLevel=True) - environment['runtime']['debug'].writeDebugOut(str( self.settingArgDict) ,debug.debugLevel.INFO, onAnyLevel=True) + environment['runtime']['debug'].writeDebugOut( + r'/-------environment-------/', debug.debugLevel.INFO, onAnyLevel=True) + environment['runtime']['debug'].writeDebugOut( + str(environment), debug.debugLevel.INFO, onAnyLevel=True) + environment['runtime']['debug'].writeDebugOut( + r'/-------settings.conf-------/', debug.debugLevel.INFO, onAnyLevel=True) + environment['runtime']['debug'].writeDebugOut( + str(environment['settings']._sections), debug.debugLevel.INFO, onAnyLevel=True) + environment['runtime']['debug'].writeDebugOut( + r'/-------self.settingArgDict-------/', + debug.debugLevel.INFO, + onAnyLevel=True) + environment['runtime']['debug'].writeDebugOut( + str(self.settingArgDict), debug.debugLevel.INFO, onAnyLevel=True) self.bindingsBackup = environment['bindings'].copy() return environment diff --git a/src/fenrirscreenreader/core/soundDriver.py b/src/fenrirscreenreader/core/soundDriver.py index cfeefd54..4bbf1a75 100644 --- a/src/fenrirscreenreader/core/soundDriver.py +++ b/src/fenrirscreenreader/core/soundDriver.py @@ -6,6 +6,7 @@ from fenrirscreenreader.core import debug + class soundDriver(): def __init__(self): self.volume = None @@ -21,13 +22,18 @@ class soundDriver(): self.cancel() self._isInitialized = False - def playFrequence(self, frequence, duration, adjustVolume = 0.0, interrupt=True): + def playFrequence( + self, + frequence, + duration, + adjustVolume=0.0, + interrupt=True): if not self._initialized: return if interrupt: self.cancel() - def playSoundFile(self, filePath, interrupt = True): + def playSoundFile(self, filePath, interrupt=True): if not self._initialized: return if interrupt: diff --git a/src/fenrirscreenreader/core/speechDriver.py b/src/fenrirscreenreader/core/speechDriver.py index 969dcbf6..be6ff5bd 100644 --- a/src/fenrirscreenreader/core/speechDriver.py +++ b/src/fenrirscreenreader/core/speechDriver.py @@ -6,9 +6,11 @@ from fenrirscreenreader.core import debug + class speechDriver(): def __init__(self): pass + def initialize(self, environment): self._isInitialized = False self.language = None @@ -19,15 +21,16 @@ class speechDriver(): self.volume = None self.env = environment self._isInitialized = True + def shutdown(self): if self._isInitialized: self.cancel() self._isInitialized = False - def speak(self,text, queueable=True, ignorePunctuation=False): + def speak(self, text, queueable=True, ignorePunctuation=False): if not self._isInitialized: return - if not queueable: + if not queueable: self.cancel() def cancel(self): @@ -49,7 +52,7 @@ class speechDriver(): return if voice == '': return - self.voice = voice + self.voice = voice def setPitch(self, pitch): if not self._isInitialized: @@ -61,6 +64,7 @@ class speechDriver(): if pitch > 1.0: return self.pitch = pitch + def setRate(self, rate): if not self._isInitialized: return @@ -71,6 +75,7 @@ class speechDriver(): if rate > 1.0: return self.rate = rate + def setModule(self, module): if not self._isInitialized: return @@ -79,9 +84,11 @@ class speechDriver(): if module == '': return self.module = module + def reset(self): self.shutdown() self.initialize(self.env) + def setLanguage(self, language): if not self._isInitialized: return @@ -89,11 +96,12 @@ class speechDriver(): return if language == '': return - self.language = language + self.language = language + def setVolume(self, volume): if not self._isInitialized: - return - if not isinstance(volume,float): + return + if not isinstance(volume, float): return if volume < 0.0: return diff --git a/src/fenrirscreenreader/core/tableManager.py b/src/fenrirscreenreader/core/tableManager.py index b27dac0f..f88e845c 100644 --- a/src/fenrirscreenreader/core/tableManager.py +++ b/src/fenrirscreenreader/core/tableManager.py @@ -7,40 +7,47 @@ from fenrirscreenreader.core import debug import re + class tableManager(): def __init__(self): self.headLine = '' - self.defaultSeparators = ['+',';','|',' '] + self.defaultSeparators = ['+', ';', '|', ' '] self.noOfHeadLineColumns = 0 self.headColumnSep = '' self.rowColumnSep = '' + def initialize(self, environment): - self.env = environment + self.env = environment + def shutdown(self): pass + def resetTableMode(self): self.setHeadLine() - def setHeadColumnSep(self, columnSep = ''): - self.headColumnSep = columnSep + + def setHeadColumnSep(self, columnSep=''): + self.headColumnSep = columnSep if columnSep == '': - self.noOfHeadLineColumns = 0 + self.noOfHeadLineColumns = 0 else: self.counNoOfHeadColumns() + def counNoOfHeadColumns(self): pass + def searchForHeadColumnSep(self, headLine): if ' ' in headLine: return ' ' return '' - def setRowColumnSep(self, columnSep = ''): - self.rowColumnSep = columnSep - def setHeadLine(self, headLine = ''): + def setRowColumnSep(self, columnSep=''): + self.rowColumnSep = columnSep + + def setHeadLine(self, headLine=''): self.setHeadColumnSep() - self.setRowColumnSep() + self.setRowColumnSep() if headLine != '': sep = self.searchForHeadColumnSep(headLine) if sep != '': self.headLine = headLine self.setHeadColumnSep(sep) - diff --git a/src/fenrirscreenreader/core/textManager.py b/src/fenrirscreenreader/core/textManager.py index 827c6391..2ab27c1f 100644 --- a/src/fenrirscreenreader/core/textManager.py +++ b/src/fenrirscreenreader/core/textManager.py @@ -5,25 +5,33 @@ # By Chrys, Storm Dragon, and contributers. from fenrirscreenreader.core import debug -import re, string +import re +import string + class textManager(): def __init__(self): # https://regex101.com/ self.regExSingle = re.compile(r'(([^\w\s])\2{5,})') - self.regExDouble = re.compile(r'([^\w\s]{2,}){5,}') + self.regExDouble = re.compile(r'([^\w\s]{2,}){5,}') + def initialize(self, environment): - self.env = environment + self.env = environment + def shutdown(self): - pass + pass def replaceHeadLines(self, text): # fast len check for bigger typing echo if len(text) < 5: return text # more strong check, to not match if not needed: - if len(text.strip(string.ascii_letters+string.digits+string.whitespace)) < 5: - return text + if len( + text.strip( + string.ascii_letters + + string.digits + + string.whitespace)) < 5: + return text result = '' newText = '' lastPos = 0 @@ -32,32 +40,38 @@ class textManager(): newText += text[lastPos:span[0]] numberOfChars = len(text[span[0]:span[1]]) name = text[span[0]:span[1]][:2] - if not self.env['runtime']['punctuationManager'].isPuctuation(name[0]): + if not self.env['runtime']['punctuationManager'].isPuctuation( + name[0]): lastPos = span[1] - continue + continue if name[0] == name[1]: - newText += ' ' + str(numberOfChars) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' ' + newText += ' ' + \ + str(numberOfChars) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' ' else: - newText += ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' ' + str(int(numberOfChars / 2)) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[1], True) + ' ' + newText += ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' ' + str(int( + numberOfChars / 2)) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[1], True) + ' ' lastPos = span[1] if lastPos != 0: newText += ' ' newText += text[lastPos:] - lastPos = 0 + lastPos = 0 for match in self.regExSingle.finditer(newText): - span = match.span() + span = match.span() result += newText[lastPos:span[0]] numberOfChars = len(newText[span[0]:span[1]]) name = newText[span[0]:span[1]][:2] - if not self.env['runtime']['punctuationManager'].isPuctuation(name[0]): - lastPos = span[1] - continue + if not self.env['runtime']['punctuationManager'].isPuctuation( + name[0]): + lastPos = span[1] + continue if name[0] == name[1]: - result += ' ' + str(numberOfChars) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' ' + result += ' ' + str(numberOfChars) + ' ' + \ + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' ' else: - result += ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' ' + str(int(numberOfChars / 2)) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[1], True) + ' ' + result += ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' ' + str(int( + numberOfChars / 2)) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[1], True) + ' ' lastPos = span[1] if lastPos != 0: - result += ' ' + result += ' ' result += newText[lastPos:] - return result + return result diff --git a/src/fenrirscreenreader/core/vmenuManager.py b/src/fenrirscreenreader/core/vmenuManager.py index bf7fef43..e2fe215c 100755 --- a/src/fenrirscreenreader/core/vmenuManager.py +++ b/src/fenrirscreenreader/core/vmenuManager.py @@ -5,12 +5,20 @@ # By Chrys, Storm Dragon, and contributers. from fenrirscreenreader.core import debug +from fenrirscreenreader.core.i18n import _ from fenrirscreenreader.utils import module_utils -import os, inspect, time +import os +import inspect +import time -currentdir = os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe())))) +currentdir = os.path.dirname( + os.path.realpath( + os.path.abspath( + inspect.getfile( + inspect.currentframe())))) fenrirPath = os.path.dirname(currentdir) + class vmenuManager(): def __init__(self): self.menuDict = {} @@ -21,25 +29,32 @@ class vmenuManager(): self.useTimeout = True self.searchText = '' self.lastSearchTime = time.time() + def initialize(self, environment): self.env = environment # use default path - self.defaultVMenuPath = fenrirPath+ "/commands/vmenu-profiles/" + self.env['runtime']['inputManager'].getShortcutType() + self.defaultVMenuPath = fenrirPath + "/commands/vmenu-profiles/" + \ + self.env['runtime']['inputManager'].getShortcutType() # if there is no user configuration - if self.env['runtime']['settingsManager'].getSetting('menu', 'vmenuPath') != '': - self.defaultVMenuPath = self.env['runtime']['settingsManager'].getSetting('menu', 'vmenuPath') + if self.env['runtime']['settingsManager'].getSetting( + 'menu', 'vmenuPath') != '': + self.defaultVMenuPath = self.env['runtime']['settingsManager'].getSetting( + 'menu', 'vmenuPath') if not self.defaultVMenuPath.endswith('/'): self.defaultVMenuPath += '/' self.defaultVMenuPath += self.env['runtime']['inputManager'].getShortcutType() self.createMenuTree() self.closeAfterAction = False + def shutdown(self): pass + def clearSearchText(self): self.searchText = '' - def searchEntry(self, value, forceReset = False): - if self.currIndex == None: + + def searchEntry(self, value, forceReset=False): + if self.currIndex is None: return '' if self.reset or forceReset: self.clearSearchText() @@ -59,7 +74,7 @@ class vmenuManager(): if startIndex == self.getCurrIndex(): return '' - def setCurrMenu(self, currMenu = ''): + def setCurrMenu(self, currMenu=''): self.currIndex = None self.currMenu = '' if currMenu != '': @@ -78,13 +93,17 @@ class vmenuManager(): else: self.currMenu = '' self.currIndex = None + def getCurrMenu(self): return self.currMenu + def getActive(self): return self.active - def togglelVMenuMode(self, closeAfterAction = True): + + def togglelVMenuMode(self, closeAfterAction=True): self.setActive(not self.getActive(), closeAfterAction) - def setActive(self, active, closeAfterAction = True): + + def setActive(self, active, closeAfterAction=True): if self.env['runtime']['helpManager'].isTutorialMode(): return self.active = active @@ -97,20 +116,26 @@ class vmenuManager(): try: if self.currMenu != '': self.setCurrMenu(self.currMenu) - if self.currIndex == None: + if self.currIndex is None: if len(self.menuDict) > 0: self.currIndex = [0] except Exception as e: print(e) try: # navigation - self.env['bindings'][str([1, ['KEY_ESC']])] = 'TOGGLE_VMENU_MODE' + self.env['bindings'][str( + [1, ['KEY_ESC']])] = 'TOGGLE_VMENU_MODE' self.env['bindings'][str([1, ['KEY_UP']])] = 'PREV_VMENU_ENTRY' - self.env['bindings'][str([1, ['KEY_DOWN']])] = 'NEXT_VMENU_ENTRY' - self.env['bindings'][str([1, ['KEY_SPACE']])] = 'CURR_VMENU_ENTRY' - self.env['bindings'][str([1, ['KEY_LEFT']])] = 'DEC_LEVEL_VMENU' - self.env['bindings'][str([1, ['KEY_RIGHT']])] = 'INC_LEVEL_VMENU' - self.env['bindings'][str([1, ['KEY_ENTER']])] = 'EXEC_VMENU_ENTRY' + self.env['bindings'][str( + [1, ['KEY_DOWN']])] = 'NEXT_VMENU_ENTRY' + self.env['bindings'][str( + [1, ['KEY_SPACE']])] = 'CURR_VMENU_ENTRY' + self.env['bindings'][str( + [1, ['KEY_LEFT']])] = 'DEC_LEVEL_VMENU' + self.env['bindings'][str( + [1, ['KEY_RIGHT']])] = 'INC_LEVEL_VMENU' + self.env['bindings'][str( + [1, ['KEY_ENTER']])] = 'EXEC_VMENU_ENTRY' # search self.env['bindings'][str([1, ['KEY_A']])] = 'SEARCH_A' self.env['bindings'][str([1, ['KEY_B']])] = 'SEARCH_B' @@ -139,45 +164,54 @@ class vmenuManager(): self.env['bindings'][str([1, ['KEY_Y']])] = 'SEARCH_Y' self.env['bindings'][str([1, ['KEY_Z']])] = 'SEARCH_Z' # page navigation - self.env['bindings'][str([1, ['KEY_PAGEUP']])] = 'PAGE_UP_VMENU' - self.env['bindings'][str([1, ['KEY_PAGEDOWN']])] = 'PAGE_DOWN_VMENU' + self.env['bindings'][str( + [1, ['KEY_PAGEUP']])] = 'PAGE_UP_VMENU' + self.env['bindings'][str( + [1, ['KEY_PAGEDOWN']])] = 'PAGE_DOWN_VMENU' except Exception as e: print(e) else: try: self.currIndex = None - self.env['bindings'] = self.env['runtime']['settingsManager'].getBindingBackup() + self.env['bindings'] = self.env['runtime']['settingsManager'].getBindingBackup( + ) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vmenuManager setActive: Error loading binding backup: ' + str(e), debug.debugLevel.ERROR) - def createMenuTree(self, resetIndex = True): + self.env['runtime']['debug'].writeDebugOut( + 'vmenuManager setActive: Error loading binding backup: ' + str(e), + debug.debugLevel.ERROR) + + def createMenuTree(self, resetIndex=True): if resetIndex: self.currIndex = None - menu = self.fs_tree_to_dict( self.defaultVMenuPath) + menu = self.fs_tree_to_dict(self.defaultVMenuPath) if menu: self.menuDict = menu - + # Add dynamic voice menus try: from fenrirscreenreader.core.dynamicVoiceMenu import addDynamicVoiceMenus addDynamicVoiceMenus(self) except Exception as e: print(f"Error adding dynamic voice menus: {e}") - + # index still valid? - if self.currIndex != None: + if self.currIndex is not None: try: r = self.getValueByPath(self.menuDict, self.currIndex) if r == {}: self.currIndex = None except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vmenuManager createMenuTree: Error checking menu index validity: ' + str(e), debug.debugLevel.ERROR) - self.currIndex = None + self.env['runtime']['debug'].writeDebugOut( + 'vmenuManager createMenuTree: Error checking menu index validity: ' + str(e), + debug.debugLevel.ERROR) + self.currIndex = None + def executeMenu(self): - if self.currIndex == None: + if self.currIndex is None: return try: command = self.getValueByPath(self.menuDict, self.currIndex) - if not command == None: + if command is not None: command.run() if self.closeAfterAction: self.setActive(False) @@ -185,24 +219,30 @@ class vmenuManager(): try: self.incLevel() text = self.getCurrentEntry() - self.env['runtime']['outputManager'].presentText(text, interrupt=True) + self.env['runtime']['outputManager'].presentText( + text, interrupt=True) except Exception as ex: - self.env['runtime']['debug'].writeDebugOut('vmenuManager executeMenu: Error presenting menu text: ' + str(ex), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'vmenuManager executeMenu: Error presenting menu text: ' + str(ex), + debug.debugLevel.ERROR) def incLevel(self): - if self.currIndex == None: + if self.currIndex is None: return False try: - r = self.getValueByPath(self.menuDict, self.currIndex +[0]) + r = self.getValueByPath(self.menuDict, self.currIndex + [0]) if r == {}: return False except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vmenuManager incLevel: Error accessing menu path: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'vmenuManager incLevel: Error accessing menu path: ' + str(e), + debug.debugLevel.ERROR) return False self.currIndex.append(0) return True + def decLevel(self): - if self.currIndex == None: + if self.currIndex is None: return False if self.currMenu != '': if len(self.currIndex) <= 2: @@ -211,31 +251,37 @@ class vmenuManager(): return False self.currIndex = self.currIndex[:len(self.currIndex) - 1] return True + def nextIndex(self): - if self.currIndex == None: + if self.currIndex is None: return False - if self.currIndex[len(self.currIndex) - 1] + 1 >= len(self.getNestedByPath(self.menuDict, self.currIndex[:-1])): - self.currIndex[len(self.currIndex) - 1] = 0 + if self.currIndex[len(self.currIndex) - 1] + 1 >= len( + self.getNestedByPath(self.menuDict, self.currIndex[:-1])): + self.currIndex[len(self.currIndex) - 1] = 0 else: self.currIndex[len(self.currIndex) - 1] += 1 return True + def getCurrIndex(self): - if self.currIndex == None: - return 0 + if self.currIndex is None: + return 0 return self.currIndex[len(self.currIndex) - 1] + def prevIndex(self): - if self.currIndex == None: + if self.currIndex is None: return False if self.currIndex[len(self.currIndex) - 1] == 0: - self.currIndex[len(self.currIndex) - 1] = len(self.getNestedByPath(self.menuDict, self.currIndex[:-1])) - 1 + self.currIndex[len(self.currIndex) - 1] = len( + self.getNestedByPath(self.menuDict, self.currIndex[:-1])) - 1 else: self.currIndex[len(self.currIndex) - 1] -= 1 return True - + def pageUp(self): - if self.currIndex == None: + if self.currIndex is None: return False - menuSize = len(self.getNestedByPath(self.menuDict, self.currIndex[:-1])) + menuSize = len(self.getNestedByPath( + self.menuDict, self.currIndex[:-1])) if menuSize <= 1: return False jumpSize = max(1, int(menuSize * 0.1)) # 10% of menu size, minimum 1 @@ -244,11 +290,12 @@ class vmenuManager(): newIndex = 0 self.currIndex[len(self.currIndex) - 1] = newIndex return True - + def pageDown(self): - if self.currIndex == None: + if self.currIndex is None: return False - menuSize = len(self.getNestedByPath(self.menuDict, self.currIndex[:-1])) + menuSize = len(self.getNestedByPath( + self.menuDict, self.currIndex[:-1])) if menuSize <= 1: return False jumpSize = max(1, int(menuSize * 0.1)) # 10% of menu size, minimum 1 @@ -259,10 +306,18 @@ class vmenuManager(): return True def getCurrentEntry(self): - return self.getKeysByPath(self.menuDict, self.currIndex)[self.currIndex[-1]] + return self.getKeysByPath(self.menuDict, self.currIndex)[ + self.currIndex[-1]] + def fs_tree_to_dict(self, path_): for root, dirs, files in os.walk(path_): - tree = {d + ' ' + _('Menu'): self.fs_tree_to_dict(os.path.join(root, d)) for d in dirs if not d.startswith('__')} + tree = { + d + + ' ' + + _('Menu'): self.fs_tree_to_dict( + os.path.join( + root, + d)) for d in dirs if not d.startswith('__')} for f in files: try: fileName, fileExtension = os.path.splitext(f) @@ -272,11 +327,13 @@ class vmenuManager(): # Skip base classes that shouldn't be loaded as commands if fileName.endswith('_base'): continue - command = self.env['runtime']['commandManager'].loadFile(root + '/' + f) + command = self.env['runtime']['commandManager'].loadFile( + root + '/' + f) tree.update({fileName + ' ' + _('Action'): command}) except Exception as e: print(e) return tree # note we discontinue iteration trough os.walk + def getNestedByPath(self, complete, path): path = path.copy() if path != []: @@ -286,10 +343,9 @@ class vmenuManager(): else: return complete - def getKeysByPath(self, complete, path): if not isinstance(complete, dict): - return[] + return [] d = complete for i in path[:-1]: d = d[list(d.keys())[i]] diff --git a/src/fenrirscreenreader/fenrirVersion.py b/src/fenrirscreenreader/fenrirVersion.py index 8dd4884c..5d10ef64 100644 --- a/src/fenrirscreenreader/fenrirVersion.py +++ b/src/fenrirscreenreader/fenrirVersion.py @@ -4,5 +4,5 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. -version = "2025.06.28" +version = "2025.07.01" codeName = "testing" diff --git a/src/fenrirscreenreader/inputDriver/debugDriver.py b/src/fenrirscreenreader/inputDriver/debugDriver.py index 1908003d..6a72371b 100644 --- a/src/fenrirscreenreader/inputDriver/debugDriver.py +++ b/src/fenrirscreenreader/inputDriver/debugDriver.py @@ -8,65 +8,72 @@ import time from fenrirscreenreader.core import debug from fenrirscreenreader.core.inputDriver import inputDriver + class driver(inputDriver): def __init__(self): inputDriver.__init__(self) - + def initialize(self, environment): self.env = environment self.env['runtime']['inputManager'].setShortcutType('KEY') self._initialized = True print('Input Debug Driver: Initialized') - + def shutdown(self): if self._initialized: self.removeAllDevices() self._initialized = False print('Input Debug Driver: Shutdown') - + def getInputEvent(self): time.sleep(0.1) if not self._initialized: return None print('Input Debug Driver: getInputEvent') return None + def writeEventBuffer(self): if not self._initialized: return print('Input Debug Driver: writeEventBuffer') + def clearEventBuffer(self): if not self._initialized: return del self.env['input']['eventBuffer'][:] print('Input Debug Driver: clearEventBuffer') - def updateInputDevices(self, newDevices = None, init = False): + + def updateInputDevices(self, newDevices=None, init=False): if not self._initialized: return - print('Input Debug Driver: updateInputDevices') - def getLedState(self, led = 0): + print('Input Debug Driver: updateInputDevices') + + def getLedState(self, led=0): if not self._initialized: return False return False - def toggleLedState(self, led = 0): + + def toggleLedState(self, led=0): if not self._initialized: return print('Input Debug Driver: toggleLedState') + def grabAllDevices(self): if not self._initialized: return print('Input Debug Driver: grabAllDevices') + def ungrabAllDevices(self): if not self._initialized: return print('Input Debug Driver: ungrabAllDevices') - + def removeAllDevices(self): if not self._initialized: - return + return print('Input Debug Driver: removeAllDevices') + def __del__(self): if self._initialized: self.removeAllDevices() print('Input Debug Driver: __del__') - - diff --git a/src/fenrirscreenreader/inputDriver/dummyDriver.py b/src/fenrirscreenreader/inputDriver/dummyDriver.py index 1c4d0ed8..71dd0bb7 100644 --- a/src/fenrirscreenreader/inputDriver/dummyDriver.py +++ b/src/fenrirscreenreader/inputDriver/dummyDriver.py @@ -8,6 +8,7 @@ import time from fenrirscreenreader.core import debug from fenrirscreenreader.core.inputDriver import inputDriver + class driver(inputDriver): def __init__(self): inputDriver.__init__(self) diff --git a/src/fenrirscreenreader/inputDriver/evdevDriver.py b/src/fenrirscreenreader/inputDriver/evdevDriver.py index 21a970ca..deef55d7 100644 --- a/src/fenrirscreenreader/inputDriver/evdevDriver.py +++ b/src/fenrirscreenreader/inputDriver/evdevDriver.py @@ -1,6 +1,16 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. +from fenrirscreenreader.core.inputDriver import inputDriver +from fenrirscreenreader.core import debug +from fenrirscreenreader.core import inputData +from fenrirscreenreader.core.eventData import fenrirEventType +import threading +from ctypes import c_bool +from multiprocessing.sharedctypes import Value +import multiprocessing +from select import select +import time _evdevAvailable = False _udevAvailable = False _evdevAvailableError = '' @@ -19,17 +29,6 @@ try: except Exception as e: _udevAvailableError = str(e) -import time -from select import select -import multiprocessing -from multiprocessing.sharedctypes import Value -from ctypes import c_bool -import threading - -from fenrirscreenreader.core.eventData import fenrirEventType -from fenrirscreenreader.core import inputData -from fenrirscreenreader.core import debug -from fenrirscreenreader.core.inputDriver import inputDriver class driver(inputDriver): def __init__(self): @@ -43,6 +42,7 @@ class driver(inputDriver): self.watchDog = Value(c_bool, True) self.UInputinject = UInput() self._deviceLock = threading.Lock() + def initialize(self, environment): self.env = environment self.env['runtime']['inputManager'].setShortcutType('KEY') @@ -51,14 +51,18 @@ class driver(inputDriver): global _evdevAvailableError global _udevAvailableError if not _udevAvailable: - self.env['runtime']['debug'].writeDebugOut('InputDriver:' + _udevAvailableError, debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'InputDriver:' + _udevAvailableError, debug.debugLevel.ERROR) if not _evdevAvailable: - self.env['runtime']['debug'].writeDebugOut('InputDriver:' + _evdevAvailableError, debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'InputDriver:' + _evdevAvailableError, debug.debugLevel.ERROR) return if _udevAvailable: - self.env['runtime']['processManager'].addCustomEventThread(self.plugInputDeviceWatchdogUdev) - self.env['runtime']['processManager'].addCustomEventThread(self.inputWatchdog) + self.env['runtime']['processManager'].addCustomEventThread( + self.plugInputDeviceWatchdogUdev) + self.env['runtime']['processManager'].addCustomEventThread( + self.inputWatchdog) self._initialized = True def plugInputDeviceWatchdogUdev(self, active, eventQueue): @@ -71,25 +75,41 @@ class driver(inputDriver): validDevices = [] device = monitor.poll(1) while device: - self.env['runtime']['debug'].writeDebugOut('plugInputDeviceWatchdogUdev:' + str(device), debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'plugInputDeviceWatchdogUdev:' + str(device), debug.debugLevel.INFO) try: try: # FIX: Check if attributes exist before accessing them - if hasattr(device, 'name') and device.name and device.name.upper() in ['','SPEAKUP','FENRIR-UINPUT']: + if hasattr( + device, + 'name') and device.name and device.name.upper() in [ + '', + 'SPEAKUP', + 'FENRIR-UINPUT']: ignorePlug = True - if hasattr(device, 'phys') and device.phys and device.phys.upper() in ['','SPEAKUP','FENRIR-UINPUT']: + if hasattr( + device, + 'phys') and device.phys and device.phys.upper() in [ + '', + 'SPEAKUP', + 'FENRIR-UINPUT']: ignorePlug = True - if hasattr(device, 'name') and device.name and 'BRLTTY' in device.name.upper(): + if hasattr( + device, + 'name') and device.name and 'BRLTTY' in device.name.upper(): ignorePlug = True except Exception as e: - self.env['runtime']['debug'].writeDebugOut("plugInputDeviceWatchdogUdev CHECK NAME CRASH: " + str(e), debug.debugLevel.ERROR) - + self.env['runtime']['debug'].writeDebugOut( + "plugInputDeviceWatchdogUdev CHECK NAME CRASH: " + str(e), debug.debugLevel.ERROR) + if not ignorePlug: virtual = '/sys/devices/virtual/input/' in device.sys_path if device.device_node: - validDevices.append({'device': device.device_node, 'virtual': virtual}) + validDevices.append( + {'device': device.device_node, 'virtual': virtual}) except Exception as e: - self.env['runtime']['debug'].writeDebugOut("plugInputDeviceWatchdogUdev APPEND CRASH: " + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "plugInputDeviceWatchdogUdev APPEND CRASH: " + str(e), debug.debugLevel.ERROR) try: pollTimeout = 1 device = monitor.poll(pollTimeout) @@ -97,20 +117,22 @@ class driver(inputDriver): device = None ignorePlug = False if validDevices: - eventQueue.put({"Type": fenrirEventType.PlugInputDevice, "Data": validDevices}) + eventQueue.put( + {"Type": fenrirEventType.PlugInputDevice, "Data": validDevices}) return time.time() def inputWatchdog(self, active, eventQueue): try: while active.value: - # Get a snapshot of devices for select() to avoid lock contention + # Get a snapshot of devices for select() to avoid lock + # contention with self._deviceLock: devices_snapshot = self.iDevices.copy() - + if not devices_snapshot: time.sleep(0.1) continue - + r, w, x = select(devices_snapshot, [], [], 0.8) event = None foundKeyInSequence = False @@ -123,16 +145,20 @@ class driver(inputDriver): continue device = self.iDevices[fd] udevice = self.uDevices.get(fd) - + try: event = device.read_one() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver handleInputEvent: Error reading event: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver handleInputEvent: Error reading event: ' + str(e), + debug.debugLevel.ERROR) self.removeDevice(fd) continue - while(event): - self.env['runtime']['debug'].writeDebugOut('inputWatchdog: EVENT:' + str(event), debug.debugLevel.INFO) - self.env['input']['eventBuffer'].append([device, udevice, event]) + while (event): + self.env['runtime']['debug'].writeDebugOut( + 'inputWatchdog: EVENT:' + str(event), debug.debugLevel.INFO) + self.env['input']['eventBuffer'].append( + [device, udevice, event]) if event.type == evdev.events.EV_KEY: if not foundKeyInSequence: foundKeyInSequence = True @@ -141,11 +167,13 @@ class driver(inputDriver): if not currMapEvent: event = device.read_one() continue - if not isinstance(currMapEvent['EventName'], str): + if not isinstance( + currMapEvent['EventName'], str): event = device.read_one() continue if currMapEvent['EventState'] in [0, 1, 2]: - eventQueue.put({"Type": fenrirEventType.KeyboardInput, "Data": currMapEvent.copy()}) + eventQueue.put( + {"Type": fenrirEventType.KeyboardInput, "Data": currMapEvent.copy()}) eventFired = True else: if event.type in [2, 3]: @@ -155,20 +183,23 @@ class driver(inputDriver): if not foundKeyInSequence: if foreward and not eventFired: self.writeEventBuffer() - self.clearEventBuffer() + self.clearEventBuffer() except Exception as e: - self.env['runtime']['debug'].writeDebugOut("INPUT WATCHDOG CRASH: " + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + "INPUT WATCHDOG CRASH: " + str(e), debug.debugLevel.ERROR) def writeEventBuffer(self): if not self._initialized: - return + return for iDevice, uDevice, event in self.env['input']['eventBuffer']: try: if uDevice: if self.gDevices[iDevice.fd]: self.writeUInput(uDevice, event) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver writeEventBuffer: Error writing event: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver writeEventBuffer: Error writing event: ' + str(e), + debug.debugLevel.ERROR) def writeUInput(self, uDevice, event): if not self._initialized: @@ -190,12 +221,13 @@ class driver(inputDriver): else: deviceFileList = evdev.list_devices() if len(deviceFileList) == self.iDeviceNo: - return + return if not deviceFileList: return - mode = self.env['runtime']['settingsManager'].getSetting('keyboard', 'device').upper() - + mode = self.env['runtime']['settingsManager'].getSetting( + 'keyboard', 'device').upper() + iDevicesFiles = [] for device in self.iDevices: iDevicesFiles.append(self.iDevices[device].fn) @@ -213,7 +245,9 @@ class driver(inputDriver): with open(deviceFile) as f: pass except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver updateInputDevices: Error opening device file: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver updateInputDevices: Error opening device file: ' + str(e), + debug.debugLevel.ERROR) continue # 3 pos absolute # 2 pos relative @@ -221,61 +255,100 @@ class driver(inputDriver): try: currDevice = evdev.InputDevice(deviceFile) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver createDeviceType: Error creating device: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver createDeviceType: Error creating device: ' + str(e), + debug.debugLevel.ERROR) continue try: # FIX: Check if attributes exist before accessing them - if hasattr(currDevice, 'name') and currDevice.name and currDevice.name.upper() in ['', 'SPEAKUP', 'FENRIR-UINPUT']: + if hasattr( + currDevice, + 'name') and currDevice.name and currDevice.name.upper() in [ + '', + 'SPEAKUP', + 'FENRIR-UINPUT']: continue - if hasattr(currDevice, 'phys') and currDevice.phys and currDevice.phys.upper() in ['', 'SPEAKUP', 'FENRIR-UINPUT']: + if hasattr( + currDevice, + 'phys') and currDevice.phys and currDevice.phys.upper() in [ + '', + 'SPEAKUP', + 'FENRIR-UINPUT']: continue - if hasattr(currDevice, 'name') and currDevice.name and 'BRLTTY' in currDevice.name.upper(): + if hasattr( + currDevice, + 'name') and currDevice.name and 'BRLTTY' in currDevice.name.upper(): continue except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver: Error checking device capabilities: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver: Error checking device capabilities: ' + str(e), + debug.debugLevel.ERROR) cap = currDevice.capabilities() if mode in ['ALL', 'NOMICE']: if eventType.EV_KEY in cap: - if 116 in cap[eventType.EV_KEY] and len(cap[eventType.EV_KEY]) < 10: - self.env['runtime']['debug'].writeDebugOut('Device Skipped (has 116):' + currDevice.name, debug.debugLevel.INFO) + if 116 in cap[eventType.EV_KEY] and len( + cap[eventType.EV_KEY]) < 10: + self.env['runtime']['debug'].writeDebugOut( + 'Device Skipped (has 116):' + currDevice.name, debug.debugLevel.INFO) continue if len(cap[eventType.EV_KEY]) < 60: - self.env['runtime']['debug'].writeDebugOut('Device Skipped (< 60 keys):' + currDevice.name, debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'Device Skipped (< 60 keys):' + currDevice.name, debug.debugLevel.INFO) continue if mode == 'ALL': self.addDevice(currDevice) - self.env['runtime']['debug'].writeDebugOut('Device added (ALL):' + self.iDevices[currDevice.fd].name, debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'Device added (ALL):' + self.iDevices[currDevice.fd].name, debug.debugLevel.INFO) elif mode == 'NOMICE': - if not ((eventType.EV_REL in cap) or (eventType.EV_ABS in cap)): + if not ( + (eventType.EV_REL in cap) or ( + eventType.EV_ABS in cap)): self.addDevice(currDevice) - self.env['runtime']['debug'].writeDebugOut('Device added (NOMICE):' + self.iDevices[currDevice.fd].name, debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'Device added (NOMICE):' + self.iDevices[currDevice.fd].name, debug.debugLevel.INFO) else: - self.env['runtime']['debug'].writeDebugOut('Device Skipped (NOMICE):' + currDevice.name, debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'Device Skipped (NOMICE):' + currDevice.name, debug.debugLevel.INFO) else: - self.env['runtime']['debug'].writeDebugOut('Device Skipped (no EV_KEY):' + currDevice.name, debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'Device Skipped (no EV_KEY):' + currDevice.name, debug.debugLevel.INFO) elif currDevice.name.upper() in mode.split(','): self.addDevice(currDevice) - self.env['runtime']['debug'].writeDebugOut('Device added (Name):' + self.iDevices[currDevice.fd].name, debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'Device added (Name):' + self.iDevices[currDevice.fd].name, debug.debugLevel.INFO) except Exception as e: try: - device_name = currDevice.name if hasattr(currDevice, 'name') else "unknown" - self.env['runtime']['debug'].writeDebugOut("Device Skipped (Exception): " + deviceFile + ' ' + device_name + ' ' + str(e), debug.debugLevel.INFO) + device_name = currDevice.name if hasattr( + currDevice, 'name') else "unknown" + self.env['runtime']['debug'].writeDebugOut( + "Device Skipped (Exception): " + + deviceFile + + ' ' + + device_name + + ' ' + + str(e), + debug.debugLevel.INFO) except Exception as ex: - self.env['runtime']['debug'].writeDebugOut("Device Skipped (Exception): " + deviceFile + ' ' + str(ex), debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + "Device Skipped (Exception): " + deviceFile + ' ' + str(ex), + debug.debugLevel.INFO) self.iDeviceNo = len(evdev.list_devices()) self.updateMPiDevicesFD() def updateMPiDevicesFD(self): try: for fd in self.iDevices: - if not fd in self.iDevicesFD: + if fd not in self.iDevicesFD: self.iDevicesFD.append(fd) for fd in self.iDevicesFD: - if not fd in self.iDevices: + if fd not in self.iDevices: self.iDevicesFD.remove(fd) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver updateMPiDevicesFD: Error updating device file descriptors: ' + str(e), debug.debugLevel.ERROR) - + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver updateMPiDevicesFD: Error updating device file descriptors: ' + + str(e), + debug.debugLevel.ERROR) + def mapEvent(self, event): if not self._initialized: return None @@ -310,7 +383,7 @@ class driver(inputDriver): if led in dev.leds(): return True return False - + def toggleLedState(self, led=0): if not self.hasIDevices(): return False @@ -323,7 +396,7 @@ class driver(inputDriver): self.iDevices[i].set_led(led, 0) else: self.iDevices[i].set_led(led, 1) - + def grabAllDevices(self): if not self._initialized: return True @@ -332,7 +405,7 @@ class driver(inputDriver): if not self.gDevices[fd]: ok = ok and self.grabDevice(fd) return ok - + def ungrabAllDevices(self): if not self._initialized: return True @@ -341,9 +414,10 @@ class driver(inputDriver): if self.gDevices[fd]: ok = ok and self.ungrabDevice(fd) return ok - + def createUInputDev(self, fd): - if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'keyboard', 'grabDevices'): self.uDevices[fd] = None return try: @@ -351,132 +425,182 @@ class driver(inputDriver): return except KeyError: self.uDevices[fd] = None - if self.uDevices[fd] != None: + if self.uDevices[fd] is not None: return try: - self.uDevices[fd] = UInput.from_device(self.iDevices[fd], name='fenrir-uinput', phys='fenrir-uinput') + self.uDevices[fd] = UInput.from_device( + self.iDevices[fd], name='fenrir-uinput', phys='fenrir-uinput') except Exception as e: try: - self.env['runtime']['debug'].writeDebugOut('InputDriver evdev: compat fallback: ' + str(e), debug.debugLevel.WARNING) + self.env['runtime']['debug'].writeDebugOut( + 'InputDriver evdev: compat fallback: ' + str(e), debug.debugLevel.WARNING) dev = self.iDevices[fd] cap = dev.capabilities() del cap[0] self.uDevices[fd] = UInput( - cap, - name='fenrir-uinput', - phys='fenrir-uinput' + cap, + name='fenrir-uinput', + phys='fenrir-uinput' ) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('InputDriver evdev: init Uinput not possible: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'InputDriver evdev: init Uinput not possible: ' + str(e), + debug.debugLevel.ERROR) return - + def addDevice(self, newDevice): - self.env['runtime']['debug'].writeDebugOut('InputDriver evdev: device added: ' + str(newDevice.fd) + ' ' + str(newDevice), debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'InputDriver evdev: device added: ' + str( + newDevice.fd) + ' ' + str(newDevice), + debug.debugLevel.INFO) with self._deviceLock: try: - self.iDevices[newDevice.fd] = newDevice + self.iDevices[newDevice.fd] = newDevice self.createUInputDev(newDevice.fd) self.gDevices[newDevice.fd] = False except Exception as e: - self.env['runtime']['debug'].writeDebugOut('InputDriver evdev: error adding device: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'InputDriver evdev: error adding device: ' + str(e), debug.debugLevel.ERROR) # if it doesnt work clean up try: - del(self.iDevices[newDevice.fd]) + del (self.iDevices[newDevice.fd]) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver removeDevice: Error removing iDevice: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver removeDevice: Error removing iDevice: ' + str(e), + debug.debugLevel.ERROR) try: - del(self.uDevices[newDevice.fd]) + del (self.uDevices[newDevice.fd]) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver removeDevice: Error removing uDevice: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver removeDevice: Error removing uDevice: ' + str(e), + debug.debugLevel.ERROR) try: - del(self.gDevices[newDevice.fd]) + del (self.gDevices[newDevice.fd]) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver addDevice: Error cleaning up gDevice: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver addDevice: Error cleaning up gDevice: ' + str(e), + debug.debugLevel.ERROR) def grabDevice(self, fd): - if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'keyboard', 'grabDevices'): return True - + # FIX: Handle exception variable scope correctly grab_error = None try: self.iDevices[fd].grab() self.gDevices[fd] = True - self.env['runtime']['debug'].writeDebugOut('InputDriver evdev: grab device (' + str(self.iDevices[fd].name) + ')', debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'InputDriver evdev: grab device (' + str(self.iDevices[fd].name) + ')', debug.debugLevel.INFO) # Reset modifier keys on successful grab if self.uDevices[fd]: - modifierKeys = [e.KEY_LEFTCTRL, e.KEY_RIGHTCTRL, e.KEY_LEFTALT, e.KEY_RIGHTALT, e.KEY_LEFTSHIFT, e.KEY_RIGHTSHIFT] + modifierKeys = [ + e.KEY_LEFTCTRL, + e.KEY_RIGHTCTRL, + e.KEY_LEFTALT, + e.KEY_RIGHTALT, + e.KEY_LEFTSHIFT, + e.KEY_RIGHTSHIFT] for key in modifierKeys: try: self.uDevices[fd].write(e.EV_KEY, key, 0) # 0 = key up self.uDevices[fd].syn() except Exception as mod_error: - self.env['runtime']['debug'].writeDebugOut('Failed to reset modifier key: ' + str(mod_error), debug.debugLevel.WARNING) + self.env['runtime']['debug'].writeDebugOut( + 'Failed to reset modifier key: ' + str(mod_error), debug.debugLevel.WARNING) except IOError: if not self.gDevices[fd]: return False except Exception as ex: grab_error = ex - + if grab_error: - self.env['runtime']['debug'].writeDebugOut('InputDriver evdev: grabing not possible: ' + str(grab_error), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'InputDriver evdev: grabing not possible: ' + + str(grab_error), + debug.debugLevel.ERROR) return False - + return True def ungrabDevice(self, fd): - if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'): + if not self.env['runtime']['settingsManager'].getSettingAsBool( + 'keyboard', 'grabDevices'): return True - + # FIX: Handle exception variable scope correctly ungrab_error = None try: self.iDevices[fd].ungrab() self.gDevices[fd] = False - self.env['runtime']['debug'].writeDebugOut('InputDriver evdev: ungrab device (' + str(self.iDevices[fd].name) + ')', debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'InputDriver evdev: ungrab device (' + str(self.iDevices[fd].name) + ')', debug.debugLevel.INFO) except IOError: if self.gDevices[fd]: return False except Exception as ex: ungrab_error = ex - + if ungrab_error: - self.env['runtime']['debug'].writeDebugOut('InputDriver evdev: ungrabing not possible: ' + str(ungrab_error), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'InputDriver evdev: ungrabing not possible: ' + + str(ungrab_error), + debug.debugLevel.ERROR) return False - + return True - + def removeDevice(self, fd): with self._deviceLock: try: - self.env['runtime']['debug'].writeDebugOut('InputDriver evdev: device removed: ' + str(fd) + ' ' + str(self.iDevices[fd]), debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'InputDriver evdev: device removed: ' + str(fd) + ' ' + str( + self.iDevices[fd]), debug.debugLevel.INFO) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('InputDriver evdev: device removed: ' + str(fd) + ' Error: ' + str(e), debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'InputDriver evdev: device removed: ' + + str(fd) + + ' Error: ' + + str(e), + debug.debugLevel.INFO) self.clearEventBuffer() try: self.ungrabDevice(fd) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver removeDevice: Error ungrabbing device ' + str(fd) + ': ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver removeDevice: Error ungrabbing device ' + str(fd) + ': ' + str(e), + debug.debugLevel.ERROR) try: self.iDevices[fd].close() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver removeDevice: Error closing iDevice ' + str(fd) + ': ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver removeDevice: Error closing iDevice ' + str(fd) + ': ' + str(e), + debug.debugLevel.ERROR) try: self.uDevices[fd].close() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver removeDevice: Error closing uDevice ' + str(fd) + ': ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver removeDevice: Error closing uDevice ' + str(fd) + ': ' + str(e), + debug.debugLevel.ERROR) try: - del(self.iDevices[fd]) + del (self.iDevices[fd]) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver removeDevice: Error deleting iDevice ' + str(fd) + ': ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver removeDevice: Error deleting iDevice ' + str(fd) + ': ' + str(e), + debug.debugLevel.ERROR) try: - del(self.uDevices[fd]) + del (self.uDevices[fd]) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver removeDevice: Error deleting uDevice ' + str(fd) + ': ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver removeDevice: Error deleting uDevice ' + str(fd) + ': ' + str(e), + debug.debugLevel.ERROR) try: - del(self.gDevices[fd]) + del (self.gDevices[fd]) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver removeDevice: Error deleting gDevice ' + str(fd) + ': ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver removeDevice: Error deleting gDevice ' + str(fd) + ': ' + str(e), + debug.debugLevel.ERROR) self.updateMPiDevicesFD() def hasIDevices(self): @@ -495,7 +619,9 @@ class driver(inputDriver): self.UInputinject.write(e.EV_KEY, e.ecodes[key], state) self.UInputinject.syn() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('evdevDriver sendKey: Error sending key ' + str(key) + ': ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'evdevDriver sendKey: Error sending key ' + str(key) + ': ' + str(e), + debug.debugLevel.ERROR) def removeAllDevices(self): if not self.hasIDevices(): diff --git a/src/fenrirscreenreader/inputDriver/ptyDriver.py b/src/fenrirscreenreader/inputDriver/ptyDriver.py index 13a00811..15d0f035 100644 --- a/src/fenrirscreenreader/inputDriver/ptyDriver.py +++ b/src/fenrirscreenreader/inputDriver/ptyDriver.py @@ -8,10 +8,12 @@ import time from fenrirscreenreader.core import debug from fenrirscreenreader.core.inputDriver import inputDriver + class driver(inputDriver): def __init__(self): self._isInitialized = False inputDriver.__init__(self) + def initialize(self, environment): self.env = environment self.env['runtime']['inputManager'].setShortcutType('BYTE') diff --git a/src/fenrirscreenreader/remoteDriver/dummyDriver.py b/src/fenrirscreenreader/remoteDriver/dummyDriver.py index aae81930..001f4023 100644 --- a/src/fenrirscreenreader/remoteDriver/dummyDriver.py +++ b/src/fenrirscreenreader/remoteDriver/dummyDriver.py @@ -7,6 +7,7 @@ from fenrirscreenreader.core import debug from fenrirscreenreader.core.remoteDriver import remoteDriver + class driver(remoteDriver): def __init__(self): remoteDriver.__init__(self) diff --git a/src/fenrirscreenreader/remoteDriver/tcpDriver.py b/src/fenrirscreenreader/remoteDriver/tcpDriver.py index 3073c9ec..b27ac19b 100644 --- a/src/fenrirscreenreader/remoteDriver/tcpDriver.py +++ b/src/fenrirscreenreader/remoteDriver/tcpDriver.py @@ -8,20 +8,28 @@ from fenrirscreenreader.core import debug from fenrirscreenreader.core.remoteDriver import remoteDriver from fenrirscreenreader.core.eventData import fenrirEventType -import select, socket, os, os.path +import select +import socket +import os +import os.path + class driver(remoteDriver): def __init__(self): remoteDriver.__init__(self) + def initialize(self, environment): - self.env = environment - self.env['runtime']['processManager'].addCustomEventThread(self.watchDog, multiprocess=True) + self.env = environment + self.env['runtime']['processManager'].addCustomEventThread( + self.watchDog, multiprocess=True) + def watchDog(self, active, eventQueue): # echo "command say this is a test" | nc localhost 22447 self.fenrirSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.fenrirSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.host = '127.0.0.1' - self.port = self.env['runtime']['settingsManager'].getSettingAsInt('remote', 'port') + self.port = self.env['runtime']['settingsManager'].getSettingAsInt( + 'remote', 'port') self.fenrirSock.bind((self.host, self.port)) self.fenrirSock.listen(1) while active.value: @@ -36,18 +44,24 @@ class driver(remoteDriver): try: rawdata = client_sock.recv(8129) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('tcpDriver watchDog: Error receiving data from client: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'tcpDriver watchDog: Error receiving data from client: ' + str(e), + debug.debugLevel.ERROR) try: data = rawdata.decode("utf-8").rstrip().lstrip() - eventQueue.put({"Type":fenrirEventType.RemoteIncomming, - "Data": data - }) + eventQueue.put({"Type": fenrirEventType.RemoteIncomming, + "Data": data + }) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('tcpDriver watchDog: Error decoding/queuing data: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'tcpDriver watchDog: Error decoding/queuing data: ' + str(e), + debug.debugLevel.ERROR) try: client_sock.close() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('tcpDriver watchDog: Error closing client socket: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'tcpDriver watchDog: Error closing client socket: ' + str(e), + debug.debugLevel.ERROR) if self.fenrirSock: self.fenrirSock.close() self.fenrirSock = None diff --git a/src/fenrirscreenreader/remoteDriver/unixDriver.py b/src/fenrirscreenreader/remoteDriver/unixDriver.py index a56724ce..579b207f 100644 --- a/src/fenrirscreenreader/remoteDriver/unixDriver.py +++ b/src/fenrirscreenreader/remoteDriver/unixDriver.py @@ -8,27 +8,39 @@ from fenrirscreenreader.core import debug from fenrirscreenreader.core.remoteDriver import remoteDriver from fenrirscreenreader.core.eventData import fenrirEventType -import select, socket, os, os.path +import select +import socket +import os +import os.path class driver(remoteDriver): def __init__(self): remoteDriver.__init__(self) + def initialize(self, environment): self.env = environment - self.env['runtime']['processManager'].addCustomEventThread(self.watchDog, multiprocess=True) + self.env['runtime']['processManager'].addCustomEventThread( + self.watchDog, multiprocess=True) + def watchDog(self, active, eventQueue): - # echo "command say this is a test" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock + # echo "command say this is a test" | socat - + # UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock socketFile = '' try: - socketFile = self.env['runtime']['settingsManager'].getSetting('remote', 'socketFile') + socketFile = self.env['runtime']['settingsManager'].getSetting( + 'remote', 'socketFile') except Exception as e: - self.env['runtime']['debug'].writeDebugOut('unixDriver watchDog: Error getting socket file setting: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'unixDriver watchDog: Error getting socket file setting: ' + str(e), + debug.debugLevel.ERROR) if socketFile == '': - if self.env['runtime']['settingsManager'].getSetting('screen', 'driver') =='vcsaDriver': - socketFile = '/tmp/fenrirscreenreader-deamon.sock' + if self.env['runtime']['settingsManager'].getSetting( + 'screen', 'driver') == 'vcsaDriver': + socketFile = '/tmp/fenrirscreenreader-deamon.sock' else: - socketFile = '/tmp/fenrirscreenreader-' + str(os.getppid()) + '.sock' + socketFile = '/tmp/fenrirscreenreader-' + \ + str(os.getppid()) + '.sock' if os.path.exists(socketFile): os.unlink(socketFile) self.fenrirSock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) @@ -45,27 +57,34 @@ class driver(remoteDriver): continue if self.fenrirSock in r: client_sock, client_addr = self.fenrirSock.accept() - # Ensure client socket is always closed to prevent resource leaks + # Ensure client socket is always closed to prevent resource + # leaks try: try: rawdata = client_sock.recv(8129) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('unixDriver watchDog: Error receiving data from client: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'unixDriver watchDog: Error receiving data from client: ' + str(e), + debug.debugLevel.ERROR) rawdata = b'' # Set default empty data if recv fails - + try: data = rawdata.decode("utf-8").rstrip().lstrip() - eventQueue.put({"Type":fenrirEventType.RemoteIncomming, - "Data": data - }) + eventQueue.put({"Type": fenrirEventType.RemoteIncomming, + "Data": data + }) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('unixDriver watchDog: Error decoding/queuing data: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'unixDriver watchDog: Error decoding/queuing data: ' + str(e), + debug.debugLevel.ERROR) finally: # Always close client socket, even if data processing fails try: client_sock.close() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('unixDriver watchDog: Error closing client socket: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'unixDriver watchDog: Error closing client socket: ' + str(e), + debug.debugLevel.ERROR) if self.fenrirSock: self.fenrirSock.close() self.fenrirSock = None diff --git a/src/fenrirscreenreader/screenDriver/dummyDriver.py b/src/fenrirscreenreader/screenDriver/dummyDriver.py index b671a0aa..21fda06b 100644 --- a/src/fenrirscreenreader/screenDriver/dummyDriver.py +++ b/src/fenrirscreenreader/screenDriver/dummyDriver.py @@ -7,6 +7,7 @@ from fenrirscreenreader.core import debug from fenrirscreenreader.core.screenDriver import screenDriver + class driver(screenDriver): def __init__(self): screenDriver.__init__(self) diff --git a/src/fenrirscreenreader/screenDriver/ptyDriver.py b/src/fenrirscreenreader/screenDriver/ptyDriver.py index 8bf541e5..12c3f216 100644 --- a/src/fenrirscreenreader/screenDriver/ptyDriver.py +++ b/src/fenrirscreenreader/screenDriver/ptyDriver.py @@ -4,7 +4,18 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. -import os, struct, sys, pty, tty, termios, shlex, signal, pyte, time, fcntl ,getpass +import os +import struct +import sys +import pty +import tty +import termios +import shlex +import signal +import pyte +import time +import fcntl +import getpass from select import select from fenrirscreenreader.core import debug from fenrirscreenreader.core.eventData import fenrirEventType @@ -17,6 +28,7 @@ class fenrirScreen(pyte.Screen): kwargs.pop("private", None) super(fenrirScreen, self).set_margins(*args, **kwargs) + class Terminal: def __init__(self, columns, lines, p_in): self.text = '' @@ -26,56 +38,75 @@ class Terminal: lambda data: p_in.write(data.encode()) self.stream = pyte.ByteStream() self.stream.attach(self.screen) + def feed(self, data): self.stream.feed(data) - def updateAttributes(self, initialize = False): + def updateAttributes(self, initialize=False): buffer = self.screen.buffer lines = None if not initialize: lines = self.screen.dirty else: lines = range(self.screen.lines) - self.attributes = [[list(attribute[1:]) + [False, 'default', 'default'] for attribute in line.values()] for line in buffer.values()] + self.attributes = [[list(attribute[1:]) + [False, 'default', 'default'] + for attribute in line.values()] for line in buffer.values()] for y in lines: try: t = self.attributes[y] except Exception as e: - # Terminal class doesn't have access to env, use fallback logging - print(f'ptyDriver Terminal updateAttributes: Error accessing attributes: {e}') + # Terminal class doesn't have access to env, use fallback + # logging + print( + f'ptyDriver Terminal updateAttributes: Error accessing attributes: {e}') self.attributes.append([]) - self.attributes[y] = [list(attribute[1:]) + [False, 'default', 'default'] for attribute in (buffer[y].values())] + self.attributes[y] = [list( + attribute[1:]) + [False, 'default', 'default'] for attribute in (buffer[y].values())] if len(self.attributes[y]) < self.screen.columns: diff = self.screen.columns - len(self.attributes[y]) - self.attributes[y] += [['default', 'default', False, False, False, False, False, False, 'default', 'default']] * diff + self.attributes[y] += [['default', + 'default', + False, + False, + False, + False, + False, + False, + 'default', + 'default']] * diff def resize(self, lines, columns): self.screen.resize(lines, columns) self.setCursor() self.updateAttributes(True) - def setCursor(self, x = -1, y = -1): + + def setCursor(self, x=-1, y=-1): xPos = x yPos = y if xPos == -1: xPos = self.screen.cursor.x if yPos == -1: yPos = self.screen.cursor.y - self.screen.cursor.x = min(self.screen.cursor.x, self.screen.columns - 1) + self.screen.cursor.x = min( + self.screen.cursor.x, + self.screen.columns - 1) self.screen.cursor.y = min(self.screen.cursor.y, self.screen.lines - 1) + def GetScreenContent(self): cursor = self.screen.cursor self.text = '\n'.join(self.screen.display) - self.updateAttributes(self.attributes == None) + self.updateAttributes(self.attributes is None) self.screen.dirty.clear() return {"cursor": (cursor.x, cursor.y), - 'lines': self.screen.lines, - 'columns': self.screen.columns, - "text": self.text, - 'attributes': self.attributes.copy(), - 'screen': 'pty', - 'screenUpdateTime': time.time(), - }.copy() + 'lines': self.screen.lines, + 'columns': self.screen.columns, + "text": self.text, + 'attributes': self.attributes.copy(), + 'screen': 'pty', + 'screenUpdateTime': time.time(), + }.copy() + class driver(screenDriver): def __init__(self): @@ -85,16 +116,21 @@ class driver(screenDriver): self.terminal = None self.p_pid = -1 signal.signal(signal.SIGWINCH, self.handleSigwinch) + def initialize(self, environment): self.env = environment - self.command = self.env['runtime']['settingsManager'].getSetting('general','shell') - self.shortcutType = self.env['runtime']['inputManager'].getShortcutType() - self.env['runtime']['processManager'].addCustomEventThread(self.terminalEmulation) + self.command = self.env['runtime']['settingsManager'].getSetting( + 'general', 'shell') + self.shortcutType = self.env['runtime']['inputManager'].getShortcutType( + ) + self.env['runtime']['processManager'].addCustomEventThread( + self.terminalEmulation) + def getCurrScreen(self): self.env['screen']['oldTTY'] = 'pty' self.env['screen']['newTTY'] = 'pty' - - def injectTextToScreen(self, msgBytes, screen = None): + + def injectTextToScreen(self, msgBytes, screen=None): if not screen: screen = self.p_out.fileno() if isinstance(msgBytes, str): @@ -105,8 +141,9 @@ class driver(screenDriver): self.env['screen']['autoIgnoreScreens'] = [] self.env['general']['prevUser'] = getpass.getuser() self.env['general']['currUser'] = getpass.getuser() - def readAll(self, fd, timeout = 0.3, interruptFd = None, len = 65536): - msgBytes = b'' + + def readAll(self, fd, timeout=0.3, interruptFd=None, len=65536): + msgBytes = b'' fdList = [] fdList += [fd] if interruptFd: @@ -115,7 +152,7 @@ class driver(screenDriver): while True: r = screen_utils.hasMoreWhat(fdList, 0.0001) # nothing more to read - if not fd in r: + if fd not in r: break data = os.read(fd, len) if data == b'': @@ -124,47 +161,57 @@ class driver(screenDriver): # exit on interrupt available if interruptFd in r: break - # respect timeout but wait a little bit of time to see if something more is here + # respect timeout but wait a little bit of time to see if something + # more is here if (time.time() - starttime) >= timeout: break return msgBytes + def openTerminal(self, columns, lines, command): p_pid, master_fd = pty.fork() if p_pid == 0: # Child. argv = shlex.split(command) env = os.environ.copy() - #values are VT100,xterm-256color,linux - try: + # values are VT100,xterm-256color,linux + try: if env["TERM"] == '': env["TERM"] = 'linux' except Exception as e: - # Child process doesn't have access to env, use fallback logging - print(f'ptyDriver spawnTerminal: Error checking TERM environment: {e}') + # Child process doesn't have access to env, use fallback + # logging + print( + f'ptyDriver spawnTerminal: Error checking TERM environment: {e}') env["TERM"] = 'linux' os.execvpe(argv[0], argv, env) # File-like object for I/O with the child process aka command. p_out = os.fdopen(master_fd, "w+b", 0) return Terminal(columns, lines, p_out), p_pid, p_out - def resizeTerminal(self,fd): + + def resizeTerminal(self, fd): s = struct.pack('HHHH', 0, 0, 0, 0) s = fcntl.ioctl(0, termios.TIOCGWINSZ, s) fcntl.ioctl(fd, termios.TIOCSWINSZ, s) lines, columns, _, _ = struct.unpack('hhhh', s) return lines, columns + def getTerminalSize(self, fd): s = struct.pack('HHHH', 0, 0, 0, 0) - lines, columns, _, _ = struct.unpack('HHHH', fcntl.ioctl(fd, termios.TIOCGWINSZ, s)) + lines, columns, _, _ = struct.unpack( + 'HHHH', fcntl.ioctl(fd, termios.TIOCGWINSZ, s)) return lines, columns + def handleSigwinch(self, *args): os.write(self.signalPipe[1], b'w') - def terminalEmulation(self,active , eventQueue): + + def terminalEmulation(self, active, eventQueue): try: old_attr = termios.tcgetattr(sys.stdin) tty.setraw(0) lines, columns = self.getTerminalSize(0) if self.command == '': self.command = screen_utils.getShell() - self.terminal, self.p_pid, self.p_out = self.openTerminal(columns, lines, self.command) + self.terminal, self.p_pid, self.p_out = self.openTerminal( + columns, lines, self.command) lines, columns = self.resizeTerminal(self.p_out) self.terminal.resize(lines, columns) fdList = [sys.stdin, self.p_out, self.signalPipe[0]] @@ -183,41 +230,53 @@ class driver(screenDriver): try: msgBytes = self.readAll(sys.stdin.fileno(), len=4096) except (EOFError, OSError): - eventQueue.put({"Type":fenrirEventType.StopMainLoop,"Data":None}) + eventQueue.put( + {"Type": fenrirEventType.StopMainLoop, "Data": None}) break if self.shortcutType == 'KEY': try: self.injectTextToScreen(msgBytes) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('ptyDriver getInputData: Error injecting text to screen: ' + str(e), debug.debugLevel.ERROR) - eventQueue.put({"Type":fenrirEventType.StopMainLoop,"Data":None}) + self.env['runtime']['debug'].writeDebugOut( + 'ptyDriver getInputData: Error injecting text to screen: ' + str(e), + debug.debugLevel.ERROR) + eventQueue.put( + {"Type": fenrirEventType.StopMainLoop, "Data": None}) break else: - eventQueue.put({"Type":fenrirEventType.ByteInput, - "Data":msgBytes }) + eventQueue.put({"Type": fenrirEventType.ByteInput, + "Data": msgBytes}) # output if self.p_out in r: try: - msgBytes = self.readAll(self.p_out.fileno(), interruptFd=sys.stdin.fileno()) + msgBytes = self.readAll( + self.p_out.fileno(), interruptFd=sys.stdin.fileno()) except (EOFError, OSError): - eventQueue.put({"Type":fenrirEventType.StopMainLoop,"Data":None}) + eventQueue.put( + {"Type": fenrirEventType.StopMainLoop, "Data": None}) break # feed and send event bevore write, the pyte already has the right state - # so fenrir already can progress bevore os.write what should give some better reaction time + # so fenrir already can progress bevore os.write what + # should give some better reaction time self.terminal.feed(msgBytes) - eventQueue.put({"Type":fenrirEventType.ScreenUpdate, - "Data":screen_utils.createScreenEventData(self.terminal.GetScreenContent()) - }) - self.injectTextToScreen(msgBytes, screen=sys.stdout.fileno()) + eventQueue.put( + { + "Type": fenrirEventType.ScreenUpdate, + "Data": screen_utils.createScreenEventData( + self.terminal.GetScreenContent())}) + self.injectTextToScreen( + msgBytes, screen=sys.stdout.fileno()) except Exception as e: # Process died? print(e) - eventQueue.put({"Type":fenrirEventType.StopMainLoop,"Data":None}) + eventQueue.put( + {"Type": fenrirEventType.StopMainLoop, "Data": None}) finally: os.kill(self.p_pid, signal.SIGTERM) self.p_out.close() termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_attr) - eventQueue.put({"Type":fenrirEventType.StopMainLoop,"Data":None}) + eventQueue.put( + {"Type": fenrirEventType.StopMainLoop, "Data": None}) sys.exit(0) - + def getCurrApplication(self): pass diff --git a/src/fenrirscreenreader/screenDriver/vcsaDriver.py b/src/fenrirscreenreader/screenDriver/vcsaDriver.py index 351f293a..0d07f12f 100644 --- a/src/fenrirscreenreader/screenDriver/vcsaDriver.py +++ b/src/fenrirscreenreader/screenDriver/vcsaDriver.py @@ -3,15 +3,16 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. -#attrib: -#http://rampex.ihep.su/Linux/linux_howto/html/tutorials/mini/Colour-ls-6.html -#0 = black, 1 = blue, 2 = green, 3 = cyan, 4 = red, 5 = purple, 6 = brown/yellow, 7 = white. -#https://github.com/jwilk/vcsapeek/blob/master/linuxvt.py -#blink = 5 if attr & 1 else 0 -#bold = 1 if attr & 16 else 0 +# attrib: +# http://rampex.ihep.su/Linux/linux_howto/html/tutorials/mini/Colour-ls-6.html +# 0 = black, 1 = blue, 2 = green, 3 = cyan, 4 = red, 5 = purple, 6 = brown/yellow, 7 = white. +# https://github.com/jwilk/vcsapeek/blob/master/linuxvt.py +# blink = 5 if attr & 1 else 0 +# bold = 1 if attr & 16 else 0 import subprocess -import glob, os +import glob +import os import termios import time import select @@ -25,46 +26,78 @@ from fenrirscreenreader.core.eventData import fenrirEventType from fenrirscreenreader.core.screenDriver import screenDriver from fenrirscreenreader.utils import screen_utils + class driver(screenDriver): def __init__(self): screenDriver.__init__(self) self.ListSessions = None self.sysBus = None self.charmap = {} - self.bgColorValues = {0: 'black', 1: 'blue', 2: 'green', 3: 'cyan', 4: 'red', 5: 'magenta', 6: 'brown/yellow', 7: 'white'} - self.fgColorValues = {0: 'black', 1: 'blue', 2: 'green', 3: 'cyan', 4: 'red', 5: 'magenta', 6: 'brown/yellow', 7: 'light gray', 8: 'dark gray', 9: 'light blue', 10: 'light green', 11: 'light cyan', 12: 'light red', 13: 'light magenta', 14: 'light yellow', 15: 'white'} + self.bgColorValues = { + 0: 'black', + 1: 'blue', + 2: 'green', + 3: 'cyan', + 4: 'red', + 5: 'magenta', + 6: 'brown/yellow', + 7: 'white'} + self.fgColorValues = { + 0: 'black', + 1: 'blue', + 2: 'green', + 3: 'cyan', + 4: 'red', + 5: 'magenta', + 6: 'brown/yellow', + 7: 'light gray', + 8: 'dark gray', + 9: 'light blue', + 10: 'light green', + 11: 'light cyan', + 12: 'light red', + 13: 'light magenta', + 14: 'light yellow', + 15: 'white'} self.hichar = None try: # set workaround for paste clipboard -> injectTextToScreen - subprocess.run(['sysctl', 'dev.tty.legacy_tiocsti=1'], - check=False, capture_output=True, timeout=5) + subprocess.run(['sysctl', 'dev.tty.legacy_tiocsti=1'], + check=False, capture_output=True, timeout=5) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vcsaDriver shutdown: Error running fgconsole: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'vcsaDriver shutdown: Error running fgconsole: ' + str(e), + debug.debugLevel.ERROR) + def initialize(self, environment): self.env = environment self.env['runtime']['attributeManager'].appendDefaultAttributes([ - self.fgColorValues[7], # fg - self.bgColorValues[0], # bg - False, # bold - False, # italics - False, # underscore - False, # strikethrough - False, # reverse - False, # blink - 'default', # fontsize - 'default' # fontfamily - ]) #end attribute ) - self.env['runtime']['processManager'].addCustomEventThread(self.updateWatchdog, multiprocess=True) + self.fgColorValues[7], # fg + self.bgColorValues[0], # bg + False, # bold + False, # italics + False, # underscore + False, # strikethrough + False, # reverse + False, # blink + 'default', # fontsize + 'default' # fontfamily + ]) # end attribute ) + self.env['runtime']['processManager'].addCustomEventThread( + self.updateWatchdog, multiprocess=True) + def getCurrScreen(self): self.env['screen']['oldTTY'] = self.env['screen']['newTTY'] try: - with open('/sys/devices/virtual/tty/tty0/active','r') as currScreenFile: + with open('/sys/devices/virtual/tty/tty0/active', 'r') as currScreenFile: self.env['screen']['newTTY'] = str(currScreenFile.read()[3:-1]) except Exception as e: - self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR) - def injectTextToScreen(self, text, screen = None): + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) + + def injectTextToScreen(self, text, screen=None): useScreen = "/dev/tty" + self.env['screen']['newTTY'] - if screen != None: + if screen is not None: useScreen = screen with open(useScreen, 'w') as fd: for c in text: @@ -75,38 +108,48 @@ class driver(screenDriver): try: if not self.sysBus: self.sysBus = dbus.SystemBus() - obj = self.sysBus.get_object('org.freedesktop.login1', '/org/freedesktop/login1') + obj = self.sysBus.get_object( + 'org.freedesktop.login1', '/org/freedesktop/login1') inf = dbus.Interface(obj, 'org.freedesktop.login1.Manager') self.ListSessions = inf.get_dbus_method('ListSessions') sessions = self.ListSessions() for session in sessions: - obj = self.sysBus.get_object('org.freedesktop.login1', session[4]) + obj = self.sysBus.get_object( + 'org.freedesktop.login1', session[4]) inf = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') sessionType = inf.Get('org.freedesktop.login1.Session', 'Type') screen = str(inf.Get('org.freedesktop.login1.Session', 'VTNr')) - if screen == '': - screen = str(inf.Get('org.freedesktop.login1.Session', 'TTY')) + if screen == '': + screen = str( + inf.Get( + 'org.freedesktop.login1.Session', + 'TTY')) screen = screen[screen.upper().find('TTY') + 3:] if screen == '': - self.env['runtime']['debug'].writeDebugOut('No TTY found for session:' + session[4],debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'No TTY found for session:' + session[4], debug.debugLevel.ERROR) return if sessionType.upper() != 'TTY': self.env['screen']['autoIgnoreScreens'] += [screen] - if screen == self.env['screen']['newTTY'] : + if screen == self.env['screen']['newTTY']: if self.env['general']['currUser'] != session[2]: self.env['general']['prevUser'] = self.env['general']['currUser'] self.env['general']['currUser'] = session[2] except Exception as e: - self.env['runtime']['debug'].writeDebugOut('getSessionInformation: Maybe no LoginD:' + str(e),debug.debugLevel.ERROR) - #self.env['runtime']['debug'].writeDebugOut('getSessionInformation:' + str(self.env['screen']['autoIgnoreScreens']) + ' ' + str(self.env['general']) ,debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'getSessionInformation: Maybe no LoginD:' + str(e), debug.debugLevel.ERROR) + # self.env['runtime']['debug'].writeDebugOut('getSessionInformation:' + str(self.env['screen']['autoIgnoreScreens']) + ' ' + str(self.env['general']) ,debug.debugLevel.INFO) + def readFile(self, file): d = b'' file.seek(0) try: d = file.read() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vcsaDriver getScreenText: Error reading file: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'vcsaDriver getScreenText: Error reading file: ' + str(e), + debug.debugLevel.ERROR) file.seek(0) while True: # Read from file @@ -117,7 +160,8 @@ class driver(screenDriver): except Exception as e: break return d - def updateWatchdog(self, active , eventQueue): + + def updateWatchdog(self, active, eventQueue): vcsa = {} vcsu = {} tty = None @@ -127,29 +171,31 @@ class driver(screenDriver): vcsaDevices = glob.glob('/dev/vcsa*') vcsuDevices = None lastScreenContent = b'' - + # Open TTY file with proper cleanup - tty = open('/sys/devices/virtual/tty/tty0/active','r') + tty = open('/sys/devices/virtual/tty/tty0/active', 'r') currScreen = str(tty.read()[3:-1]) oldScreen = currScreen - + # Open VCSA devices with proper cleanup tracking for vcsaDev in vcsaDevices: index = str(vcsaDev[9:]) - vcsa[index] = open(vcsaDev,'rb') + vcsa[index] = open(vcsaDev, 'rb') if index == currScreen: lastScreenContent = self.readFile(vcsa[index]) - + # Open VCSU devices if available if useVCSU: vcsuDevices = glob.glob('/dev/vcsu*') for vcsuDev in vcsuDevices: index = str(vcsuDev[9:]) - vcsu[index] = open(vcsuDev,'rb') - + vcsu[index] = open(vcsuDev, 'rb') + self.updateCharMap(currScreen) watchdog = select.epoll() - watchdog.register(vcsa[currScreen], select.POLLPRI | select.POLLERR) + watchdog.register( + vcsa[currScreen], + select.POLLPRI | select.POLLERR) watchdog.register(tty, select.POLLPRI | select.POLLERR) while active.value: changes = watchdog.poll(1) @@ -157,34 +203,43 @@ class driver(screenDriver): fileno = change[0] event = change[1] if fileno == tty.fileno(): - self.env['runtime']['debug'].writeDebugOut('ScreenChange',debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'ScreenChange', debug.debugLevel.INFO) tty.seek(0) currScreen = str(tty.read()[3:-1]) if currScreen != oldScreen: try: watchdog.unregister(vcsa[oldScreen]) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vcsaDriver updateWatchdog: Error unregistering watchdog: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'vcsaDriver updateWatchdog: Error unregistering watchdog: ' + str(e), + debug.debugLevel.ERROR) try: - watchdog.register(vcsa[currScreen], select.POLLPRI | select.POLLERR) + watchdog.register( + vcsa[currScreen], select.POLLPRI | select.POLLERR) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vcsaDriver updateWatchdog: Error registering watchdog: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'vcsaDriver updateWatchdog: Error registering watchdog: ' + str(e), + debug.debugLevel.ERROR) self.updateCharMap(currScreen) oldScreen = currScreen try: vcsa[currScreen].seek(0) - lastScreenContent = self.readFile(vcsa[currScreen]) + lastScreenContent = self.readFile( + vcsa[currScreen]) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vcsaDriver updateWatchdog: Error reading screen content: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'vcsaDriver updateWatchdog: Error reading screen content: ' + str(e), + debug.debugLevel.ERROR) vcsuContent = None if useVCSU: vcsu[currScreen].seek(0) vcsuContent = self.readFile(vcsu[currScreen]) - eventQueue.put({"Type":fenrirEventType.ScreenChanged, - "Data":self.createScreenEventData(currScreen, lastScreenContent, vcsuContent) - }) + eventQueue.put({"Type": fenrirEventType.ScreenChanged, "Data": self.createScreenEventData( + currScreen, lastScreenContent, vcsuContent)}) else: - self.env['runtime']['debug'].writeDebugOut('ScreenUpdate',debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'ScreenUpdate', debug.debugLevel.INFO) vcsa[currScreen].seek(0) time.sleep(0.01) dirtyContent = self.readFile(vcsa[currScreen]) @@ -196,12 +251,12 @@ class driver(screenDriver): continue if lastScreenContent == b'': lastScreenContent = screenContent - if (abs( int(screenContent[2]) - int(lastScreenContent[2])) in [1,2]) and \ - (int(screenContent[3]) == int(lastScreenContent[3])): + if (abs(int(screenContent[2]) - int(lastScreenContent[2])) in [1, 2]) and ( + int(screenContent[3]) == int(lastScreenContent[3])): # Skip X Movement pass - elif (abs( int(screenContent[3]) - int(lastScreenContent[3])) in [1]) and \ - (int(screenContent[2]) == int(lastScreenContent[2])): + elif (abs(int(screenContent[3]) - int(lastScreenContent[3])) in [1]) and \ + (int(screenContent[2]) == int(lastScreenContent[2])): # Skip Y Movement pass else: @@ -209,8 +264,8 @@ class driver(screenDriver): while True: screenContent = dirtyContent time.sleep(0.02) - #r,_,_ = select.select([vcsa[currScreen]], [], [], 0.07) - #if not vcsa[currScreen] in r: + # r,_,_ = select.select([vcsa[currScreen]], [], [], 0.07) + # if not vcsa[currScreen] in r: # break vcsa[currScreen].seek(0) dirtyContent = self.readFile(vcsa[currScreen]) @@ -223,11 +278,11 @@ class driver(screenDriver): vcsu[currScreen].seek(0) vcsuContent = self.readFile(vcsu[currScreen]) lastScreenContent = screenContent - eventQueue.put({"Type":fenrirEventType.ScreenUpdate, - "Data":self.createScreenEventData(currScreen, screenContent, vcsuContent) - }) + eventQueue.put({"Type": fenrirEventType.ScreenUpdate, "Data": self.createScreenEventData( + currScreen, screenContent, vcsuContent)}) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('VCSA:updateWatchdog:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'VCSA:updateWatchdog:' + str(e), debug.debugLevel.ERROR) time.sleep(0.2) finally: # Clean up all file handles @@ -235,51 +290,65 @@ class driver(screenDriver): if watchdog: watchdog.close() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vcsaDriver updateWatchdog: Error closing watchdog: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'vcsaDriver updateWatchdog: Error closing watchdog: ' + str(e), + debug.debugLevel.ERROR) try: if tty: tty.close() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vcsaDriver shutdown: Error closing TTY: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'vcsaDriver shutdown: Error closing TTY: ' + str(e), debug.debugLevel.ERROR) for handle in vcsa.values(): try: handle.close() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vcsaDriver shutdown: Error closing VCSA handle: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'vcsaDriver shutdown: Error closing VCSA handle: ' + str(e), + debug.debugLevel.ERROR) for handle in vcsu.values(): try: handle.close() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vcsaDriver shutdown: Error closing VCSU handle: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'vcsaDriver shutdown: Error closing VCSU handle: ' + str(e), + debug.debugLevel.ERROR) - def createScreenEventData(self, screen, vcsaContent, vcsuContent = None): + def createScreenEventData(self, screen, vcsaContent, vcsuContent=None): eventData = { 'bytes': vcsaContent, - 'lines': int( vcsaContent[0]), - 'columns': int( vcsaContent[1]), - 'textCursor': + 'lines': int(vcsaContent[0]), + 'columns': int(vcsaContent[1]), + 'textCursor': { - 'x': int( vcsaContent[2]), - 'y': int( vcsaContent[3]) - }, + 'x': int(vcsaContent[2]), + 'y': int(vcsaContent[3]) + }, 'screen': screen, 'screenUpdateTime': time.time(), 'text': '', 'attributes': [], } try: - eventData['text'], eventData['attributes'] =\ - self.autoDecodeVCSA(vcsaContent[4:], eventData['lines'], eventData['columns']) + eventData['text'], eventData['attributes'] = self.autoDecodeVCSA( + vcsaContent[4:], eventData['lines'], eventData['columns']) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vcsaDriver createScreenEventData: Error decoding VCSA content: ' + str(e), debug.debugLevel.ERROR) - # VCSU seems to give b' ' instead of b'\x00\x00\x00' (tsp), deactivated until its fixed - if vcsuContent != None: + self.env['runtime']['debug'].writeDebugOut( + 'vcsaDriver createScreenEventData: Error decoding VCSA content: ' + str(e), + debug.debugLevel.ERROR) + # VCSU seems to give b' ' instead of b'\x00\x00\x00' (tsp), + # deactivated until its fixed + if vcsuContent is not None: try: vcsuContentAsText = vcsuContent.decode('UTF-32') - eventData['text'] = screen_utils.insertNewlines(vcsuContentAsText, eventData['columns']) + eventData['text'] = screen_utils.insertNewlines( + vcsuContentAsText, eventData['columns']) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vcsaDriver createScreenEventData: Error decoding VCSU content: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'vcsaDriver createScreenEventData: Error decoding VCSU content: ' + str(e), + debug.debugLevel.ERROR) return eventData.copy() + def updateCharMap(self, screen): self.charmap = {} try: @@ -293,18 +362,23 @@ class driver(screenDriver): line = '' while True: try: - unipairs = array("H", [0]*(2*sz)) - unimapdesc = array("B", pack("@HP", sz, unipairs.buffer_info()[0])) + unipairs = array("H", [0] * (2 * sz)) + unimapdesc = array( + "B", pack( + "@HP", sz, unipairs.buffer_info()[0])) ioctl(tty.fileno(), GIO_UNIMAP, unimapdesc) break except Exception as e: - self.env['runtime']['debug'].writeDebugOut('VCSA:updateCharMap:scaling up sz=' + str(sz) + ' ' + str(e),debug.debugLevel.WARNING) + self.env['runtime']['debug'].writeDebugOut( + 'VCSA:updateCharMap:scaling up sz=' + str(sz) + ' ' + str(e), + debug.debugLevel.WARNING) sz *= 2 except Exception as e: - self.env['runtime']['debug'].writeDebugOut('VCSA:updateCharMap:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'VCSA:updateCharMap:' + str(e), debug.debugLevel.ERROR) return ncodes, = unpack_from("@H", unimapdesc) - utable = unpack_from("@%dH" % (2*ncodes), unipairs) + utable = unpack_from("@%dH" % (2 * ncodes), unipairs) for u, b in zip(utable[::2], utable[1::2]): if self.charmap.get(b) is None: self.charmap[b] = chr(u) @@ -319,26 +393,26 @@ class driver(screenDriver): blink = 0 bold = 0 ink = 7 - paper = 0 + paper = 0 for x in range(cols): data = allData[i: i + 2] i += 2 if data == b' \x07': - #attr = 7 - #ink = 7 - #paper = 0 - #ch = ' ' + # attr = 7 + # ink = 7 + # paper = 0 + # ch = ' ' charAttrib = [ - self.fgColorValues[7], # fg - self.bgColorValues[0], # bg - False, # bold - False, # italics - False, # underscore - False, # strikethrough - False, # reverse - False, # blink - 'default', # fontsize - 'default'] # fontfamily + self.fgColorValues[7], # fg + self.bgColorValues[0], # bg + False, # bold + False, # italics + False, # underscore + False, # strikethrough + False, # reverse + False, # blink + 'default', # fontsize + 'default'] # fontfamily lineAttrib.append(charAttrib) lineText += ' ' continue @@ -351,53 +425,65 @@ class driver(screenDriver): if sh & self.hichar: ch |= 0x100 except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vcsaDriver autoDecodeVCSA: Error processing character: ' + str(e), debug.debugLevel.ERROR) - ch = None + self.env['runtime']['debug'].writeDebugOut( + 'vcsaDriver autoDecodeVCSA: Error processing character: ' + str(e), + debug.debugLevel.ERROR) + ch = None if self.hichar == 0x100: attr >>= 1 ink = attr & 0x0F - paper = (attr>>4) & 0x0F - if attr & 1: + paper = (attr >> 4) & 0x0F + if attr & 1: blink = 1 # blink seems to be set always, ignore for now - blink = 0 - bold = 0 + blink = 0 + bold = 0 if attr & 16: bold = 1 - #if (ink != 7) or (paper != 0): + # if (ink != 7) or (paper != 0): # print(ink,paper) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('vcsaDriver autoDecodeVCSA: Error processing attributes: ' + str(e), debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'vcsaDriver autoDecodeVCSA: Error processing attributes: ' + str(e), + debug.debugLevel.ERROR) try: lineText += self.charmap[ch] except KeyError: lineText += '?' charAttrib = [ - self.fgColorValues[ink], - self.bgColorValues[paper], - bold == 1, # bold - False, # italics - False, # underscore - False, # strikethrough - False, # reverse - blink == 1, # blink - 'default', # fontsize - 'default'] # fontfamily + self.fgColorValues[ink], + self.bgColorValues[paper], + bold == 1, # bold + False, # italics + False, # underscore + False, # strikethrough + False, # reverse + blink == 1, # blink + 'default', # fontsize + 'default'] # fontfamily lineAttrib.append(charAttrib) allText += lineText if y + 1 < rows: allText += '\n' allAttrib.append(lineAttrib) return str(allText), allAttrib - + def getCurrApplication(self): apps = [] try: currScreen = self.env['screen']['newTTY'] - apps = subprocess.Popen('ps -t tty' + currScreen + ' -o comm,tty,stat', shell=True, stdout=subprocess.PIPE).stdout.read().decode()[:-1].split('\n') + apps = subprocess.Popen( + 'ps -t tty' + + currScreen + + ' -o comm,tty,stat', + shell=True, + stdout=subprocess.PIPE).stdout.read().decode()[ + :- + 1].split('\n') except Exception as e: - self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) return try: for i in apps: @@ -408,11 +494,12 @@ class driver(screenDriver): if '+' in i[2]: if i[0] != '': if not "GREP" == i[0] and \ - not "SH" == i[0] and \ - not "PS" == i[0]: - if "TTY"+currScreen in i[1]: + not "SH" == i[0] and \ + not "PS" == i[0]: + if "TTY" + currScreen in i[1]: if self.env['screen']['newApplication'] != i[0]: self.env['screen']['newApplication'] = i[0] return except Exception as e: - self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + str(e), debug.debugLevel.ERROR) diff --git a/src/fenrirscreenreader/soundDriver/debugDriver.py b/src/fenrirscreenreader/soundDriver/debugDriver.py index 24b44680..39728ef9 100644 --- a/src/fenrirscreenreader/soundDriver/debugDriver.py +++ b/src/fenrirscreenreader/soundDriver/debugDriver.py @@ -7,6 +7,7 @@ from fenrirscreenreader.core import debug from fenrirscreenreader.core.soundDriver import soundDriver + class driver(soundDriver): def __init__(self): soundDriver.__init__(self) @@ -23,34 +24,46 @@ class driver(soundDriver): self._initialized = False print('Sound Debug Driver: Shutdown') - def playFrequence(self, frequence, duration, adjustVolume = 0.0, interrupt=True): + def playFrequence( + self, + frequence, + duration, + adjustVolume=0.0, + interrupt=True): if not self._initialized: - return + return if interrupt: self.cancel() - print('Sound Debug Driver: playFrequence:' + ' freq:' + str(frequence) + ' duration:' + str(duration) + ' adjustVolume:' + str(adjustVolume) ) + print( + 'Sound Debug Driver: playFrequence:' + + ' freq:' + + str(frequence) + + ' duration:' + + str(duration) + + ' adjustVolume:' + + str(adjustVolume)) print('Sound Debug Driver: -----------------------------------') - def playSoundFile(self, filePath, interrupt = True): + def playSoundFile(self, filePath, interrupt=True): if not self._initialized: - return + return if interrupt: self.cancel() - print('Sound Debug Driver: playSoundFile:' + str(filePath)) + print('Sound Debug Driver: playSoundFile:' + str(filePath)) print('Sound Debug Driver: -----------------------------------') def cancel(self): if not self._initialized: return - print('Sound Debug Driver: Cancel') + print('Sound Debug Driver: Cancel') def setCallback(self, callback): if not self._initialized: return - print('Sound Debug Driver: setCallback') + print('Sound Debug Driver: setCallback') def setVolume(self, volume): if not self._initialized: - return + return self.volume = volume - print('Sound Debug Driver: setVolume:' + str(self.volume)) + print('Sound Debug Driver: setVolume:' + str(self.volume)) diff --git a/src/fenrirscreenreader/soundDriver/dummyDriver.py b/src/fenrirscreenreader/soundDriver/dummyDriver.py index 436bff89..0cf20d65 100644 --- a/src/fenrirscreenreader/soundDriver/dummyDriver.py +++ b/src/fenrirscreenreader/soundDriver/dummyDriver.py @@ -7,6 +7,7 @@ from fenrirscreenreader.core import debug from fenrirscreenreader.core.soundDriver import soundDriver + class driver(soundDriver): def __init__(self): soundDriver.__init__(self) diff --git a/src/fenrirscreenreader/soundDriver/genericDriver.py b/src/fenrirscreenreader/soundDriver/genericDriver.py index 4d8e6200..7b5ca1e6 100644 --- a/src/fenrirscreenreader/soundDriver/genericDriver.py +++ b/src/fenrirscreenreader/soundDriver/genericDriver.py @@ -9,6 +9,7 @@ import subprocess import shlex from fenrirscreenreader.core.soundDriver import soundDriver + class driver(soundDriver): def __init__(self): soundDriver.__init__(self) @@ -16,30 +17,46 @@ class driver(soundDriver): self.soundType = '' self.soundFileCommand = '' self.frequenceCommand = '' + def initialize(self, environment): self.env = environment - self.soundFileCommand = self.env['runtime']['settingsManager'].getSetting('sound', 'genericPlayFileCommand') - self.frequenceCommand = self.env['runtime']['settingsManager'].getSetting('sound', 'genericFrequencyCommand') + self.soundFileCommand = self.env['runtime']['settingsManager'].getSetting( + 'sound', 'genericPlayFileCommand') + self.frequenceCommand = self.env['runtime']['settingsManager'].getSetting( + 'sound', 'genericFrequencyCommand') if self.soundFileCommand == '': self.soundFileCommand = 'play -q -v fenrirVolume fenrirSoundFile' if self.frequenceCommand == '': self.frequenceCommand = 'play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence' self._initialized = True - def playFrequence(self, frequence, duration, adjustVolume = 0.0, interrupt=True): + def playFrequence( + self, + frequence, + duration, + adjustVolume=0.0, + interrupt=True): if not self._initialized: return if interrupt: self.cancel() popenFrequenceCommand = shlex.split(self.frequenceCommand) for idx, word in enumerate(popenFrequenceCommand): - word = word.replace('fenrirVolume', str(self.volume * adjustVolume)) + word = word.replace( + 'fenrirVolume', str( + self.volume * adjustVolume)) word = word.replace('fenrirDuration', str(duration)) word = word.replace('fenrirFrequence', str(frequence)) popenFrequenceCommand[idx] = word - self.proc = subprocess.Popen(popenFrequenceCommand, stdin=None, stdout=None, stderr=None, shell=False) + self.proc = subprocess.Popen( + popenFrequenceCommand, + stdin=None, + stdout=None, + stderr=None, + shell=False) self.soundType = 'frequence' - def playSoundFile(self, filePath, interrupt = True): + + def playSoundFile(self, filePath, interrupt=True): if not self._initialized: return if interrupt: @@ -50,11 +67,12 @@ class driver(soundDriver): return popenSoundFileCommand = shlex.split(self.soundFileCommand) for idx, word in enumerate(popenSoundFileCommand): - word = word.replace('fenrirVolume', str(self.volume )) + word = word.replace('fenrirVolume', str(self.volume)) word = word.replace('fenrirSoundFile', shlex.quote(str(filePath))) popenSoundFileCommand[idx] = word self.proc = subprocess.Popen(popenSoundFileCommand, shell=False) self.soundType = 'file' + def cancel(self): if not self._initialized: return @@ -63,7 +81,8 @@ class driver(soundDriver): if self.soundType == 'file': self.proc.kill() try: - self.proc.wait(timeout=1.0) # Wait for process to finish to prevent zombies + # Wait for process to finish to prevent zombies + self.proc.wait(timeout=1.0) except subprocess.TimeoutExpired: pass # Process already terminated except Exception as e: @@ -71,7 +90,8 @@ class driver(soundDriver): if self.soundType == 'frequence': self.proc.kill() try: - self.proc.wait(timeout=1.0) # Wait for process to finish to prevent zombies + # Wait for process to finish to prevent zombies + self.proc.wait(timeout=1.0) except subprocess.TimeoutExpired: pass # Process already terminated except Exception as e: diff --git a/src/fenrirscreenreader/soundDriver/gstreamerDriver.py b/src/fenrirscreenreader/soundDriver/gstreamerDriver.py index 42926e37..91bc35a0 100644 --- a/src/fenrirscreenreader/soundDriver/gstreamerDriver.py +++ b/src/fenrirscreenreader/soundDriver/gstreamerDriver.py @@ -5,7 +5,8 @@ # By Chrys, Storm Dragon, and contributers. from fenrirscreenreader.core import debug -import time, threading +import time +import threading from fenrirscreenreader.core.soundDriver import soundDriver _gstreamerAvailable = False @@ -19,19 +20,21 @@ except Exception as e: _gstreamerAvailable = False _availableError = str(e) + class driver(soundDriver): def __init__(self): soundDriver.__init__(self) self._source = None self._sink = None - + def initialize(self, environment): self.env = environment global _gstreamerAvailable self._initialized = _gstreamerAvailable if not self._initialized: global _availableError - self.environment['runtime']['debug'].writeDebugOut('Gstreamer not available ' + _availableError,debug.debugLevel.ERROR) + self.environment['runtime']['debug'].writeDebugOut( + 'Gstreamer not available ' + _availableError, debug.debugLevel.ERROR) return self._player = Gst.ElementFactory.make('playbin', 'player') bus = self._player.get_bus() @@ -59,28 +62,33 @@ class driver(soundDriver): self.mainloop.quit() # Wait for the GLib MainLoop thread to finish to prevent shutdown races if hasattr(self, 'thread') and self.thread.is_alive(): - self.thread.join(timeout=2.0) # 2 second timeout to prevent hanging + # 2 second timeout to prevent hanging + self.thread.join(timeout=2.0) def _onPlayerMessage(self, bus, message): if not self._initialized: - return + return if message.type == Gst.MessageType.EOS: self._player.set_state(Gst.State.NULL) elif message.type == Gst.MessageType.ERROR: self._player.set_state(Gst.State.NULL) error, info = message.parse_error() - self.env['runtime']['debug'].writeDebugOut('GSTREAMER: _onPlayerMessage'+ str(error) + str(info),debug.debugLevel.WARNING) + self.env['runtime']['debug'].writeDebugOut( + 'GSTREAMER: _onPlayerMessage' + str(error) + str(info), + debug.debugLevel.WARNING) def _onPipelineMessage(self, bus, message): if not self._initialized: - return + return if message.type == Gst.MessageType.EOS: self._pipeline.set_state(Gst.State.NULL) elif message.type == Gst.MessageType.ERROR: self._pipeline.set_state(Gst.State.NULL) error, info = message.parse_error() - self.env['runtime']['debug'].writeDebugOut('GSTREAMER: _onPipelineMessage'+ str(error) + str(info),debug.debugLevel.WARNING) - + self.env['runtime']['debug'].writeDebugOut( + 'GSTREAMER: _onPipelineMessage' + str(error) + str(info), + debug.debugLevel.WARNING) + def _onTimeout(self, element): if not self._initialized: return @@ -95,7 +103,12 @@ class driver(soundDriver): self._player.set_property('uri', 'file://%s' % fileName) self._player.set_state(Gst.State.PLAYING) - def playFrequence(self, frequence, duration, adjustVolume = 0.0, interrupt=True): + def playFrequence( + self, + frequence, + duration, + adjustVolume=0.0, + interrupt=True): if not self._initialized: return if interrupt: diff --git a/src/fenrirscreenreader/speechDriver/debugDriver.py b/src/fenrirscreenreader/speechDriver/debugDriver.py index d8b18051..8fd50f1a 100644 --- a/src/fenrirscreenreader/speechDriver/debugDriver.py +++ b/src/fenrirscreenreader/speechDriver/debugDriver.py @@ -8,26 +8,28 @@ from fenrirscreenreader.core import debug from fenrirscreenreader.core.speechDriver import speechDriver + class driver(speechDriver): def __init__(self): speechDriver.__init__(self) + def initialize(self, environment): self._isInitialized = True self.env = environment print('Speech Debug Driver: Iitialized') - + def shutdown(self): if self._isInitialized: self.cancel() self._isInitialized = False print('Speech Debug Driver: Shutdown') - def speak(self,text, queueable=True, ignorePunctuation=False): + def speak(self, text, queueable=True, ignorePunctuation=False): if not self._isInitialized: return - if not queueable: + if not queueable: self.cancel() - print('Speech Debug Driver: Speak:'+text) + print('Speech Debug Driver: Speak:' + text) print('Speech Debug Driver: -----------------------------------') def cancel(self): @@ -46,7 +48,7 @@ class driver(speechDriver): def setVoice(self, voice): if not self._isInitialized: return - print('Speech Debug Driver: setVoice:' + str(voice)) + print('Speech Debug Driver: setVoice:' + str(voice)) def setPitch(self, pitch): if not self._isInitialized: diff --git a/src/fenrirscreenreader/speechDriver/dummyDriver.py b/src/fenrirscreenreader/speechDriver/dummyDriver.py index 8860d403..c9da1f56 100644 --- a/src/fenrirscreenreader/speechDriver/dummyDriver.py +++ b/src/fenrirscreenreader/speechDriver/dummyDriver.py @@ -8,6 +8,7 @@ from fenrirscreenreader.core import debug from fenrirscreenreader.core.speechDriver import speechDriver + class driver(speechDriver): def __init__(self): speechDriver.__init__(self) diff --git a/src/fenrirscreenreader/speechDriver/genericDriver.py b/src/fenrirscreenreader/speechDriver/genericDriver.py index 2fce657a..27df449c 100644 --- a/src/fenrirscreenreader/speechDriver/genericDriver.py +++ b/src/fenrirscreenreader/speechDriver/genericDriver.py @@ -13,6 +13,7 @@ from subprocess import Popen import subprocess from fenrirscreenreader.core.speechDriver import speechDriver + class speakQueue(Queue): def clear(self): try: @@ -21,6 +22,7 @@ class speakQueue(Queue): except Empty: pass + class driver(speechDriver): def __init__(self): speechDriver.__init__(self) @@ -28,44 +30,53 @@ class driver(speechDriver): self.speechThread = Thread(target=self.worker) self.lock = Lock() self.textQueue = speakQueue() + def initialize(self, environment): - self.env = environment - self.minVolume = self.env['runtime']['settingsManager'].getSettingAsInt('speech', 'fenrirMinVolume') - self.maxVolume = self.env['runtime']['settingsManager'].getSettingAsInt('speech', 'fenrirMaxVolume') - self.minPitch = self.env['runtime']['settingsManager'].getSettingAsInt('speech', 'fenrirMinPitch') - self.maxPitch = self.env['runtime']['settingsManager'].getSettingAsInt('speech', 'fenrirMaxPitch') - self.minRate = self.env['runtime']['settingsManager'].getSettingAsInt('speech', 'fenrirMinRate') - self.maxRate = self.env['runtime']['settingsManager'].getSettingAsInt('speech', 'fenrirMaxRate') - - self.speechCommand = self.env['runtime']['settingsManager'].getSetting('speech', 'genericSpeechCommand') + self.env = environment + self.minVolume = self.env['runtime']['settingsManager'].getSettingAsInt( + 'speech', 'fenrirMinVolume') + self.maxVolume = self.env['runtime']['settingsManager'].getSettingAsInt( + 'speech', 'fenrirMaxVolume') + self.minPitch = self.env['runtime']['settingsManager'].getSettingAsInt( + 'speech', 'fenrirMinPitch') + self.maxPitch = self.env['runtime']['settingsManager'].getSettingAsInt( + 'speech', 'fenrirMaxPitch') + self.minRate = self.env['runtime']['settingsManager'].getSettingAsInt( + 'speech', 'fenrirMinRate') + self.maxRate = self.env['runtime']['settingsManager'].getSettingAsInt( + 'speech', 'fenrirMaxRate') + + self.speechCommand = self.env['runtime']['settingsManager'].getSetting( + 'speech', 'genericSpeechCommand') if self.speechCommand == '': self.speechCommand = 'espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice -- "fenrirText"' - if False: #for debugging overwrite here - #self.speechCommand = 'spd-say --wait -r 100 -i 100 "fenrirText"' + if False: # for debugging overwrite here + # self.speechCommand = 'spd-say --wait -r 100 -i 100 "fenrirText"' self.speechCommand = 'flite -t "fenrirText"' - + self._isInitialized = True if self._isInitialized: self.speechThread.start() + def shutdown(self): if not self._isInitialized: return self.cancel() self.textQueue.put(-1) - def speak(self,text, queueable=True, ignorePunctuation=False): + def speak(self, text, queueable=True, ignorePunctuation=False): if not self._isInitialized: return if not queueable: self.cancel() utterance = { - 'text': text, - 'volume': self.volume, - 'rate': self.rate, - 'pitch': self.pitch, - 'module': self.module, - 'language': self.language, - 'voice': self.voice, + 'text': text, + 'volume': self.volume, + 'rate': self.rate, + 'pitch': self.pitch, + 'module': self.module, + 'language': self.language, + 'voice': self.voice, } self.textQueue.put(utterance.copy()) @@ -86,16 +97,20 @@ class driver(speechDriver): self.proc.kill() self.proc.wait(timeout=1.0) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver:Cancel:self.proc.terminate():' + str(e),debug.debugLevel.WARNING) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver:Cancel:self.proc.terminate():' + str(e), debug.debugLevel.WARNING) try: self.proc.kill() - self.proc.wait(timeout=1.0) # Wait after kill to prevent zombies + # Wait after kill to prevent zombies + self.proc.wait(timeout=1.0) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver:Cancel:self.proc.kill():' + str(e),debug.debugLevel.WARNING) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver:Cancel:self.proc.kill():' + str(e), debug.debugLevel.WARNING) self.proc = None finally: # Ensure lock is always released, even if process termination fails self.lock.release() + def setCallback(self, callback): print('SpeechDummyDriver: setCallback') @@ -103,7 +118,7 @@ class driver(speechDriver): if not self._isInitialized: return self.textQueue.clear() - + def setVoice(self, voice): if not self._isInitialized: return @@ -112,16 +127,17 @@ class driver(speechDriver): def setPitch(self, pitch): if not self._isInitialized: return - self.pitch = str(self.minPitch + pitch * (self.maxPitch - self.minPitch )) + self.pitch = str(self.minPitch + pitch * + (self.maxPitch - self.minPitch)) def setRate(self, rate): if not self._isInitialized: return - self.rate = str(self.minRate + rate * (self.maxRate - self.minRate )) + self.rate = str(self.minRate + rate * (self.maxRate - self.minRate)) def setModule(self, module): if not self._isInitialized: - return + return self.module = str(module) def setLanguage(self, language): @@ -131,9 +147,10 @@ class driver(speechDriver): def setVolume(self, volume): if not self._isInitialized: - return - self.volume = str(self.minVolume + volume * (self.maxVolume - self.minVolume )) - + return + self.volume = str(self.minVolume + volume * + (self.maxVolume - self.minVolume)) + def worker(self): while True: utterance = self.textQueue.get() @@ -146,60 +163,69 @@ class driver(speechDriver): elif not isinstance(utterance, dict): continue # no text means nothing to speak - if not 'text' in utterance: + if 'text' not in utterance: continue - if not isinstance(utterance['text'],str): + if not isinstance(utterance['text'], str): continue if utterance['text'] == '': continue # check for valid data fields - if not 'volume' in utterance: + if 'volume' not in utterance: utterance['volume'] = '' - if not isinstance(utterance['volume'],str): + if not isinstance(utterance['volume'], str): utterance['volume'] = '' - if not 'module' in utterance: + if 'module' not in utterance: utterance['module'] = '' - if not isinstance(utterance['module'],str): + if not isinstance(utterance['module'], str): utterance['module'] = '' - if not 'language' in utterance: + if 'language' not in utterance: utterance['language'] = '' - if not isinstance(utterance['language'],str): + if not isinstance(utterance['language'], str): utterance['language'] = '' - if not 'voice' in utterance: + if 'voice' not in utterance: utterance['voice'] = '' - if not isinstance(utterance['voice'],str): + if not isinstance(utterance['voice'], str): utterance['voice'] = '' - if not 'pitch' in utterance: + if 'pitch' not in utterance: utterance['pitch'] = '' - if not isinstance(utterance['pitch'],str): + if not isinstance(utterance['pitch'], str): utterance['pitch'] = '' - if not 'rate' in utterance: + if 'rate' not in utterance: utterance['rate'] = '' - if not isinstance(utterance['rate'],str): + if not isinstance(utterance['rate'], str): utterance['rate'] = '' popenSpeechCommand = shlex.split(self.speechCommand) for idx, word in enumerate(popenSpeechCommand): - word = word.replace('fenrirVolume', str(utterance['volume'] )) + word = word.replace('fenrirVolume', str(utterance['volume'])) word = word.replace('fenrirModule', str(utterance['module'])) - word = word.replace('fenrirLanguage', str(utterance['language'])) + word = word.replace( + 'fenrirLanguage', str( + utterance['language'])) word = word.replace('fenrirVoice', str(utterance['voice'])) word = word.replace('fenrirPitch', str(utterance['pitch'])) word = word.replace('fenrirRate', str(utterance['rate'])) # Properly quote text to prevent command injection - word = word.replace('fenrirText', shlex.quote(str(utterance['text']))) + word = word.replace('fenrirText', + shlex.quote(str(utterance['text']))) popenSpeechCommand[idx] = word try: - self.env['runtime']['debug'].writeDebugOut('speechDriver:worker:' + ' '.join(popenSpeechCommand),debug.debugLevel.INFO) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver:worker:' + ' '.join(popenSpeechCommand), debug.debugLevel.INFO) self.lock.acquire(True) - self.proc = Popen(popenSpeechCommand, stdin=None, stdout=None, stderr=None, shell=False) - self.lock.release() + self.proc = Popen( + popenSpeechCommand, + stdin=None, + stdout=None, + stderr=None, + shell=False) + self.lock.release() self.proc.wait() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver:worker:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver:worker:' + str(e), debug.debugLevel.ERROR) self.lock.acquire(True) self.proc = None self.lock.release() - diff --git a/src/fenrirscreenreader/speechDriver/speechdDriver.py b/src/fenrirscreenreader/speechDriver/speechdDriver.py index 57859e05..2405a1aa 100644 --- a/src/fenrirscreenreader/speechDriver/speechdDriver.py +++ b/src/fenrirscreenreader/speechDriver/speechdDriver.py @@ -8,6 +8,7 @@ from fenrirscreenreader.core import debug from fenrirscreenreader.core.speechDriver import speechDriver + class driver(speechDriver): def __init__(self): speechDriver.__init__(self) @@ -16,22 +17,24 @@ class driver(speechDriver): self._sd = None self.env = environment self._isInitialized = False - - # Only set these if they haven't been set yet (preserve existing values) + + # Only set these if they haven't been set yet (preserve existing + # values) if not hasattr(self, 'language') or self.language is None: self.language = '' if not hasattr(self, 'voice') or self.voice is None: - self.voice = '' + self.voice = '' if not hasattr(self, 'module') or self.module is None: self.module = '' - + try: - import speechd - self._sd = speechd.SSIPClient('fenrir') + import speechd + self._sd = speechd.SSIPClient('fenrir') self._punct = speechd.PunctuationMode() self._isInitialized = True except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver initialize:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver initialize:' + str(e), debug.debugLevel.ERROR) def shutdown(self): if not self._isInitialized: @@ -43,7 +46,7 @@ class driver(speechDriver): pass self._isInitialized = False - def speak(self,text, queueable=True, ignorePunctuation=False): + def speak(self, text, queueable=True, ignorePunctuation=False): if not queueable: self.cancel() if not self._isInitialized: @@ -57,19 +60,22 @@ class driver(speechDriver): if self.module != '': self._sd.set_output_module(self.module) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver setModule:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver setModule:' + str(e), debug.debugLevel.ERROR) try: if self.language != '': self._sd.set_language(self.language) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver set_language:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver set_language:' + str(e), debug.debugLevel.ERROR) try: if self.voice != '': self._sd.set_synthesis_voice(self.voice) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver setVoice:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver setVoice:' + str(e), debug.debugLevel.ERROR) try: if ignorePunctuation: @@ -77,12 +83,14 @@ class driver(speechDriver): else: self._sd.set_punctuation(self._punct.NONE) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver set_punctuation:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver set_punctuation:' + str(e), debug.debugLevel.ERROR) try: self._sd.speak(text) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver speak:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver speak:' + str(e), debug.debugLevel.ERROR) self._isInitialized = False def cancel(self): @@ -93,29 +101,33 @@ class driver(speechDriver): try: self._sd.cancel() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver cancel:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver cancel:' + str(e), debug.debugLevel.ERROR) self._isInitialized = False def setPitch(self, pitch): if not self._isInitialized: return try: - self._sd.set_pitch(int(-100 + pitch * 200)) + self._sd.set_pitch(int(-100 + pitch * 200)) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver setPitch:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver setPitch:' + str(e), debug.debugLevel.ERROR) def setRate(self, rate): if not self._isInitialized: - return + return try: self._sd.set_rate(int(-100 + rate * 200)) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver setRate:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver setRate:' + str(e), debug.debugLevel.ERROR) def setVolume(self, volume): if not self._isInitialized: - return + return try: self._sd.set_volume(int(-100 + volume * 200)) except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver setVolume:' + str(e),debug.debugLevel.ERROR) + self.env['runtime']['debug'].writeDebugOut( + 'speechDriver setVolume:' + str(e), debug.debugLevel.ERROR) diff --git a/src/fenrirscreenreader/utils/char_utils.py b/src/fenrirscreenreader/utils/char_utils.py index b812ffc2..b56a3ff6 100644 --- a/src/fenrirscreenreader/utils/char_utils.py +++ b/src/fenrirscreenreader/utils/char_utils.py @@ -6,14 +6,15 @@ from fenrirscreenreader.core import debug -def getPrevChar(currX,currY, currText): - lineBreak = False + +def getPrevChar(currX, currY, currText): + lineBreak = False endOfScreen = False if currText == '': return -1, -1, '', endOfScreen, lineBreak - wrappedLines = currText.split('\n') + wrappedLines = currText.split('\n') x = currX - y = currY + y = currY if x - 1 < 0: if y - 1 >= 0: y -= 1 @@ -26,63 +27,68 @@ def getPrevChar(currX,currY, currText): x -= 1 currChar = '' if not endOfScreen: - currChar = wrappedLines[y][x] + currChar = wrappedLines[y][x] return x, y, currChar, endOfScreen, lineBreak -def getCurrentChar(currX,currY, currText): + +def getCurrentChar(currX, currY, currText): if currText == '': return -1, -1, '' - wrappedLines = currText.split('\n') + wrappedLines = currText.split('\n') currChar = wrappedLines[currY][currX] return currX, currY, currChar -def getUpChar(currX,currY, currText): + +def getUpChar(currX, currY, currText): endOfScreen = False if currText == '': return -1, -1, '', endOfScreen - wrappedLines = currText.split('\n') + wrappedLines = currText.split('\n') currY -= 1 if currY < 0: - currY = 0 + currY = 0 else: - endOfScreen = True + endOfScreen = True currChar = '' if not endOfScreen: currChar = wrappedLines[currY][currX] return currX, currY, currChar, endOfScreen -def getDownChar(currX,currY, currText): + +def getDownChar(currX, currY, currText): endOfScreen = False if currText == '': return -1, -1, '', endOfScreen - wrappedLines = currText.split('\n') + wrappedLines = currText.split('\n') currY += 1 if currY >= len(wrappedLines): - currY = len(wrappedLines) -1 + currY = len(wrappedLines) - 1 else: - endOfScreen = True + endOfScreen = True currChar = '' if not endOfScreen: - currChar = wrappedLines[currY][currX] + currChar = wrappedLines[currY][currX] return currX, currY, currChar, endOfScreen + def getLastCharInLine(currY, currText): - endOfScreen = False + endOfScreen = False if currText == '': return -1, -1, '' - wrappedLines = currText.split('\n') - currX = len(wrappedLines[currY].rstrip())-1 + wrappedLines = currText.split('\n') + currX = len(wrappedLines[currY].rstrip()) - 1 if currX < 0: currX = 0 currChar = wrappedLines[currY][currX] return currX, currY, currChar -def getNextChar(currX,currY, currText): - lineBreak = False - endOfScreen = False + +def getNextChar(currX, currY, currText): + lineBreak = False + endOfScreen = False if currText == '': return -1, -1, '', endOfScreen, lineBreak - wrappedLines = currText.split('\n') + wrappedLines = currText.split('\n') x = currX y = currY if x + 1 == len(wrappedLines[y]): @@ -91,26 +97,27 @@ def getNextChar(currX,currY, currText): x = 0 lineBreak = True else: - lineBreak = False + lineBreak = False endOfScreen = True else: - x += 1 + x += 1 currChar = '' if not endOfScreen: - currChar = wrappedLines[y][x] + currChar = wrappedLines[y][x] return x, y, currChar, endOfScreen, lineBreak + def getPhonetic(currChar): if len(currChar) != 1: return currChar phoneticsDict = { - "A":"alpha", "B":"bravo", "C":"charlie", "D":"delta", "E":"echo", - "F":"foxtrot", "G":"golf", "H":"hotel", "I":"india", "J":"juliet", - "K":"kilo", "L":"lima", "M":"mike", "N":"november", "O":"oscar", - "P":"papa", "Q":"quebec", "R":"romeo", "S":"sierra", "T":"tango", - "U":"uniform", "V":"victor", "W":"whisky", "X":"x ray", - "Y":"yankee", "Z":"zulu" + "A": "alpha", "B": "bravo", "C": "charlie", "D": "delta", "E": "echo", + "F": "foxtrot", "G": "golf", "H": "hotel", "I": "india", "J": "juliet", + "K": "kilo", "L": "lima", "M": "mike", "N": "november", "O": "oscar", + "P": "papa", "Q": "quebec", "R": "romeo", "S": "sierra", "T": "tango", + "U": "uniform", "V": "victor", "W": "whisky", "X": "x ray", + "Y": "yankee", "Z": "zulu" } try: phonChar = phoneticsDict[currChar.upper()] @@ -121,14 +128,25 @@ def getPhonetic(currChar): # Utility function, no env access - return fallback return currChar -def presentCharForReview(env, char, interrupt=True, announceCapital=True, flush=False): + +def presentCharForReview( + env, + char, + interrupt=True, + announceCapital=True, + flush=False): """Present a character for explicit review commands only""" if char == ' ': if ' ' in env['punctuation']['PUNCTDICT']: announceChar = env['punctuation']['PUNCTDICT'][' '] else: announceChar = 'space' - env['runtime']['outputManager'].presentText(announceChar, interrupt=interrupt, flush=flush) + env['runtime']['outputManager'].presentText( + announceChar, interrupt=interrupt, flush=flush) else: - env['runtime']['outputManager'].presentText(char, interrupt=interrupt, ignorePunctuation=True, announceCapital=announceCapital, flush=flush) - + env['runtime']['outputManager'].presentText( + char, + interrupt=interrupt, + ignorePunctuation=True, + announceCapital=announceCapital, + flush=flush) diff --git a/src/fenrirscreenreader/utils/fenrir-config.py b/src/fenrirscreenreader/utils/fenrir-config.py index 97d1087f..ecb9817e 100644 --- a/src/fenrirscreenreader/utils/fenrir-config.py +++ b/src/fenrirscreenreader/utils/fenrir-config.py @@ -17,7 +17,6 @@ elif os.geteuid() == 0: else: # Use local settings configPath = BaseDirectory.xdg_data_home + "/fenrir" - if not os.path.exists(configPath): os.makedirs(configPath) + if not os.path.exists(configPath): + os.makedirs(configPath) configPath = configPath + "/fenrir.conf" - - diff --git a/src/fenrirscreenreader/utils/line_utils.py b/src/fenrirscreenreader/utils/line_utils.py index a18caaa7..a9f24b27 100644 --- a/src/fenrirscreenreader/utils/line_utils.py +++ b/src/fenrirscreenreader/utils/line_utils.py @@ -6,13 +6,14 @@ from fenrirscreenreader.core import debug -def getPrevLine(currX,currY, currText): + +def getPrevLine(currX, currY, currText): endOfScreen = False if currText == '': return -1, -1, '', endOfScreen wrappedLines = currText.split('\n') x = currX - y = currY + y = currY if y - 1 >= 0: y -= 1 else: @@ -23,7 +24,8 @@ def getPrevLine(currX,currY, currText): currLine = wrappedLines[y] return x, y, currLine, endOfScreen -def getCurrentLine(currX,currY, currText): + +def getCurrentLine(currX, currY, currText): if currText == '': return -1, -1, '' wrappedLines = currText.split('\n') @@ -33,7 +35,8 @@ def getCurrentLine(currX,currY, currText): currLine = wrappedLines[y] return x, y, currLine -def getNextLine(currX,currY, currText): + +def getNextLine(currX, currY, currText): endOfScreen = False if currText == '': return -1, -1, '', endOfScreen @@ -47,5 +50,5 @@ def getNextLine(currX,currY, currText): x = currX currLine = '' if not endOfScreen: - currLine = wrappedLines[y] + currLine = wrappedLines[y] return x, y, currLine, endOfScreen diff --git a/src/fenrirscreenreader/utils/mark_utils.py b/src/fenrirscreenreader/utils/mark_utils.py index c2de1f9a..00da2bae 100644 --- a/src/fenrirscreenreader/utils/mark_utils.py +++ b/src/fenrirscreenreader/utils/mark_utils.py @@ -6,28 +6,30 @@ from fenrirscreenreader.core import debug + def getTextBetweenMarks(firstMark, secondMark, inText): - if inText == None: + if inText is None: return '' if not isinstance(inText, list): inText = inText.split('\n') if len(inText) < 1: - return '' - if firstMark == None: return '' - if secondMark == None: - return '' - if (firstMark['y'] + 1) * (firstMark['x'] + 1) <= (secondMark['y'] + 1) * (secondMark['x'] + 1): + if firstMark is None: + return '' + if secondMark is None: + return '' + if (firstMark['y'] + 1) * (firstMark['x'] + + 1) <= (secondMark['y'] + 1) * (secondMark['x'] + 1): startMark = firstMark.copy() endMark = secondMark.copy() else: endMark = firstMark.copy() - startMark = secondMark.copy() + startMark = secondMark.copy() textPart = '' if startMark['y'] == endMark['y']: textPart += inText[startMark['y']][startMark['x']:endMark['x'] + 1] else: - currY = startMark['y'] + currY = startMark['y'] while currY <= endMark['y']: if currY < endMark['y']: if currY == startMark['y']: @@ -35,7 +37,7 @@ def getTextBetweenMarks(firstMark, secondMark, inText): else: textPart += inText[currY] if len(inText[currY].strip()) != 0: - if len(textPart) - len(textPart.rstrip()) > 0: + if len(textPart) - len(textPart.rstrip()) > 0: textPart = textPart[:len(textPart.rstrip())] + "\n" else: textPart += '\n' @@ -44,17 +46,22 @@ def getTextBetweenMarks(firstMark, secondMark, inText): currY += 1 return textPart + def getTextBeforeMark(mark, inText): - if inText == None: + if inText is None: return '' - if mark == None: + if mark is None: return '' - return getTextBetweenMarks({'x':0,'y':0}, mark, inText) + return getTextBetweenMarks({'x': 0, 'y': 0}, mark, inText) + def getTextAfterMark(mark, inText): - if inText == None: + if inText is None: return '' - if mark == None: + if mark is None: return '' inText = inText.split('\n') - return getTextBetweenMarks(mark, {'x':len(inText[0])-1,'y':len(inText)-1}, inText) + return getTextBetweenMarks( + mark, { + 'x': len( + inText[0]) - 1, 'y': len(inText) - 1}, inText) diff --git a/src/fenrirscreenreader/utils/module_utils.py b/src/fenrirscreenreader/utils/module_utils.py index 08fbed86..5e7dd197 100644 --- a/src/fenrirscreenreader/utils/module_utils.py +++ b/src/fenrirscreenreader/utils/module_utils.py @@ -3,17 +3,19 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. import sys -version = sys.version[:3] # we only need major.minor version. -if version in ["3.3","3.4"]: +version = sys.version[:3] # we only need major.minor version. +if version in ["3.3", "3.4"]: from importlib.machinery import SourceFileLoader -else: # Python 3.5+, no support for python < 3.3. +else: # Python 3.5+, no support for python < 3.3. import importlib.util + def importModule(moduleName, moduleLocation): - if version in ["3.3","3.4"]: + if version in ["3.3", "3.4"]: return SourceFileLoader(moduleName, moduleLocation).load_module() else: - spec = importlib.util.spec_from_file_location(moduleName, moduleLocation) + spec = importlib.util.spec_from_file_location( + moduleName, moduleLocation) driver_mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(driver_mod) return driver_mod diff --git a/src/fenrirscreenreader/utils/review_utils.py b/src/fenrirscreenreader/utils/review_utils.py index fe1afa2f..cde145bd 100644 --- a/src/fenrirscreenreader/utils/review_utils.py +++ b/src/fenrirscreenreader/utils/review_utils.py @@ -5,4 +5,3 @@ # By Chrys, Storm Dragon, and contributers. from fenrirscreenreader.core import debug - diff --git a/src/fenrirscreenreader/utils/screen_utils.py b/src/fenrirscreenreader/utils/screen_utils.py index 1fb34fc3..94cbd50e 100644 --- a/src/fenrirscreenreader/utils/screen_utils.py +++ b/src/fenrirscreenreader/utils/screen_utils.py @@ -5,50 +5,63 @@ # By Chrys, Storm Dragon, and contributers. from fenrirscreenreader.core import debug -import getpass, time, string, os +import getpass +import time +import string +import os from select import select + def removeNonprintable(text): - # Get the difference of all ASCII characters from the set of printable characters - nonprintable = set([chr(i) for i in range(128)]).difference(string.printable) + # Get the difference of all ASCII characters from the set of printable + # characters + nonprintable = set([chr(i) for i in range(128)] + ).difference(string.printable) # Use translate to remove all non-printable characters - return text.translate({ord(character):None for character in nonprintable}) + return text.translate({ord(character): None for character in nonprintable}) + def insertNewlines(string, every=64): - return '\n'.join(string[i:i+every] for i in range(0, len(string), every)) + return '\n'.join(string[i:i + every] for i in range(0, len(string), every)) + def splitEvery(toSplit, every=64): - return list(toSplit[i:i+every] for i in range(0, len(toSplit), every)) + return list(toSplit[i:i + every] for i in range(0, len(toSplit), every)) + + def createScreenEventData(content): eventData = { 'bytes': content, 'lines': content['lines'], 'columns': content['columns'], - 'textCursor': + 'textCursor': { - 'x': int( content['cursor'][0]), - 'y': int( content['cursor'][1]) - }, + 'x': int(content['cursor'][0]), + 'y': int(content['cursor'][1]) + }, 'screen': content['screen'], 'text': content['text'], 'attributes': content['attributes'], 'screenUpdateTime': time.time(), } - return eventData.copy() + return eventData.copy() + def hasMore(fd, timetout=0.05): r, _, _ = select([fd], [], [], timetout) return (fd in r) + def hasMoreWhat(fdList, timetout=0.05): if not isinstance(fdList, list): - return [] + return [] elif fdList == []: return [] r, _, _ = select(fdList, [], [], timetout) return r -def isValidShell(shell = ''): + +def isValidShell(shell=''): if not isinstance(shell, str): return False if shell == '': @@ -56,7 +69,7 @@ def isValidShell(shell = ''): try: if not os.path.isfile(shell): return False - if not os.access(shell,os.X_OK): + if not os.access(shell, os.X_OK): return False except Exception as e: # Utility function, no env access - use fallback logging @@ -64,6 +77,7 @@ def isValidShell(shell = ''): return False return True + def getShell(): try: shell = os.environ["FENRIRSHELL"] @@ -71,7 +85,7 @@ def getShell(): return shell except Exception as e: # Utility function, no env access - continue silently - pass + pass try: shell = os.environ["SHELL"] if isValidShell(shell): @@ -84,8 +98,9 @@ def getShell(): with open('/etc/passwd') as f: users = f.readlines() for user in users: - (username, encrypwd, uid, gid, gecos, homedir, shell) = user.split(':') - shell = shell.replace('\n','') + (username, encrypwd, uid, gid, gecos, + homedir, shell) = user.split(':') + shell = shell.replace('\n', '') if username == getpass.getuser(): if isValidShell(shell): return shell diff --git a/src/fenrirscreenreader/utils/word_utils.py b/src/fenrirscreenreader/utils/word_utils.py index 56c02de5..87811ef2 100644 --- a/src/fenrirscreenreader/utils/word_utils.py +++ b/src/fenrirscreenreader/utils/word_utils.py @@ -7,20 +7,21 @@ from fenrirscreenreader.core import debug import string -def getCurrentWord(currX,currY, currText): - lineBreak = False + +def getCurrentWord(currX, currY, currText): + lineBreak = False endOfScreen = False if currText == '': return -1, -1, '', endOfScreen, lineBreak - if currText.strip( string.whitespace) == '': - return currX, currY, '', endOfScreen, lineBreak + if currText.strip(string.whitespace) == '': + return currX, currY, '', endOfScreen, lineBreak x = currX y = currY - currWord = '' + currWord = '' wrappedLines = currText.split('\n') currLine = wrappedLines[y] Found = False - while(not Found): + while (not Found): if not currLine[x] in string.whitespace: if x == 0: Found = True @@ -36,7 +37,7 @@ def getCurrentWord(currX,currY, currText): else: y -= 1 currLine = wrappedLines[y] - x = len( currLine) - 1 + x = len(currLine) - 1 lineBreak = True else: x -= 1 @@ -45,18 +46,20 @@ def getCurrentWord(currX,currY, currText): for d in string.whitespace: delimiterPos = currWord.find(d) if delimiterPos != -1: - currWord = currWord[:delimiterPos] + currWord = currWord[:delimiterPos] return x, y, currWord, endOfScreen, lineBreak return currX, currY, '', False, False -def getPrevWord(currX,currY, currText): - lineBreak = False + +def getPrevWord(currX, currY, currText): + lineBreak = False endOfScreen = False if currText == '': return -1, -1, '', endOfScreen, lineBreak - if currText.strip( string.whitespace) == '': - return currX, currY, '', endOfScreen, lineBreak - x, y, currWord, endOfScreen, lineBreakCurrWord = getCurrentWord(currX,currY,currText) + if currText.strip(string.whitespace) == '': + return currX, currY, '', endOfScreen, lineBreak + x, y, currWord, endOfScreen, lineBreakCurrWord = getCurrentWord( + currX, currY, currText) if endOfScreen: return x, y, currWord, endOfScreen, lineBreak wrappedLines = currText.split('\n') @@ -69,32 +72,33 @@ def getPrevWord(currX,currY, currText): else: y -= 1 currLine = wrappedLines[y] - x = len( currLine) - 1 + x = len(currLine) - 1 lineBreak = True else: x -= 1 lineBreakCurrWord = lineBreak or lineBreakCurrWord - x, y, currWord, endOfScreen, lineBreak = getCurrentWord(x,y,currText) + x, y, currWord, endOfScreen, lineBreak = getCurrentWord(x, y, currText) lineBreak = lineBreak or lineBreakCurrWord return x, y, currWord, endOfScreen, lineBreak -def getNextWord(currX,currY, currText): - lineBreak = False + +def getNextWord(currX, currY, currText): + lineBreak = False endOfScreen = False if currText == '': return -1, -1, '', endOfScreen, lineBreak - if currText.strip( string.whitespace) == '': - return currX, currY, '', endOfScreen, lineBreak + if currText.strip(string.whitespace) == '': + return currX, currY, '', endOfScreen, lineBreak x = currX y = currY - currWord = '' + currWord = '' wrappedLines = currText.split('\n') currLine = wrappedLines[y] Found = False - while(not Found): + while (not Found): if not Found: - if x + 1 > len( currLine ) - 1: - if y + 1 > len( wrappedLines ) - 1: + if x + 1 > len(currLine) - 1: + if y + 1 > len(wrappedLines) - 1: lineBreak = False endOfScreen = True return currX, currY, '', endOfScreen, lineBreak @@ -110,7 +114,7 @@ def getNextWord(currX,currY, currText): Found = True else: if currLine[x - 1] in string.whitespace: - Found = True + Found = True if Found: currWord = currLine[x:] for d in string.whitespace: @@ -119,4 +123,3 @@ def getNextWord(currX,currY, currText): currWord = currWord[:delimiterPos] return x, y, currWord, endOfScreen, lineBreak return currX, currY, '', False, False -