diff --git a/config/keyboard/desktop.conf b/config/keyboard/desktop.conf index 23fb312b..561c4754 100644 --- a/config/keyboard/desktop.conf +++ b/config/keyboard/desktop.conf @@ -126,3 +126,4 @@ KEY_FENRIR,KEY_F8=export_clipboard_to_x KEY_FENRIR,KEY_CTRL,KEY_UP=inc_alsa_volume KEY_FENRIR,KEY_CTRL,KEY_DOWN=dec_alsa_volume KEY_FENRIR,KEY_SHIFT,KEY_V=announce_fenrir_version +KEY_F4=cycle_keyboard_layout diff --git a/config/keyboard/laptop.conf b/config/keyboard/laptop.conf index 8affb134..0493eae4 100644 --- a/config/keyboard/laptop.conf +++ b/config/keyboard/laptop.conf @@ -126,3 +126,4 @@ KEY_FENRIR,KEY_F8=export_clipboard_to_x KEY_FENRIR,KEY_CTRL,KEY_UP=inc_alsa_volume KEY_FENRIR,KEY_CTRL,KEY_DOWN=dec_alsa_volume KEY_FENRIR,KEY_SHIFT,KEY_V=announce_fenrir_version +KEY_F4=cycle_keyboard_layout diff --git a/config/keyboard/nvda-desktop.conf b/config/keyboard/nvda-desktop.conf index 9a0dba35..6c98c440 100644 --- a/config/keyboard/nvda-desktop.conf +++ b/config/keyboard/nvda-desktop.conf @@ -126,3 +126,4 @@ KEY_FENRIR,KEY_CTRL,KEY_C=save_settings KEY_FENRIR,KEY_F8=export_clipboard_to_x KEY_FENRIR,KEY_ALT,KEY_UP=inc_alsa_volume KEY_FENRIR,KEY_ALT,KEY_DOWN=dec_alsa_volume +KEY_F4=cycle_keyboard_layout diff --git a/config/keyboard/nvda-laptop.conf b/config/keyboard/nvda-laptop.conf index dab8d124..abe269a0 100644 --- a/config/keyboard/nvda-laptop.conf +++ b/config/keyboard/nvda-laptop.conf @@ -126,3 +126,4 @@ KEY_FENRIR,KEY_CTRL,KEY_C=save_settings KEY_FENRIR,KEY_F8=export_clipboard_to_x KEY_FENRIR,KEY_ALT,KEY_UP=inc_alsa_volume KEY_FENRIR,KEY_ALT,KEY_DOWN=dec_alsa_volume +KEY_F4=cycle_keyboard_layout diff --git a/config/keyboard/pty.conf b/config/keyboard/pty.conf index 871bfd4b..0f2b0a60 100644 --- a/config/keyboard/pty.conf +++ b/config/keyboard/pty.conf @@ -85,3 +85,5 @@ alt+f12 - quit fenrir ^[[1;3F=temp_disable_speech # control+end - toggle auto read ^[[1;5F=toggle_auto_read +# F12 - cycle keyboard layout +^[[24~=cycle_keyboard_layout diff --git a/config/keyboard/speakup.conf b/config/keyboard/speakup.conf deleted file mode 100644 index 17d4aca0..00000000 --- a/config/keyboard/speakup.conf +++ /dev/null @@ -1,218 +0,0 @@ -# Fenrir comment: copy of speakup DefaultKeyAssignments converted to fenrir syntax -# Fenrir comment: https://android.googlesource.com/kernel/msm/+/android-7.1.0_r0.2/drivers/staging/speakup/DefaultKeyAssignments -# Fenrir comment: The insert or shift key named below is the fenrir key - -# This file is intended to give you an overview of the default keys used -# by speakup for it's review functions. You may change them to be -# anything you want but that will take some familiarity with key -# mapping. - -# We have remapped the insert or zero key on the keypad to act as a -# shift key. Well, actually as an altgr key. So in the following list -# InsKeyPad-period means hold down the insert key like a shift key and -# hit the keypad period. - -# KeyPad-8 Say current Line -KEY_KP8=review_curr_line - -# InsKeyPad-8 say from top of screen to reading cursor. -KEY_FENRIR,KEY_KP8=curr_screen_before_cursor - -# KeyPad-7 Say Previous Line (UP one line) -KEY_KP7=review_prev_line - -# KeyPad-9 Say Next Line (down one line) -KEY_KP9=review_next_line - -# KeyPad-5 Say Current Word -KEY_KP5=review_curr_word - -# InsKeyPad-5 Spell Current Word -KEY_FENRIR,KEY_KP5=review_curr_word_phonetic - -# KeyPad-4 Say Previous Word (left one word) -KEY_KP4=review_prev_word - -# InsKeyPad-4 say from left edge of line to reading cursor. -KEY_FENRIR,KEY_KP4=cursor_read_line_to_cursor - -# KeyPad-6 Say Next Word (right one word) -KEY_KP6=review_next_word - -# InsKeyPad-6 Say from reading cursor to right edge of line. -KEY_FENRIR,KEY_KP6=cursor_read_to_end_of_line - -# KeyPad-2 Say Current Letter -KEY_KP2=review_curr_char - -# InsKeyPad-2 say current letter phonetically -KEY_FENRIR,KEY_KP2=review_curr_char_phonetic - -# KeyPad-1 Say Previous Character (left one letter) -KEY_KP1=review_prev_char - -# KeyPad-3 Say Next Character (right one letter) -KEY_KP3=review_next_char - -# KeyPad-plus Say Entire Screen -KEY_KPPLUS=curr_screen - -# InsKeyPad-plus Say from reading cursor line to bottom of screen. -KEY_FENRIR,KEY_KPPLUS=curr_screen_after_cursor - -# KeyPad-Minus Park reading cursor (toggle) -# TODO - -# InsKeyPad-minus Say character hex and decimal value. -# TODO - -# KeyPad-period Say Position (current line, position and console) -KEY_KPDOT=cursor_position - -# InsKeyPad-period say colour attributes of current position. -KEY_FENRIR,KEY_KPDOT=attribute_cursor - -# InsKeyPad-9 Move reading cursor to top of screen (insert pgup) -KEY_FENRIR,KEY_KP9=review_bottom - -# InsKeyPad-3 Move reading cursor to bottom of screen (insert pgdn) -KEY_FENRIR,KEY_KP3=review_top - -# InsKeyPad-7 Move reading cursor to left edge of screen (insert home) -KEY_FENRIR,KEY_KP7=review_screen_first_char - -# InsKeyPad-1 Move reading cursor to right edge of screen (insert end) -KEY_FENRIR,KEY_KP1=review_screen_last_char - -# ControlKeyPad-1 Move reading cursor to last character on current line. -KEY_CTRL,KEY_KP1=review_line_end - -# KeyPad-Enter Shut Up (until another key is hit) and sync reading cursor -KEY_KPENTER=temp_disable_speech - -# InsKeyPad-Enter Shut Up (until toggled back on). -KEY_FENRIR,KEY_KPENTER=toggle_speech - -# InsKeyPad-star n go to line (y) or column (x). Where 'n' is any -# allowed value for the row or column for your current screen. -# TODO - -# KeyPad-/ Mark and Cut screen region. -KEY_KPSLASH=copy_marked_to_clipboard - -# InsKeyPad-/ Paste screen region into any console. -KEY_FENRIR,KEY_KPSLASH=paste_clipboard - - -# Hitting any key while speakup is outputting speech will quiet the -# synth until it has caught up with what is being printed on the -# console. - -# following by other fenrir commands -KEY_FENRIR,KEY_H=toggle_tutorial_mode -KEY_CTRL=shut_up - - -KEY_FENRIR,KEY_KP4=review_line_begin -#=review_line_end -#=review_line_first_char -#=review_line_last_char -KEY_FENRIR,KEY_ALT,KEY_1=present_first_line -KEY_FENRIR,KEY_ALT,KEY_2=present_last_line - -KEY_FENRIR,KEY_SHIFT,KEY_KP4=review_prev_word_phonetic -KEY_FENRIR,KEY_SHIFT,KEY_KP6=review_next_word_phonetic - -KEY_FENRIR,KEY_SHIFT,KEY_KP1=review_prev_char_phonetic -KEY_FENRIR,KEY_SHIFT,KEY_KP3=review_next_char_phonetic -KEY_FENRIR,KEY_CTRL,KEY_KP8=review_up -KEY_FENRIR,KEY_CTRL,KEY_KP2=review_down -#=exit_review -KEY_FENRIR,KEY_I=indent_curr_line -KEY_KPPLUS=curr_screen -#=cursor_column -#=cursor_lineno -#=braille_flush -#=braille_return_to_cursor -#=braille_pan_left -#=braille_pan_right -KEY_FENRIR,KEY_CTRL,KEY_1=clear_bookmark_1 -KEY_FENRIR,KEY_SHIFT,KEY_1=set_bookmark_1 -KEY_FENRIR,KEY_1=bookmark_1 -KEY_FENRIR,KEY_CTRL,KEY_2=clear_bookmark_2 -KEY_FENRIR,KEY_SHIFT,KEY_2=set_bookmark_2 -KEY_FENRIR,KEY_2=bookmark_2 -KEY_FENRIR,KEY_CTRL,KEY_3=clear_bookmark_3 -KEY_FENRIR,KEY_SHIFT,KEY_3=set_bookmark_3 -KEY_FENRIR,KEY_3=bookmark_3 -KEY_FENRIR,KEY_CTRL,KEY_4=clear_bookmark_4 -KEY_FENRIR,KEY_SHIFT,KEY_4=set_bookmark_4 -KEY_FENRIR,KEY_4=bookmark_4 -KEY_FENRIR,KEY_CTRL,KEY_5=clear_bookmark_5 -KEY_FENRIR,KEY_SHIFT,KEY_5=set_bookmark_5 -KEY_FENRIR,KEY_5=bookmark_5 -KEY_FENRIR,KEY_CTRL,KEY_6=clear_bookmark_6 -KEY_FENRIR,KEY_SHIFT,KEY_6=set_bookmark_6 -KEY_FENRIR,KEY_6=bookmark_6 -KEY_FENRIR,KEY_CTRL,KEY_7=clear_bookmark_7 -KEY_FENRIR,KEY_SHIFT,KEY_7=set_bookmark_7 -KEY_FENRIR,KEY_7=bookmark_7 -KEY_FENRIR,KEY_CTRL,KEY_8=clear_bookmark_8 -KEY_FENRIR,KEY_SHIFT,KEY_8=set_bookmark_8 -KEY_FENRIR,KEY_8=bookmark_8 -KEY_FENRIR,KEY_CTRL,KEY_9=clear_bookmark_9 -KEY_FENRIR,KEY_SHIFT,KEY_9=set_bookmark_9 -KEY_FENRIR,KEY_9=bookmark_9 -KEY_FENRIR,KEY_CTRL,KEY_0=clear_bookmark_10 -KEY_FENRIR,KEY_SHIFT,KEY_0=set_bookmark_10 -KEY_FENRIR,KEY_0=bookmark_10 -KEY_FENRIR,KEY_KPSLASH=set_window_application -2,KEY_FENRIR,KEY_KPSLASH=clear_window_application -#=last_incoming -KEY_FENRIR,KEY_F2=toggle_braille -KEY_FENRIR,KEY_F3=toggle_sound - -KEY_FENRIR,KEY_F9=toggle_punctuation_level -KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check -KEY_FENRIR,KEY_BACKSLASH=toggle_output -KEY_FENRIR,KEY_CTRL,KEY_E=toggle_emoticons -key_FENRIR,KEY_KPENTER=toggle_auto_read -KEY_FENRIR,KEY_CTRL,KEY_T=toggle_auto_time -KEY_FENRIR,KEY_KPASTERISK=toggle_highlight_tracking -KEY_FENRIR,KEY_KPMINUS=toggle_barrier -KEY_FENRIR,KEY_Q=quit_fenrir -KEY_FENRIR,KEY_T=time -2,KEY_FENRIR,KEY_T=date -KEY_KPSLASH=toggle_auto_indent -#=toggle_has_attribute -KEY_FENRIR,KEY_S=spell_check -2,KEY_FENRIR,KEY_S=add_word_to_spell_check -KEY_FENRIR,KEY_SHIFT,KEY_S=remove_word_from_spell_check -KEY_FENRIR,KEY_BACKSPACE=forward_keypress -KEY_FENRIR,KEY_ALT,KEY_UP=inc_sound_volume -KEY_FENRIR,KEY_ALT,KEY_DOWN=dec_sound_volume -KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_C=clear_clipboard -KEY_FENRIR,KEY_HOME=first_clipboard -KEY_FENRIR,KEY_END=last_clipboard -KEY_FENRIR,KEY_PAGEUP=prev_clipboard -KEY_FENRIR,KEY_PAGEDOWN=next_clipboard -KEY_FENRIR,KEY_SHIFT,KEY_C=curr_clipboard -KEY_FENRIR,KEY_CTRL,KEY_C=copy_last_echo_to_clipboard -KEY_FENRIR,KEY_F5=import_clipboard_from_file -KEY_FENRIR,KEY_F6=export_clipboard_to_file -KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_X=remove_marks -KEY_FENRIR,KEY_X=set_mark -KEY_FENRIR,KEY_SHIFT,KEY_X=marked_text -KEY_FENRIR,KEY_F10=toggle_vmenu_mode -KEY_FENRIR,KEY_SPACE=current_quick_menu_entry -KEY_FENRIR,KEY_CTRL,KEY_SPACE=current_quick_menu_value -KEY_FENRIR,KEY_RIGHT=next_quick_menu_entry -KEY_FENRIR,KEY_UP=next_quick_menu_value -KEY_FENRIR,KEY_LEFT=prev_quick_menu_entry -KEY_FENRIR,KEY_DOWN=prev_quick_menu_value -KEY_FENRIR,KEY_CTRL,KEY_S=save_settings -# linux specific -KEY_FENRIR,KEY_F7=import_clipboard_from_x -KEY_FENRIR,KEY_F8=export_clipboard_to_x -KEY_FENRIR,KEY_CTRL,KEY_UP=inc_alsa_volume -KEY_FENRIR,KEY_CTRL,KEY_DOWN=dec_alsa_volume diff --git a/config/punctuation/default.conf b/config/punctuation/default.conf index 66608489..ea63344e 100644 --- a/config/punctuation/default.conf +++ b/config/punctuation/default.conf @@ -4,8 +4,8 @@ # the entrys are seperated with :===: in words colon tripple equal colon ( to not collide with substitutions) [levelDict] none:===: -some:===:-$~+*-/\@#_ -most:===:.,:-$~+*-/\@!#%^&*()[]}{<>; +some:===:-$~+*-/\@# +most:===:.,:-_$~+*-/\@!#%^&*()[]}{<>; all:===:!"#$%& \'()*+,-./:;<=>?@[\\]^_`{|}~ [punctDict] diff --git a/config/punctuation/en.conf b/config/punctuation/en.conf index a75b7b62..86a44472 100644 --- a/config/punctuation/en.conf +++ b/config/punctuation/en.conf @@ -4,8 +4,8 @@ # the entrys are seperated with :===: in words colon tripple equal colon ( to not collide with substitutions) [levelDict] none:===: -some:===:-$~+*-/\@_ -most:===:.,:-$~+*-/\@!#%^&*()[]}{<>; +some:===:-$~+*-/\@ +most:===:.,:-$~+*-_/\@!#%^&*()[]}{<>; all:===:!"#$%& \'()*+,-./:;<=>?@[\\]^_`{|}~ [punctDict] diff --git a/src/fenrirscreenreader/commands/commands/cycle_keyboard_layout.py b/src/fenrirscreenreader/commands/commands/cycle_keyboard_layout.py new file mode 100644 index 00000000..7f7f977b --- /dev/null +++ b/src/fenrirscreenreader/commands/commands/cycle_keyboard_layout.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Fenrir TTY screen reader +# By Chrys, Storm Dragon, and contributers. + +from fenrirscreenreader.core import debug +import os + +class command(): + def __init__(self): + pass + def initialize(self, environment): + self.env = environment + def shutdown(self): + 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): + # Fallback to source directory + 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'): + 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') + + # Extract layout name from full path if needed + if '/' in current_layout: + 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) + next_index = (current_index + 1) % len(available_layouts) + 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) + + # Reload shortcuts with new layout + try: + self.env['runtime']['inputManager'].reloadShortcuts() + self.env['runtime']['outputManager'].presentText( + _('Switched to {} keyboard layout').format(next_layout), + interrupt=True + ) + except Exception as e: + self.env['runtime']['debug'].writeDebugOut( + "Error reloading shortcuts: " + str(e), + debug.debugLevel.ERROR + ) + self.env['runtime']['outputManager'].presentText( + _('Error switching keyboard layout'), + interrupt=True + ) + + def setCallback(self, callback): + pass \ No newline at end of file diff --git a/src/fenrirscreenreader/core/inputManager.py b/src/fenrirscreenreader/core/inputManager.py index ac993f11..ee7d6e67 100644 --- a/src/fenrirscreenreader/core/inputManager.py +++ b/src/fenrirscreenreader/core/inputManager.py @@ -389,3 +389,35 @@ class inputManager(): 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') + + # Resolve full path if needed + if not os.path.exists(layout_setting): + settingsRoot = '/etc/fenrirscreenreader/' + if not os.path.exists(settingsRoot): + 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, + onAnyLevel=True + )