diff --git a/README.md b/README.md index a029197d..d4e3942f 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,26 @@ # Fenrir + A modern, modular, flexible and fast console screenreader. It should run on any operating system. If you want to help, or write drivers to make it work on other systems, just let me know. This software is licensed under the LGPL v3. + # OS Requirements + - Linux (ptyDriver, vcsaDriver, evdevDriver) - macOS (ptyDriver) - BSD (ptyDriver) - Windows (ptyDriver) + # Core Requirements + - python3 >= 3.3 - screen, input, speech, sound or braille drivers dependencies see "Features, Drivers, Extras". + # Features, Drivers, Extras, Dependencies + # Input Drivers: 1. "evdevDriver" input driver for linux evdev - python-evdev >=0.6.3 (This is commonly referred to as python3-evdev by your distribution) @@ -25,7 +32,9 @@ This software is licensed under the LGPL v3. 2. "ptyDriver" terminal emulation input driver - python-pyte + # Screen Drivers: + 1. "vcsaDriver" screen driver for linux VCSA devices - python-dbus - Read permission to the following files and services: @@ -36,7 +45,9 @@ This software is licensed under the LGPL v3. 2. "ptyDriver" terminal emulation driver - python-pyte + # Speech Drivers: + 1. "genericDriver" (default) speech driver for sound as subprocess: - espeak or espeak-ng 2. "espeakDriver" speech driver for Espeak or Espeak-NG: @@ -47,19 +58,25 @@ This software is licensed under the LGPL v3. 4. "emacspeakDriver" speech driver for emacspeak - emacspeak + # Braille Drivers: + 1. "BrlttyDriver" braille driver (WIP): - brltty (configured and running) - python-brlapi + # Sound Drivers: + 1. "genericDriver" (default) sound driver for sound as subprocess: - Sox 2. "gstreamerDriver" sound driver for gstreamer - gstreamer >=1.0 - GLib + # Extras: + 1. spellchecker - python-pyenchant - aspell-YourLanguageCode (example aspell-en for us English) @@ -68,18 +85,29 @@ This software is licensed under the LGPL v3. 3. Modify system volume: - pyalsaaudio (needs libasound2's headers). + # installation -- Archlinux: PKGBUILD in AUR + +If there is a package for your distrobution of choice, please let us know so we can add it here. + +- Archlinux: PKGBUILD in AUR (fenrir-git recommended) - PIP: sudo pip install fenrir-screenreader - Manual: - install "espeak" and "sox" with your package manager - sudo pip install -r requirements.txt - - run install.sh and uninstall.sh as root + - run install.sh or uninstall.sh as root - you also can just run it from Git without installing: You can just run the following as root: if you are in Fenrir Git rootfolder: -cd src/fenrir/ -sudo ./fenrir + + cd src/fenrir/ + sudo ./fenrir + +Same thing, but use the daemon so the terminal is not blocked: + + cd src/fenrir/ + sudo ./fenrir-daemon + Settings "settings.conf" is located in the "config" directory or after installation in /etc/fenrir/settings. Take care to use drivers from the config matching your installed drivers. By default it uses: @@ -87,21 +115,37 @@ By default it uses: - speech driver: genericDriver (via espeak or espeak-ng, could configured in settings.conf) - braille driver: brlttyDriver (WIP) - input driver: evdevDriver + + # Configure pulseaudio -Pulseaudio by default does only play sound for the user its currently running for. As fenrir is running as root, your local user does not hear the sound and speech produced by fenrir. -for this fenrir provides a script to configure pulseaudio to stream the sound played as root to your local user. Last is playing the sound then. This is not a issue of fenrir but this is how pulseaudio works. -just run the configuration scipt twice (once as user, once as root). +Pulseaudio by default only plays sound for the user its currently running for. As fenrir is running as root, your local user does not hear the sound and speech produced by fenrir. +for this fenrir provides a script to configure pulseaudio to stream the sound played as root to your local user. This is not a issue of fenrir but this is how pulseaudio works. -Run: -configure_pulse.sh -sudo configure_pulse.sh +just run the configuration script twice (once as user, once as root): -The script could also be found at /tools/ in git + /usr/share/fenrirscreenreader/tools/configure_pulse.sh + sudo /usr/share/fenrirscreenreader/tools/configure_pulse.sh + +The script is also located in the tools directory in git + + +# Configure pipewire + +Pipewire by default only plays sound for the user its currently running for. As fenrir is running as root, your local user does not hear the sound and speech produced by fenrir. +for this fenrir provides a script to configure pipewire to stream the sound played as root to your local user. This is not a issue of fenrir but this is how pipewire works. + +just run the configuration script twice (once as user, once as root): + + /usr/share/fenrirscreenreader/tools/configure_pipewire.sh + sudo /usr/share/fenrirscreenreader/tools/configure_pipewire.sh + +The script is also located in the tools directory in git # localization copy fenrir.mo translations file from fenrir/locale/your_language/LC_MESSAGES/fenrir.mo to /usr/share/locale/your_language/LC_MESSAGES/fenrir.mo + # Documentation -You can see all information on the Wiki: -https://wiki.linux-a11y.org/doku.php?id=fenrir_user_manual + +Here is the [Fenrir Wiki](https://github.com/chrys87/fenrir/wiki). It is currently being updated, so keep checking back. Feel free to help with documentation. diff --git a/config/keyboard/desktop.conf b/config/keyboard/desktop.conf index d6c173ed..2725721e 100644 --- a/config/keyboard/desktop.conf +++ b/config/keyboard/desktop.conf @@ -32,12 +32,15 @@ KEY_FENRIR,KEY_KP5=curr_screen KEY_FENRIR,KEY_KP8=curr_screen_before_cursor KEY_FENRIR,KEY_KP2=curr_screen_after_cursor #=cursor_read_to_end_of_line +#=review_screen_last_char +#=review_screen_first_char #=cursor_column #=cursor_lineno #=braille_flush #=braille_return_to_cursor #=braille_pan_left #=braille_pan_right +#=cursor_read_line_to_cursor KEY_FENRIR,KEY_CTRL,KEY_1=clear_bookmark_1 KEY_FENRIR,KEY_SHIFT,KEY_1=set_bookmark_1 KEY_FENRIR,KEY_1=bookmark_1 diff --git a/config/keyboard/laptop.conf b/config/keyboard/laptop.conf index 0d0d73ea..91fa43ab 100644 --- a/config/keyboard/laptop.conf +++ b/config/keyboard/laptop.conf @@ -6,7 +6,7 @@ KEY_FENRIR,KEY_I=review_curr_line KEY_FENRIR,KEY_U=review_prev_line KEY_FENRIR,KEY_O=review_next_line KEY_FENRIR,KEY_SHIFT,KEY_J=review_line_begin -KEY_FENRIR,KEY_SHFIT,KEY_L=review_line_end +KEY_FENRIR,KEY_SHIFT,KEY_L=review_line_end KEY_FENRIR,KEY_CTRL,KEY_J=review_line_first_char KEY_FENRIR,KEY_CTRL,KEY_L=review_line_last_char KEY_FENRIR,KEY_ALT,KEY_1=present_first_line @@ -83,6 +83,7 @@ KEY_FENRIR,KEY_ENTER=toggle_auto_read KEY_FENRIR,KEY_CTRL,KEY_T=toggle_auto_time KEY_FENRIR,KEY_Y=toggle_highlight_tracking #=toggle_barrier +#=cursor_read_line_to_cursor KEY_FENRIR,KEY_Q=quit_fenrir KEY_FENRIR,KEY_T=time 2,KEY_FENRIR,KEY_T=date diff --git a/config/keyboard/speakup.conf b/config/keyboard/speakup.conf new file mode 100644 index 00000000..17d4aca0 --- /dev/null +++ b/config/keyboard/speakup.conf @@ -0,0 +1,218 @@ +# 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/rhvoice-en.conf b/config/punctuation/rhvoice-en.conf new file mode 100644 index 00000000..b8b13d2a --- /dev/null +++ b/config/punctuation/rhvoice-en.conf @@ -0,0 +1,78 @@ +# how to use this file? +# the # on the beginning of the line is a comment +# the different sections are seperated by [Dict] is the section name. Dict is a keyword +# the entrys are seperated with :===: in words colon tripple equal colon ( to not collide with substitutions) +[levelDict] +none:===: +some:===:-$~+*-/\@ +most:===:.,:-$~+*-/\@!#%^&*()[]}{<>; +all:===:!"#$%& \'()*+,-./:;<=>?@[\\]^_`{|}~ + +[punctDict] + :===:space +&:===:and +':===:apostrophe +@:===:at +\:===:backslash +|:===:bar +!:===:bang +^:===:carrot +::===:colon +,:===:comma +-:===:dash +$:===:dollar +.:===:dot +>:===:greater +`:===:grave +#:===:hash +{:===:left brace +[:===:left bracket +(:===:left paren +<:===:less +%:===:percent ++:===:plus +?:===:question? +":===:quote +):===:right paren +}:===:right brace +]:===:right bracket +;:===:semicolon +/:===:slash +*:===:star +~:===:tilde +_:===:line +=:===:equals + +[customDict] +regex;(?i)certificates:===:certiffikets +regex;(?i)certificate:===:certifficate +regex;(?i)lowblow:===:LowBlow +regex;(?i)nginx:===:EngineX +regex;(?i)shit:===:shitt +regex;(?i)slither:===:slitther + +[emoticonDict] +# This dictionary uses regexp when prefixed with "regex;", so be sure to escape anything that would be parsed by regexp, e.g. *, ., ^, $, etc. +regex;[\s*|'|"][\s*|'|"]<{-.-}>:===:Raves +regex;[\s*|'|"][\s*|'|"]8-\):===:smile with sunglasses +regex;[\s*|'|"][\s*|'|"]:-/:===:confused +regex;[\s*|'|"][\s*|'|"]-\.-:===:bugged +regex;[\s*|'|"][\s*|'|"]>\.<:===:laughing +regex;[\s*|'|"][\s*|'|"]8-X:===:skull +regex;[\s*|'|"][\s*|'|"]>:\):===:evil smile +regex;[\s*|'|"][\s*|'|"]>:-\):===:evil smile +regex;[\s*|'|"][\s*|'|"]\\o/:===:Hurray +regex;[\s*|'|"][\s*|'|"]:/:===:confused +regex;[\s*|'|"]:D[\s*|'|"]:===:laugh +regex;[\s*|'|"];\)[\s*|'|"]:===:wink +regex;[\s*|'|"]XD[\s*|'|"]:===:LOL +regex;[\s*|'|"]:-\)[\s*|'|"]:===:smile +regex;[\s*|'|"]:\)[\s*|'|"]:===:smile +regex;[\s*|'|"]->[\s*|'|"]:===:arrow right +# example for arrow left +#(?:[ |^])(<-)(?:[ ,.!?$]):===:arrow left +# or +#([ |^])<-([ ,.!?$]):===:arrow left\2 +regex;[\s*|'|"]<-[\s*|'|"]:===:arrow left +regex;[\s+|'|"][O|o][O|o][\s+|'|"]:===:WTF? +regex;[\s*|'|"]\^\^[\s*|'|"]:===:enjoy smile diff --git a/config/settings/espeak.settings.conf b/config/settings/espeak.settings.conf index c929283e..64d5c086 100644 --- a/config/settings/espeak.settings.conf +++ b/config/settings/espeak.settings.conf @@ -134,7 +134,10 @@ ignoreShortcuts=False # the current shortcut layout located in /etc/fenrirscreenreader/keyboard keyboardLayout=desktop # echo chars while typing. -charEcho=True +# 0 = None +# 1 = always +# 2 = only while capslock +charEchoMode=2 ## echo deleted chars charDeleteEcho=True # echo word after pressing space diff --git a/config/settings/settings-chime.conf b/config/settings/settings-chime.conf new file mode 100644 index 00000000..f796ed60 --- /dev/null +++ b/config/settings/settings-chime.conf @@ -0,0 +1,265 @@ +[sound] +# Turn sound on or off: +enabled=True + +# Select the driver used to play sounds, choices are genericDriver and gstreamerDriver. +# Sox is the default. +#driver=gstreamerDriver +driver=genericDriver + +# Sound themes. These are the pack of sounds used for sound alerts. +# Sound packs may be located at /usr/share/sounds +# For system wide availability, or ~/.local/share/fenrirscreenreader/sounds +# For the current user. +theme=default + +# Sound volume controls how loud the sounds for your selected soundpack are. +# 0 is quietest, 1.0 is loudest. +volume=1.0 + +# shell commands for generic sound driver +# the folowing variable are substituted +# fenrirVolume = the current volume setting +# fenrirSoundFile = the soundfile for an soundicon +# fenrirFrequence = the frequency to play +# fenrirDuration = the duration of the frequency +# the following command is used to play a soundfile +genericPlayFileCommand=play -q -v fenrirVolume fenrirSoundFile +#the following command is used to generate a frequency beep +genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence + +[speech] +# Turn speech on or off: +enabled=True + +# Select speech driver, options are speechdDriver (default), genericDriver or espeakDriver: +# chrys: comment out genericDriver, uncomment speechdDriver +driver=speechdDriver +#driver=espeakDriver +#driver=genericDriver + +# server path for emacspeak +serverPath=/home/chrys/Projekte/emacspeak/servers/espeak + +# The rate selects how fast Fenrir will speak. Options range from 0, slowest, to 1.0, fastest. +rate=0.65 + +# Pitch controls the pitch of the voice, select from 0, lowest, to 1.0, highest. +pitch=0.5 +# Pitch for capital letters +capitalPitch=0.9 + +# Volume controls the loudness of the voice, select from 0, quietest, to 1.0, loudest. +volume=1.0 + +# Module is used for Speech-dispatcher, to select the speech module you want to use. +# Consult Speech-dispatcher's configuration and help Fenrir find out which modules are available. +# The default is specified in speechd.conf. +# chrys: uncomment module, set it to voxin (default espeak-ng) +module=voxin + +# Voice selects the voice you want to use, for example, en-GB-scotland will use the Scotish English voice in Espeak, +# To find out which voices are available, consult the documentation provided with your selected synthesizer. +# This also sets the voice used in the generic driver. +# You can add a variant by adding +name onto the end. +# chrys: set voice (default was en-us) +voice=allison-embedded-high + +# Select the language you want Fenrir to use. +# chrys: uncomment language and set language to en-US (default was en) +language=en + +# Read new text as it happens? +autoReadIncoming=True + +# genericSpeechCommand is the command that is executed for talking +# the following variables are replaced with values +# fenrirText = is the text that should be spoken +# fenrirModule = may be the speech module like used in speech-dispatcher, not every TTY need this +# fenrirLanguage = the language +# fenrirVoice = is the current voice that should be used. Set the voice variable above. +# the current volume, pitch and rate is calculated like this +# value = min + settingValue * (min - max ) +# fenrirVolume = is replaced with the current volume +# fenrirPitch = is replaced with the current pitch +# fenrirRate = is replaced with the current speed (speech rate) +genericSpeechCommand=espeak-ng -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice -- "fenrirText" + +# those are the min and max values of the TTS system that is used in genericSpeechCommand +fenrirMinVolume=0 +fenrirMaxVolume=200 +fenrirMinPitch=0 +fenrirMaxPitch=99 +fenrirMinRate=80 +fenrirMaxRate=450 + +[braille] +enabled=False +driver=dummyDriver +layout=en +# to what should the flush timeout relate to +# word = flush after (number of words to display) * seconds +# char = flush after (number of chars to display) * seconds +# fix = flush after X seconds +# none = no automatic flush (manual via shortcut) +flushMode=word +# seconds to flush or +# -1 = no automatic flush (manual via shortcut) +flushTimeout=3 +# how should the cursor be focused? +# page = if cursor cross the border move to next page and start at beginn +# fixCell = ajust the cursor on an special cell where it is always placed. the display scroll here more smooth. +cursorFocusMode=page +# define the cell on the Braille device where fenrir should scroll and keep the cursor +# 0 = first cell on device +# -1 = last cell on device +# >0 = fix cell number +fixCursorOnCell=-1 +#How should the braille follow the focus +# none = no automatic toggle command used +# review = priority to review +# last = follow last used cursor +cursorFollowMode=review +# number of cells in panning (horizontal) +# 0 = display size, >0 number of cells +panSizeHorizontal=0 + +[screen] +driver=vcsaDriver +encoding=auto +screenUpdateDelay=0.05 +suspendingScreen= +autodetectSuspendingScreen=True + +[keyboard] +driver=evdevDriver +# filter input devices NOMICE, ALL or a DEVICE NAME +device=ALL +# gives Fenrir exclusive access to the keyboard and lets it control keystrokes. +grabDevices=True +ignoreShortcuts=False +# the current shortcut layout located in /etc/fenrirscreenreader/keyboard +keyboardLayout=desktop +# echo chars while typing. +# 0 = None +# 1 = always +# 2 = only while capslock +charEchoMode=2 +# echo deleted chars +charDeleteEcho=True +# echo word after pressing space +wordEcho=False +# interrupt speech on any keypress +interruptOnKeyPress=True +# you can filter the keys on that the speech should interrupt (empty = all keys, otherwhise the given keys) +interruptOnKeyPressFilter= +# timeout for double tap in sec +doubleTapTimeout=0.2 + +[general] +debugLevel=0 +# debugMode sets where the debug output should send to: +# debugMode=File writes to debugFile (Default:/tmp/fenrir-PID.log) +# debugMode=Print just prints on the screen +debugMode=File +debugFile= +punctuationProfile=default +punctuationLevel=some +respectPunctuationPause=True +newLinePause=True +numberOfClipboards=10 +# used path for "export_clipboard_to_file" +# $user is replaced by username +#clipboardExportPath=/home/$user/fenrirClipboard +clipboardExportPath=/tmp/fenrirClipboard +emoticons=True +# define the current Fenrir key +fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT +scriptKeys=KEY_COMPOSE +timeFormat=%H:%M:%P +dateFormat=%A, %B %d, %Y +autoSpellCheck=True +spellCheckLanguage=en_US +# path for your scripts "scriptKeys" functionality +scriptPath=/usr/share/fenrirscreenreader/scripts +# overload commands, and create new one without changing Fenrir default +commandPath= +#fenrirBGColor = the backgroundcolor +#fenrirFGColor = the foregroundcolor +#fenrirUnderline = speak the underline attribute +#fenrirBold = speak the bold attribute +#fenrirBlink = speak the blink attribute +#fenrirFont = the font +#fenrirFontSize = the fontsize +attributeFormatString=Background fenrirBGColor,Foreground fenrirFGColor,fenrirUnderline,fenrirBold,fenrirBlink, Font fenrirFont,Fontsize fenrirFontSize +# present indentation +autoPresentIndent=False +# speak is only invoked on changeing ident level, sound always +# 0 = sound and speak +# 1 = sound only +# 2 = speak only +autoPresentIndentMode=1 +# play a sound when attributes are changeing +hasAttributes=True +# shell for PTY emulatiun (empty = default shell) +shell= + +[focus] +#follow the text cursor +cursor=True +#follow highlighted text changes +highlight=False + +[remote] +enable=True +# driver +# unixDriver = unix sockets +# tcpDriver = tcp (localhost only) +driver=unixDriver +# tcp port +port=22447 +# socket filepath +socketFile= +# allow settings to overwrite +enableSettingsRemote=True +# allow commands to be executed +enableCommandRemote=True + +[barrier] +enabled=True +leftBarriers=│└┌─ +rightBarriers=│┘┐─ + +[review] +lineBreak=True +endOfScreen=True +# leave the review when pressing a key +leaveReviewOnCursorChange=True +# leave the review when changing the screen +leaveReviewOnScreenChange=True + +[promote] +enabled=True +inactiveTimeoutSec=120 +list= + +[menu] +vmenuPath= +quickMenu=speech#rate;speech#pitch;speech#volume + +[time] +# automatic time anouncement +enabled=False +# present time +presentTime=True +# present date (on change) +presentDate=True +# present time after a given period of seconds +delaySec=0 +# present time after to given minutes example every 15 minutes: 00,15,30,45 +# if delaySec is >0 onMinutes is ignored +onMinutes=00,30 +# announce via soundicon (not interrupting) +announce=True +# interrupt current speech for time announcement +interrupt=False diff --git a/config/settings/settings-daemon.conf b/config/settings/settings-daemon.conf index 67a2c140..851fd4a1 100644 --- a/config/settings/settings-daemon.conf +++ b/config/settings/settings-daemon.conf @@ -136,7 +136,10 @@ ignoreShortcuts=False # the current shortcut layout located in /etc/fenrirscreenreader/keyboard keyboardLayout=desktop # echo chars while typing. -charEcho=False +# 0 = None +# 1 = always +# 2 = only while capslock +charEchoMode=2 # echo deleted chars charDeleteEcho=True # echo word after pressing space diff --git a/config/settings/settings-pty.conf b/config/settings/settings-pty.conf index 67a2c140..851fd4a1 100644 --- a/config/settings/settings-pty.conf +++ b/config/settings/settings-pty.conf @@ -136,7 +136,10 @@ ignoreShortcuts=False # the current shortcut layout located in /etc/fenrirscreenreader/keyboard keyboardLayout=desktop # echo chars while typing. -charEcho=False +# 0 = None +# 1 = always +# 2 = only while capslock +charEchoMode=2 # echo deleted chars charDeleteEcho=True # echo word after pressing space diff --git a/config/settings/settings.conf b/config/settings/settings.conf index 31fc23c3..5985be79 100644 --- a/config/settings/settings.conf +++ b/config/settings/settings.conf @@ -137,7 +137,10 @@ ignoreShortcuts=False # the current shortcut layout located in /etc/fenrirscreenreader/keyboard keyboardLayout=desktop # echo chars while typing. -charEcho=False +# 0 = None +# 1 = always +# 2 = only while capslock +charEchoMode=1 # echo deleted chars charDeleteEcho=True # echo word after pressing space diff --git a/config/settings/settings.conf.dectalk b/config/settings/settings.conf.dectalk new file mode 100644 index 00000000..e9c065ca --- /dev/null +++ b/config/settings/settings.conf.dectalk @@ -0,0 +1,261 @@ +[sound] +# Turn sound on or off: +enabled=True + +# Select the driver used to play sounds, choices are genericDriver and gstreamerDriver. +# Sox is the default. +#driver=gstreamerDriver +driver=genericDriver + +# Sound themes. These are the pack of sounds used for sound alerts. +# Sound packs may be located at /usr/share/sounds +# For system wide availability, or ~/.local/share/fenrirscreenreader/sounds +# For the current user. +theme=default + +# Sound volume controls how loud the sounds for your selected soundpack are. +# 0 is quietest, 1.0 is loudest. +volume=1.0 + +# shell commands for generic sound driver +# the folowing variable are substituted +# fenrirVolume = the current volume setting +# fenrirSoundFile = the soundfile for an soundicon +# fenrirFrequence = the frequency to play +# fenrirDuration = the duration of the frequency +# the following command is used to play a soundfile +genericPlayFileCommand=play -q -v fenrirVolume fenrirSoundFile +#the following command is used to generate a frequency beep +genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence + +[speech] +# Turn speech on or off: +enabled=True + +# Select speech driver, options are speechdDriver (default), genericDriver or espeakDriver: +#driver=speechdDriver +#driver=espeakDriver +driver=genericDriver + +# server path for emacspeak +serverPath=/home/chrys/Projekte/emacspeak/servers/espeak + +# The rate selects how fast Fenrir will speak. Options range from 0, slowest, to 1.0, fastest. +rate=0.2 + +# Pitch controls the pitch of the voice, select from 0, lowest, to 1.0, highest. +pitch=0.5 +# Pitch for capital letters +capitalPitch=0.9 + +# Volume controls the loudness of the voice, select from 0, quietest, to 1.0, loudest. +volume=1.0 + +# Module is used for Speech-dispatcher, to select the speech module you want to use. +# Consult Speech-dispatcher's configuration and help Fenrir find out which modules are available. +# The default is specified in speechd.conf. +#module=espeak-ng + +# Voice selects the voice you want to use, for example, en-GB-scotland will use the Scotish English voice in Espeak, +# To find out which voices are available, consult the documentation provided with your selected synthesizer. +# This also sets the voice used in the generic driver. +# You can add a variant by adding +name onto the end. +voice=0 + +# Select the language you want Fenrir to use. +#language=en + +# Read new text as it happens? +autoReadIncoming=True + +# genericSpeechCommand is the command that is executed for talking +# the following variables are replaced with values +# fenrirText = is the text that should be spoken +# fenrirModule = may be the speech module like used in speech-dispatcher, not every TTY need this +# fenrirLanguage = the language +# fenrirVoice = is the current voice that should be used. Set the voice variable above. +# the current volume, pitch and rate is calculated like this +# value = min + settingValue * (min - max ) +# fenrirVolume = is replaced with the current volume +# fenrirPitch = is replaced with the current pitch +# fenrirRate = is replaced with the current speed (speech rate) +genericSpeechCommand=/opt/dectalk/say -v fenrirVolume -r fenrirRate -s fenrirVoice -a "fenrirText" + +# those are the min and max values of the TTS system that is used in genericSpeechCommand +fenrirMinVolume=0 +fenrirMaxVolume=100 +fenrirMinPitch=0 +fenrirMaxPitch=99 +fenrirMinRate=75 +fenrirMaxRate=600 + +[braille] +enabled=False +driver=dummyDriver +layout=en +# to what should the flush timeout relate to +# word = flush after (number of words to display) * seconds +# char = flush after (number of chars to display) * seconds +# fix = flush after X seconds +# none = no automatic flush (manual via shortcut) +flushMode=word +# seconds to flush or +# -1 = no automatic flush (manual via shortcut) +flushTimeout=3 +# how should the cursor be focused? +# page = if cursor cross the border move to next page and start at beginn +# fixCell = ajust the cursor on an special cell where it is always placed. the display scroll here more smooth. +cursorFocusMode=page +# define the cell on the Braille device where fenrir should scroll and keep the cursor +# 0 = first cell on device +# -1 = last cell on device +# >0 = fix cell number +fixCursorOnCell=-1 +#How should the braille follow the focus +# none = no automatic toggle command used +# review = priority to review +# last = follow last used cursor +cursorFollowMode=review +# number of cells in panning (horizontal) +# 0 = display size, >0 number of cells +panSizeHorizontal=0 + +[screen] +driver=vcsaDriver +encoding=auto +screenUpdateDelay=0.05 +suspendingScreen= +autodetectSuspendingScreen=True + +[keyboard] +driver=evdevDriver +# filter input devices NOMICE, ALL or a DEVICE NAME +device=ALL +# gives Fenrir exclusive access to the keyboard and lets it control keystrokes. +grabDevices=True +ignoreShortcuts=False +# the current shortcut layout located in /etc/fenrirscreenreader/keyboard +keyboardLayout=desktop +# echo chars while typing. +# 0 = None +# 1 = always +# 2 = only while capslock +charEchoMode=1 +# echo deleted chars +charDeleteEcho=True +# echo word after pressing space +wordEcho=False +# interrupt speech on any keypress +interruptOnKeyPress=True +# you can filter the keys on that the speech should interrupt (empty = all keys, otherwhise the given keys) +interruptOnKeyPressFilter= +# timeout for double tap in sec +doubleTapTimeout=0.2 + +[general] +debugLevel=0 +# debugMode sets where the debug output should send to: +# debugMode=File writes to debugFile (Default:/tmp/fenrir-PID.log) +# debugMode=Print just prints on the screen +debugMode=File +debugFile= +punctuationProfile=default +punctuationLevel=some +respectPunctuationPause=True +newLinePause=True +numberOfClipboards=10 +# used path for "export_clipboard_to_file" +# $user is replaced by username +#clipboardExportPath=/home/$user/fenrirClipboard +clipboardExportPath=/tmp/fenrirClipboard +emoticons=True +# define the current Fenrir key +fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT +scriptKeys=KEY_COMPOSE +timeFormat=%H:%M:%P +dateFormat=%A, %B %d, %Y +autoSpellCheck=True +spellCheckLanguage=en_US +# path for your scripts "scriptKeys" functionality +scriptPath=/usr/share/fenrirscreenreader/scripts +# overload commands, and create new one without changing Fenrir default +commandPath= +#fenrirBGColor = the backgroundcolor +#fenrirFGColor = the foregroundcolor +#fenrirUnderline = speak the underline attribute +#fenrirBold = speak the bold attribute +#fenrirBlink = speak the blink attribute +#fenrirFont = the font +#fenrirFontSize = the fontsize +attributeFormatString=Background fenrirBGColor,Foreground fenrirFGColor,fenrirUnderline,fenrirBold,fenrirBlink, Font fenrirFont,Fontsize fenrirFontSize +# present indentation +autoPresentIndent=False +# speak is only invoked on changeing ident level, sound always +# 0 = sound and speak +# 1 = sound only +# 2 = speak only +autoPresentIndentMode=1 +# play a sound when attributes are changeing +hasAttributes=True +# shell for PTY emulatiun (empty = default shell) +shell= + +[focus] +#follow the text cursor +cursor=True +#follow highlighted text changes +highlight=False + +[remote] +enable=True +# driver +# unixDriver = unix sockets +# tcpDriver = tcp (localhost only) +driver=unixDriver +# tcp port +port=22447 +# socket filepath +socketFile= +# allow settings to overwrite +enableSettingsRemote=True +# allow commands to be executed +enableCommandRemote=True + +[barrier] +enabled=True +leftBarriers=│└┌─ +rightBarriers=│┘┐─ + +[review] +lineBreak=True +endOfScreen=True +# leave the review when pressing a key +leaveReviewOnCursorChange=True +# leave the review when changing the screen +leaveReviewOnScreenChange=True + +[promote] +enabled=True +inactiveTimeoutSec=120 +list= + +[menu] +vmenuPath= +quickMenu=speech#rate;speech#pitch;speech#volume + +[time] +# automatic time anouncement +enabled=False +# present time +presentTime=True +# present date (on change) +presentDate=True +# present time after a given period of seconds +delaySec=0 +# present time after to given minutes example every 15 minutes: 00,15,30,45 +# if delaySec is >0 onMinutes is ignored +onMinutes=00,30 +# announce via soundicon (not interrupting) +announce=True +# interrupt current speech for time announcement +interrupt=False diff --git a/config/settings/settings.conf.example b/config/settings/settings.conf.example index c844d29a..c67130fb 100644 --- a/config/settings/settings.conf.example +++ b/config/settings/settings.conf.example @@ -137,7 +137,10 @@ ignoreShortcuts=False # the current shortcut layout located in /etc/fenrirscreenreader/keyboard keyboardLayout=desktop # echo chars while typing. -charEcho=False +# 0 = None +# 1 = always +# 2 = only while capslock +charEchoMode=2 # echo deleted chars charDeleteEcho=True # echo word after pressing space diff --git a/config/settings/settings.conf.storm b/config/settings/settings.conf.storm index dcd59af1..0b8d2bd8 100644 --- a/config/settings/settings.conf.storm +++ b/config/settings/settings.conf.storm @@ -88,7 +88,10 @@ device=ALL grabDevices=True ignoreShortcuts=False keyboardLayout=desktop -charEcho=False +# 0 = None +# 1 = always +# 2 = only while capslock +charEchoMode=2 charDeleteEcho=True wordEcho=False interruptOnKeyPress=True diff --git a/config/settings/speech-dispatcher.settings.conf b/config/settings/speech-dispatcher.settings.conf index adf108f1..c898d2ee 100644 --- a/config/settings/speech-dispatcher.settings.conf +++ b/config/settings/speech-dispatcher.settings.conf @@ -136,7 +136,10 @@ ignoreShortcuts=False # the current shortcut layout located in /etc/fenrirscreenreader/keyboard keyboardLayout=desktop # echo chars while typing. -charEcho=False +# 0 = None +# 1 = always +# 2 = only while capslock +charEchoMode=2 # echo deleted chars charDeleteEcho=True # echo word after pressing space diff --git a/docu/fenrir.1 b/docu/fenrir.1 index 4f2e70e6..c604e491 100644 --- a/docu/fenrir.1 +++ b/docu/fenrir.1 @@ -222,7 +222,7 @@ your language for aspell (aspell\-\f[C]\f[]) (spellchecker) sox (sound) .IP \[bu] 2 For an individual installation see Support and -Requirements (#Support%20and%20Requirements) or consult the +Requirements (#Support and Requirements) or consult the Readme (https///github.com/chrys87/fenrir/blob/master/README.md)) .RE .IP "5." 3 @@ -261,13 +261,13 @@ at these resources: .IP \[bu] 2 Keybindings (#Keybindings) .IP \[bu] 2 -Tutorial Mode (#Tutorial%20Mode) +Tutorial Mode (#Tutorial Mode) .SH Features .SS Commands .SS Keybindings .PP Normal commands can be invoked in two ways: 1. -Using a Metakey (FenrirKey (#Fenrir%20Key)) 2. +Using a Metakey (FenrirKey (#Fenrir Key)) 2. Shortcuts with a single key .PP See section Keyboard (#Keyboard) in \[aq]\[aq]settings.conf\[aq]\[aq] @@ -298,429 +298,429 @@ _ T{ FenrirKey + H T}@T{ -toggle tutorial mode (#Tutorial%20Mode) +toggle tutorial mode (#Tutorial Mode) T} T{ CTRL T}@T{ -shut up (interrupts speech) (#shut%20up) +shut up (interrupts speech) (#shut up) T} T{ FenrirKey + KeyPad 9 T}@T{ -reviews bottom (#review%20bottom) +reviews bottom (#review bottom) T} T{ FenrirKey + KeyPad 7 T}@T{ -reviews top (#review%20top) +reviews top (#review top) T} T{ KeyPad 8 T}@T{ -reviews current line (#review%20current%20line) +reviews current line (#review current line) T} T{ KeyPad 7 T}@T{ -reviews previous line (#review%20previous%20line) +reviews previous line (#review previous line) T} T{ KeyPad 9 T}@T{ -reviews next line (#review%20next%20line) +reviews next line (#review next line) T} T{ FenrirKey + KeyPad 4 T}@T{ -reviews line beginning (#review%20line%20beginning) +reviews line beginning (#review line beginning) T} T{ FenrirKey + KeyPad 6 T}@T{ -reviews line ending (#review%20line%20ending) +reviews line ending (#review line ending) T} T{ FenrirKey + KeyPad 1 T}@T{ -reviews line first character (#review%20line%20first%20character) +reviews line first character (#review line first character) T} T{ FenrirKey + KeyPad 3 T}@T{ -reviews line last character (#review%20line%20last%20character) +reviews line last character (#review line last character) T} T{ FenrirKey + Alt + 1 T}@T{ -presents first line (#present%20first%20line) +presents first line (#present first line) T} T{ FenrirKey + Alt + 2 T}@T{ -presents last line (#present%20last%20line) +presents last line (#present last line) T} T{ KeyPad 5 T}@T{ -reviews current word (#review%20current%20word) +reviews current word (#review current word) T} T{ KeyPad 4 T}@T{ -reviews previous word (#review%20previous%20word) +reviews previous word (#review previous word) T} T{ KeyPad 6 T}@T{ -reviews next word (#review%20next%20word) +reviews next word (#review next word) T} T{ FenrirKey + Shift + KeyPad 5 T}@T{ -reviews current word phonetic (#review%20current%20word%20phonetic) +reviews current word phonetic (#review current word phonetic) T} T{ FenrirKey + Shift + KeyPad 4 T}@T{ -reviews previous word phonetic (#review%20previous%20word%20phonetic) +reviews previous word phonetic (#review previous word phonetic) T} T{ FenrirKey + Shift + KeyPad 6 T}@T{ -reviews next word phonetic (#review%20next%20word%20phonetic) +reviews next word phonetic (#review next word phonetic) T} T{ KeyPad 2 T}@T{ -reviews current char (#review%20current%20character) +reviews current char (#review current character) T} T{ KeyPad 1 T}@T{ -reviews previous char (#review%20previous%20character) +reviews previous char (#review previous character) T} T{ KeyPad 3 T}@T{ -reviews next char (#review%20next%20character) +reviews next char (#review next character) T} T{ FenrirKey + Shift + KeyPad 2 T}@T{ reviews current character -phonetic (#review%20current%20character%20phonetic) +phonetic (#review current character phonetic) T} T{ FenrirKey + Shift + KeyPad 1 T}@T{ reviews previous character -phonetic (#review%20previous%20character%20phonetic) +phonetic (#review previous character phonetic) T} T{ FenrirKey + Shift + KeyPad 3 T}@T{ -reviews next character phonetic (#review%20next%20character%20phonetic) +reviews next character phonetic (#review next character phonetic) T} T{ FenrirKey + CTRL + KeyPad 8 T}@T{ -reviews up (#review%20up) +reviews up (#review up) T} T{ FenrirKey + CTRL + KeyPad 2 T}@T{ -reviews down (#review%20down) +reviews down (#review down) T} T{ FenrirKey + KeyPad dot T}@T{ -exit review (#exit%20review) +exit review (#exit review) T} T{ KeyPad dot T}@T{ -cursor position (#cursor%20position) +cursor position (#cursor position) T} T{ FenrirKey + I T}@T{ -indent curr line (#indent%20current%20line) +indent curr line (#indent current line) T} T{ FenrirKey + KeyPad 5 T}@T{ -current screen (#current%20screen) +current screen (#current screen) T} T{ FenrirKey + KeyPad 8 T}@T{ -current screen before cursor (#current%20screen%20before%20cursor) +current screen before cursor (#current screen before cursor) T} T{ FenrirKey + KeyPad 2 T}@T{ -current screen after cursor (#current%20screen%20after%20cursor) +current screen after cursor (#current screen after cursor) T} T{ \f[C]\f[] T}@T{ -cursor read to end of line (#cursor%20read%20to%20end%20of%20line) +cursor read to end of line (#cursor read to end of line) T} T{ \f[C]\f[] T}@T{ -cursor column (#cursor%20column) +cursor column (#cursor column) T} T{ \f[C]\f[] T}@T{ -cursor line number (#cursor%20line%20number) +cursor line number (#cursor line number) T} T{ \f[C]\f[] T}@T{ -Braille flush (#braille%20flush) +Braille flush (#braille flush) T} T{ \f[C]\f[] T}@T{ -Braille pan left (#braille%20pan%20left) +Braille pan left (#braille pan left) T} T{ \f[C]\f[] T}@T{ -Braille pan right (#braille%20pan%20right) +Braille pan right (#braille pan right) T} T{ \f[C]\f[] T}@T{ -Braille return to cursor (#braille%20return%20to%20cursor) +Braille return to cursor (#braille return to cursor) T} T{ FenrirKey + CTRL + 1 T}@T{ -clear bookmark 1 (#clear%20Bookmark%20X) +clear bookmark 1 (#clear Bookmark X) T} T{ FenrirKey + Shift + 1 T}@T{ -set bookmark 1 (#set%20Bookmark%20X) +set bookmark 1 (#set Bookmark X) T} T{ FenrirKey + 1 T}@T{ -bookmark 1 (#read%20Bookmark%20X) +bookmark 1 (#read Bookmark X) T} T{ FenrirKey + CTRL + 2 T}@T{ -clear bookmark 2 (#clear%20Bookmark%20X) +clear bookmark 2 (#clear Bookmark X) T} T{ FenrirKey + Shift + 2 T}@T{ -set bookmark 2 (#set%20Bookmark%20X) +set bookmark 2 (#set Bookmark X) T} T{ FenrirKey + 2 T}@T{ -bookmark 2 (#read%20Bookmark%20X) +bookmark 2 (#read Bookmark X) T} T{ FenrirKey + CTRL + 3 T}@T{ -clear bookmark 3 (#clear%20Bookmark%20X) +clear bookmark 3 (#clear Bookmark X) T} T{ FenrirKey + Shift + 3 T}@T{ -set bookmark 3 (#set%20Bookmark%20X) +set bookmark 3 (#set Bookmark X) T} T{ FenrirKey + 3 T}@T{ -bookmark 3 (#read%20Bookmark%20X) +bookmark 3 (#read Bookmark X) T} T{ FenrirKey + CTRL + 4 T}@T{ -clear bookmark 4 (#clear%20Bookmark%20X) +clear bookmark 4 (#clear Bookmark X) T} T{ FenrirKey + Shift + 4 T}@T{ -set bookmark 4 (#set%20Bookmark%20X) +set bookmark 4 (#set Bookmark X) T} T{ FenrirKey + 4 T}@T{ -bookmark 4 (#read%20Bookmark%20X) +bookmark 4 (#read Bookmark X) T} T{ FenrirKey + CTRL + 5 T}@T{ -clear bookmark 5 (#clear%20Bookmark%20X) +clear bookmark 5 (#clear Bookmark X) T} T{ FenrirKey + Shift + 5 T}@T{ -set bookmark 5 (#set%20Bookmark%20X) +set bookmark 5 (#set Bookmark X) T} T{ FenrirKey + 5 T}@T{ -bookmark 5 (#read%20Bookmark%20X) +bookmark 5 (#read Bookmark X) T} T{ FenrirKey + CTRL + 6 T}@T{ -clear bookmark 6 (#clear%20Bookmark%20X) +clear bookmark 6 (#clear Bookmark X) T} T{ FenrirKey + Shift + 6 T}@T{ -set bookmark 6 (#set%20Bookmark%20X) +set bookmark 6 (#set Bookmark X) T} T{ FenrirKey + 6 T}@T{ -bookmark 6 (#read%20Bookmark%20X) +bookmark 6 (#read Bookmark X) T} T{ FenrirKey + CTRL + 7 T}@T{ -clear bookmark 7 (#clear%20Bookmark%20X) +clear bookmark 7 (#clear Bookmark X) T} T{ FenrirKey + Shift + 7 T}@T{ -set bookmark 7 (#set%20Bookmark%20X) +set bookmark 7 (#set Bookmark X) T} T{ FenrirKey + 7 T}@T{ -bookmark 7 (#read%20Bookmark%20X) +bookmark 7 (#read Bookmark X) T} T{ FenrirKey + CTRL + 8 T}@T{ -clear bookmark 8 (#clear%20Bookmark%20X) +clear bookmark 8 (#clear Bookmark X) T} T{ FenrirKey + Shift + 8 T}@T{ -set bookmark 8 (#set%20Bookmark%20X) +set bookmark 8 (#set Bookmark X) T} T{ FenrirKey + 8 T}@T{ -bookmark 8 (#read%20Bookmark%20X) +bookmark 8 (#read Bookmark X) T} T{ FenrirKey + CTRL + 9 T}@T{ -clear bookmark 9 (#clear%20Bookmark%20X) +clear bookmark 9 (#clear Bookmark X) T} T{ FenrirKey + Shift + 9 T}@T{ -set bookmark 9 (#set%20Bookmark%20X) +set bookmark 9 (#set Bookmark X) T} T{ FenrirKey + 9 T}@T{ -bookmark 9 (#read%20Bookmark%20X) +bookmark 9 (#read Bookmark X) T} T{ FenrirKey + CTRL + 0 T}@T{ -clear bookmark 10 (#clear%20Bookmark%20X) +clear bookmark 10 (#clear Bookmark X) T} T{ FenrirKey + Shift + 0 T}@T{ -set bookmark 10 (#set%20Bookmark%20X) +set bookmark 10 (#set Bookmark X) T} T{ FenrirKey + 0 T}@T{ -bookmark 10 (#read%20Bookmark%20X) +bookmark 10 (#read Bookmark X) T} T{ FenrirKey + KeyPad Slash T}@T{ -set window application (#Create%20Window) +set window application (#Create Window) T} T{ 2 * FenrirKey + KeyPad Slash T}@T{ -clear window application (#Remove%20Window) +clear window application (#Remove Window) T} T{ KeyPad Plus T}@T{ -read last incoming (#last%20incoming) +read last incoming (#last incoming) T} T{ FenrirKey + F2 T}@T{ -toggles braille (#toggle%20braille) +toggles braille (#toggle braille) T} T{ FenrirKey + F3 T}@T{ -toggles sound (#toggle%20sound) +toggles sound (#toggle sound) T} T{ FenrirKey + F4 T}@T{ -toggles speech (#toggle%20speech) +toggles speech (#toggle speech) T} T{ KeyPad Enter T}@T{ -temporarily disables speech (#disable%20speech%20temporarily) +temporarily disables speech (#disable speech temporarily) T} T{ FenrirKey + CTRL + P T}@T{ -toggles punctuation level (#toggle%20punctuation%20level) +toggles punctuation level (#toggle punctuation level) T} T{ FenrirKey + RightBrace T}@T{ -toggle auto spell check (#toggle%20auto%20spell%20check) +toggle auto spell check (#toggle auto spell check) T} T{ FenrirKey + Backslash T}@T{ -toggles output (#toggle%20output) +toggles output (#toggle output) T} T{ FenrirKey + CTRL + E T}@T{ -toggles emoticons (#toggle%20emoticons) +toggles emoticons (#toggle emoticons) T} T{ FenrirKey + KeyPad Enter T}@T{ -toggles auto read (#toggle%20auto%20read) +toggles auto read (#toggle auto read) T} T{ FenrirKey + CTRL + T T}@T{ -toggles auto time (#toggle%20auto%20time) +toggles auto time (#toggle auto time) T} T{ FenrirKey + KeyPad ASTERISK T}@T{ -toggles highlight tracking (#toggle%20highlight%20tracking) +toggles highlight tracking (#toggle highlight tracking) T} T{ FenrirKey + Q T}@T{ -quits fenrir (#quit%20Fenrir) +quits fenrir (#quit Fenrir) T} T{ FenrirKey + T @@ -735,127 +735,127 @@ T} T{ FenrirKey + S T}@T{ -spell check (#spell%20check) +spell check (#spell check) T} T{ 2 * FenrirKey + S T}@T{ -add word to spell check (#add%20word%20to%20spell%20check) +add word to spell check (#add word to spell check) T} T{ FenrirKey + Shift + S T}@T{ -removes word from spell check (#removes%20word%20from%20spell%20check) +removes word from spell check (#removes word from spell check) T} T{ FenrirKey + Backspace T}@T{ -forward keypress (#forward%20keypress) +forward keypress (#forward keypress) T} T{ FenrirKey + Up T}@T{ -increase speech volume (#increase%20speech%20volume) +increase speech volume (#increase speech volume) T} T{ FenrirKey + Down T}@T{ -decrease speech volume (#decrease%20speech%20volume) +decrease speech volume (#decrease speech volume) T} T{ FenrirKey + Right T}@T{ -increase speech rate (#increase%20speech%20rate) +increase speech rate (#increase speech rate) T} T{ FenrirKey + Left T}@T{ -decrease speech rate (#decrease%20speech%20rate) +decrease speech rate (#decrease speech rate) T} T{ FenrirKey + Alt + Right T}@T{ -increase speech pitch (#increase%20speech%20pitch) +increase speech pitch (#increase speech pitch) T} T{ FenrirKey + Alt + Left T}@T{ -decrease speech pitch (#decrease%20speech%20pitch) +decrease speech pitch (#decrease speech pitch) T} T{ FenrirKey + Alt + Up T}@T{ -increase sound volume (#increase%20sound%20volume) +increase sound volume (#increase sound volume) T} T{ FenrirKey + Alt + Down T}@T{ -decrease sound volume (#decrease%20sound%20volume) +decrease sound volume (#decrease sound volume) T} T{ FenrirKey + CTRL + Shift + C T}@T{ -clears clipboard (#clear%20clipboard) +clears clipboard (#clear clipboard) T} T{ FenrirKey + Home T}@T{ -first clipboard (#first%20clipboard) +first clipboard (#first clipboard) T} T{ FenrirKey + End T}@T{ -last clipboard (#last%20clipboard) +last clipboard (#last clipboard) T} T{ FenrirKey + PageUp T}@T{ -previous clipboard (#previous%20clipboard) +previous clipboard (#previous clipboard) T} T{ FenrirKey + PageDown T}@T{ -next clipboard (#next%20clipboard) +next clipboard (#next clipboard) T} T{ FenrirKey + Shift + C T}@T{ -current clipboard (#read%20current%20clipboard) +current clipboard (#read current clipboard) T} T{ FenrirKey + C T}@T{ -copy marked text to clipboard (#copy%20marked%20to%20clipboard) +copy marked text to clipboard (#copy marked to clipboard) T} T{ FenrirKey + V T}@T{ -paste clipboard contents (#paste%20clipboard) +paste clipboard contents (#paste clipboard) T} T{ FenrirKey + P T}@T{ -import clipboard from file (#import%20clipboard%20from%20file) +import clipboard from file (#import clipboard from file) T} T{ FenrirKey + Alt + Shift +C T}@T{ -export clipboard to file (#export%20clipboard%20to%20file) +export clipboard to file (#export clipboard to file) T} T{ FenrirKey + CTRL + Shift + X T}@T{ -remove marks (#Remove%20Marks) +remove marks (#Remove Marks) T} T{ FenrirKey + X T}@T{ -set mark (#Set%20mark) +set mark (#Set mark) T} T{ FenrirKey + Shift + X T}@T{ -announce marked text (#Get%20text%20between%20marks) +announce marked text (#Get text between marks) T} T{ Linux specific @@ -891,429 +891,429 @@ _ T{ FenrirKey + H T}@T{ -toggle tutorial mode (#Tutorial%20Mode) +toggle tutorial mode (#Tutorial Mode) T} T{ CTRL T}@T{ -shut up (interrupts speech) (#shut%20up) +shut up (interrupts speech) (#shut up) T} T{ FenrirKey + Shift + O T}@T{ -reviews bottom (#review%20bottom) +reviews bottom (#review bottom) T} T{ FenrirKey + Shift + U T}@T{ -reviews top (#review%20top) +reviews top (#review top) T} T{ FenrirKey + I T}@T{ -reviews current line (#review%20current%20line) +reviews current line (#review current line) T} T{ FenrirKey + U T}@T{ -reviews previous line (#review%20previous%20line) +reviews previous line (#review previous line) T} T{ FenrirKey + O T}@T{ -reviews next line (#review%20next%20line) +reviews next line (#review next line) T} T{ FenrirKey + Shift + J T}@T{ -reviews line beginning (#review%20line%20beginning) +reviews line beginning (#review line beginning) T} T{ FenrirKey + Shift + L T}@T{ -reviews line ending (#review%20line%20ending) +reviews line ending (#review line ending) T} T{ FenrirKey + CTRL + J T}@T{ -reviews line first character (#review%20line%20first%20character) +reviews line first character (#review line first character) T} T{ FenrirKey + CTRL + L T}@T{ -reviews line last character (#review%20line%20last%20character) +reviews line last character (#review line last character) T} T{ FenrirKey + Alt + 1 T}@T{ -presents first line (#present%20first%20line) +presents first line (#present first line) T} T{ FenrirKey + Alt + 2 T}@T{ -presents last line (#present%20last%20line) +presents last line (#present last line) T} T{ FenrirKey + K T}@T{ -reviews current word (#review%20current%20word) +reviews current word (#review current word) T} T{ FenrirKey + J T}@T{ -reviews previous word (#review%20previous%20word) +reviews previous word (#review previous word) T} T{ FenrirKey + L T}@T{ -reviews next word (#review%20next%20word) +reviews next word (#review next word) T} T{ FenrirKey + CTRL + ALT + K T}@T{ -reviews current word phonetic (#review%20current%20word%20phonetic) +reviews current word phonetic (#review current word phonetic) T} T{ FenrirKey + CTRL + ALT + J T}@T{ -reviews previous word phonetic (#review%20previous%20word%20phonetic) +reviews previous word phonetic (#review previous word phonetic) T} T{ FenrirKey + CTRL + ALT + L T}@T{ -reviews next word phonetic (#review%20next%20word%20phonetic) +reviews next word phonetic (#review next word phonetic) T} T{ FenrirKey + comma T}@T{ -reviews current character (#review%20current%20character) +reviews current character (#review current character) T} T{ FenrirKey + M T}@T{ -reviews previous character (#review%20previous%20character) +reviews previous character (#review previous character) T} T{ FenrirKey + dot T}@T{ -reviews next character (#review%20next%20character) +reviews next character (#review next character) T} T{ FenrirKey + CTRL + ALT + comma T}@T{ reviews current character -phonetic (#review%20current%20character%20phonetic) +phonetic (#review current character phonetic) T} T{ FenrirKey + CTRL + ALT + M T}@T{ reviews previous character -phonetic (#review%20previous%20character%20phonetic) +phonetic (#review previous character phonetic) T} T{ FenrirKey + CTRL + ALT + dot T}@T{ -reviews next character phonetic (#review%20next%20character%20phonetic) +reviews next character phonetic (#review next character phonetic) T} T{ FenrirKey + CTRL + I T}@T{ -reviews up (#review%20up) +reviews up (#review up) T} T{ FenrirKey + CTRL + comma T}@T{ -reviews down (#review%20down) +reviews down (#review down) T} T{ FenrirKey + Slash T}@T{ -exit review (#exit%20review) +exit review (#exit review) T} T{ FenrirKey + Shift + dot T}@T{ -cursor position (#cursor%20position) +cursor position (#cursor position) T} T{ 2 * FenrirKey + I T}@T{ -indent curr line (#indent%20current%20line) +indent curr line (#indent current line) T} T{ FenrirKey + Shift + K T}@T{ -current screen (#current%20screen) +current screen (#current screen) T} T{ FenrirKey + Shift + I T}@T{ -current screen before cursor (#current%20screen%20before%20cursor) +current screen before cursor (#current screen before cursor) T} T{ FenrirKey + Shift + comma T}@T{ -current screen after cursor (#current%20screen%20after%20cursor) +current screen after cursor (#current screen after cursor) T} T{ \f[C]\f[] T}@T{ -cursor read to end of line (#cursor%20read%20to%20end%20of%20line) +cursor read to end of line (#cursor read to end of line) T} T{ \f[C]\f[] T}@T{ -cursor column (#cursor%20column) +cursor column (#cursor column) T} T{ \f[C]\f[] T}@T{ -cursor line number (#cursor%20line%20number) +cursor line number (#cursor line number) T} T{ \f[C]\f[] T}@T{ -Braille flush (#braille%20flush) +Braille flush (#braille flush) T} T{ \f[C]\f[] T}@T{ -Braille pan left (#braille%20pan%20left) +Braille pan left (#braille pan left) T} T{ \f[C]\f[] T}@T{ -Braille pan right (#braille%20pan%20right) +Braille pan right (#braille pan right) T} T{ \f[C]\f[] T}@T{ -Braille return to cursor (#braille%20return%20to%20cursor) +Braille return to cursor (#braille return to cursor) T} T{ FenrirKey + CTRL + 1 T}@T{ -clear bookmark 1 (#clear%20Bookmark%20X) +clear bookmark 1 (#clear Bookmark X) T} T{ FenrirKey + Shift + 1 T}@T{ -set bookmark 1 (#set%20Bookmark%20X) +set bookmark 1 (#set Bookmark X) T} T{ FenrirKey + 1 T}@T{ -bookmark 1 (#read%20Bookmark%20X) +bookmark 1 (#read Bookmark X) T} T{ FenrirKey + CTRL + 2 T}@T{ -clear bookmark 2 (#clear%20Bookmark%20X) +clear bookmark 2 (#clear Bookmark X) T} T{ FenrirKey + Shift + 2 T}@T{ -set bookmark 2 (#set%20Bookmark%20X) +set bookmark 2 (#set Bookmark X) T} T{ FenrirKey + 2 T}@T{ -bookmark 2 (#read%20Bookmark%20X) +bookmark 2 (#read Bookmark X) T} T{ FenrirKey + CTRL + 3 T}@T{ -clear bookmark 3 (#clear%20Bookmark%20X) +clear bookmark 3 (#clear Bookmark X) T} T{ FenrirKey + Shift + 3 T}@T{ -set bookmark 3 (#set%20Bookmark%20X) +set bookmark 3 (#set Bookmark X) T} T{ FenrirKey + 3 T}@T{ -bookmark 3 (#read%20Bookmark%20X) +bookmark 3 (#read Bookmark X) T} T{ FenrirKey + CTRL + 4 T}@T{ -clear bookmark 4 (#clear%20Bookmark%20X) +clear bookmark 4 (#clear Bookmark X) T} T{ FenrirKey + Shift + 4 T}@T{ -set bookmark 4 (#set%20Bookmark%20X) +set bookmark 4 (#set Bookmark X) T} T{ FenrirKey + 4 T}@T{ -bookmark 4 (#read%20Bookmark%20X) +bookmark 4 (#read Bookmark X) T} T{ FenrirKey + CTRL + 5 T}@T{ -clear bookmark 5 (#clear%20Bookmark%20X) +clear bookmark 5 (#clear Bookmark X) T} T{ FenrirKey + Shift + 5 T}@T{ -set bookmark 5 (#set%20Bookmark%20X) +set bookmark 5 (#set Bookmark X) T} T{ FenrirKey + 5 T}@T{ -bookmark 5 (#read%20Bookmark%20X) +bookmark 5 (#read Bookmark X) T} T{ FenrirKey + CTRL + 6 T}@T{ -clear bookmark 6 (#clear%20Bookmark%20X) +clear bookmark 6 (#clear Bookmark X) T} T{ FenrirKey + Shift + 6 T}@T{ -set bookmark 6 (#set%20Bookmark%20X) +set bookmark 6 (#set Bookmark X) T} T{ FenrirKey + 6 T}@T{ -bookmark 6 (#read%20Bookmark%20X) +bookmark 6 (#read Bookmark X) T} T{ FenrirKey + CTRL + 7 T}@T{ -clear bookmark 7 (#clear%20Bookmark%20X) +clear bookmark 7 (#clear Bookmark X) T} T{ FenrirKey + Shift + 7 T}@T{ -set bookmark 7 (#set%20Bookmark%20X) +set bookmark 7 (#set Bookmark X) T} T{ FenrirKey + 7 T}@T{ -bookmark 7 (#read%20Bookmark%20X) +bookmark 7 (#read Bookmark X) T} T{ FenrirKey + CTRL + 8 T}@T{ -clear bookmark 8 (#clear%20Bookmark%20X) +clear bookmark 8 (#clear Bookmark X) T} T{ FenrirKey + Shift + 8 T}@T{ -set bookmark 8 (#set%20Bookmark%20X) +set bookmark 8 (#set Bookmark X) T} T{ FenrirKey + 8 T}@T{ -bookmark 8 (#read%20Bookmark%20X) +bookmark 8 (#read Bookmark X) T} T{ FenrirKey + CTRL + 9 T}@T{ -clear bookmark 9 (#clear%20Bookmark%20X) +clear bookmark 9 (#clear Bookmark X) T} T{ FenrirKey + Shift + 9 T}@T{ -set bookmark 9 (#set%20Bookmark%20X) +set bookmark 9 (#set Bookmark X) T} T{ FenrirKey + 9 T}@T{ -bookmark 9 (#read%20Bookmark%20X) +bookmark 9 (#read Bookmark X) T} T{ FenrirKey + CTRL + 0 T}@T{ -clear bookmark 10 (#clear%20Bookmark%20X) +clear bookmark 10 (#clear Bookmark X) T} T{ FenrirKey + Shift + 0 T}@T{ -set bookmark 10 (#set%20Bookmark%20X) +set bookmark 10 (#set Bookmark X) T} T{ FenrirKey + 0 T}@T{ -bookmark 10 (#read%20Bookmark%20X) +bookmark 10 (#read Bookmark X) T} T{ FenrirKey + CTRL + 8 T}@T{ -set window application (#Create%20Window) +set window application (#Create Window) T} T{ 2 * FenrirKey + CTRL + 8 T}@T{ -clear window application (#Remove%20Window) +clear window application (#Remove Window) T} T{ FenrirKey + Semicolon T}@T{ -read last incoming (#last%20incoming) +read last incoming (#last incoming) T} T{ FenrirKey + F2 T}@T{ -toggles braille (#toggle%20braille) +toggles braille (#toggle braille) T} T{ FenrirKey + F3 T}@T{ -toggles sound (#toggle%20sound) +toggles sound (#toggle sound) T} T{ FenrirKey + F4 T}@T{ -toggles speech (#toggle%20speech) +toggles speech (#toggle speech) T} T{ FenrirKey + Enter T}@T{ -temporarily disables speech (#disable%20speech%20temporarily) +temporarily disables speech (#disable speech temporarily) T} T{ FenrirKey + Shift + CTRL + P T}@T{ -toggles punctuation level (#toggle%20punctuation%20level) +toggles punctuation level (#toggle punctuation level) T} T{ FenrirKey + RightBrace T}@T{ -toggle auto spell check (#toggle%20auto%20spell%20check) +toggle auto spell check (#toggle auto spell check) T} T{ FenrirKey + Shift + Enter T}@T{ -toggles output (#toggle%20output) +toggles output (#toggle output) T} T{ FenrirKey + Shift + E T}@T{ -toggles emoticons (#toggle%20emoticons) +toggles emoticons (#toggle emoticons) T} T{ FenrirKey + Enter T}@T{ -toggles auto read (#toggle%20auto%20read) +toggles auto read (#toggle auto read) T} T{ FenrirKey + CTRL + T T}@T{ -toggles auto time (#toggle%20auto%20time) +toggles auto time (#toggle auto time) T} T{ FenrirKey + Y T}@T{ -toggles highlight tracking (#toggle%20highlight%20tracking) +toggles highlight tracking (#toggle highlight tracking) T} T{ FenrirKey + Q T}@T{ -quits fenrir (#quit%20Fenrir) +quits fenrir (#quit Fenrir) T} T{ FenrirKey + T @@ -1328,127 +1328,127 @@ T} T{ FenrirKey + S T}@T{ -spell check (#spell%20check) +spell check (#spell check) T} T{ 2 * FenrirKey + S T}@T{ -add word to spell check (#add%20word%20to%20spell%20check) +add word to spell check (#add word to spell check) T} T{ FenrirKey + Shift + S T}@T{ -removes word from spell check (#removes%20word%20from%20spell%20check) +removes word from spell check (#removes word from spell check) T} T{ FenrirKey + Backspace T}@T{ -forward keypress (#forward%20keypress) +forward keypress (#forward keypress) T} T{ FenrirKey + Up T}@T{ -increase speech volume (#increase%20speech%20volume) +increase speech volume (#increase speech volume) T} T{ FenrirKey + Down T}@T{ -decrease speech volume (#decrease%20speech%20volume) +decrease speech volume (#decrease speech volume) T} T{ FenrirKey + Right T}@T{ -increase speech rate (#increase%20speech%20rate) +increase speech rate (#increase speech rate) T} T{ FenrirKey + Left T}@T{ -decrease speech rate (#decrease%20speech%20rate) +decrease speech rate (#decrease speech rate) T} T{ FenrirKey + Alt + Right T}@T{ -increase speech pitch (#increase%20speech%20pitch) +increase speech pitch (#increase speech pitch) T} T{ FenrirKey + Alt + Left T}@T{ -decrease speech pitch (#decrease%20speech%20pitch) +decrease speech pitch (#decrease speech pitch) T} T{ FenrirKey + Alt + Up T}@T{ -increase sound volume (#increase%20sound%20volume) +increase sound volume (#increase sound volume) T} T{ FenrirKey + Alt + Down T}@T{ -decrease sound volume (#decrease%20sound%20volume) +decrease sound volume (#decrease sound volume) T} T{ FenrirKey + CTRL + Shift + C T}@T{ -clears clipboard (#clear%20clipboard) +clears clipboard (#clear clipboard) T} T{ FenrirKey + Home T}@T{ -first clipboard (#first%20clipboard) +first clipboard (#first clipboard) T} T{ FenrirKey + End T}@T{ -last clipboard (#last%20clipboard) +last clipboard (#last clipboard) T} T{ FenrirKey + PageUp T}@T{ -previous clipboard (#previous%20clipboard) +previous clipboard (#previous clipboard) T} T{ FenrirKey + PageDown T}@T{ -next clipboard (#next%20clipboard) +next clipboard (#next clipboard) T} T{ FenrirKey + Shift + C T}@T{ -current clipboard (#read%20current%20clipboard) +current clipboard (#read current clipboard) T} T{ FenrirKey + C T}@T{ -copy marked text to clipboard (#copy%20marked%20to%20clipboard) +copy marked text to clipboard (#copy marked to clipboard) T} T{ FenrirKey + V T}@T{ -paste clipboard contents (#paste%20clipboard) +paste clipboard contents (#paste clipboard) T} T{ FenrirKey + F5 T}@T{ -import clipboard from file (#import%20clipboard%20from%20file) +import clipboard from file (#import clipboard from file) T} T{ FenrirKey + Alt + Shift +C T}@T{ -export clipboard to file (#export%20clipboard%20to%20file) +export clipboard to file (#export clipboard to file) T} T{ FenrirKey + CTRL + Shift + X T}@T{ -remove marks (#Remove%20Marks) +remove marks (#Remove Marks) T} T{ FenrirKey + X T}@T{ -set mark (#Set%20mark) +set mark (#Set mark) T} T{ FenrirKey + Shift + X T}@T{ -announce marked text (#Get%20text%20between%20marks) +announce marked text (#Get text between marks) T} T{ Linux specific @@ -2088,7 +2088,7 @@ want to hear colons and perryns not smiles. You can configure Fenrir in the following places (ordered by priority): 1. Commandline Parameters \[aq]\[aq]\-o\[aq]\[aq] see Set settings -coption (#Set%20settings%20coption) 2. +coption (#Set settings coption) 2. /etc/fenrir/settings/settings.conf see Settigns (#Settings) 3. \f[C]\f[]/config/settings/settings.conf see Settigns (#Settings) 4. @@ -2107,7 +2107,7 @@ For example changing the sound driver to gstreamer and disabling Braille fenrir \-o "sound#driver=gstreamerDriver;braille#enabled=False=False" or change the debug level to verbose fenrir \-o "general#debugLevel=3" You can find the available sections and variables here <#Settings> See -Syntax #settings.conf syntax (#settings.conf%20syntax) ### settings.conf +Syntax #settings.conf syntax (#settings.conf syntax) ### settings.conf syntax .PP the syntax of the settings.conf (#Settings) is quite simple and similar @@ -2482,7 +2482,7 @@ Add a pause on Line break: newLinePause=True Values: on=\[aq]\[aq]True\[aq]\[aq], off=\[aq]\[aq]False\[aq]\[aq] .PP Specify the path where the clipboard should be exported to. -See export clipboard to file (#export%20clipboard%20to%20file). +See export clipboard to file (#export clipboard to file). The variable \[aq]\[aq]$user\[aq]\[aq] is replaced by the current logged username. clipboardExportPath=/tmp/fenrirClipboard Values: Text, Systemfilepath @@ -2697,7 +2697,7 @@ and has no functionality yet. .SS Fenrir does not start .IP " 1." 4 Have you installed all the dependencies Support and -Requirements (#Support%20and%20Requirements) +Requirements (#Support and Requirements) .IP " 2." 4 Try using master, a lot of changes take place there to make Fenrir compatible with more systems ## Fenrir does not utilize the shortcuts @@ -2748,7 +2748,7 @@ feature requests Please report Bugs and feature requests to: https://github.com/chrys87/fenrir/issues (https///github.com/chrys87/fenrir/issues) .PP -for bugs please provide a debug (#Howto%20create%20a%20debug%20file) +for bugs please provide a debug (#Howto create a debug file) file that shows the issue. ### How\-to create a debug file .IP "1." 3 diff --git a/play zone/pasteClipboardDemo.py b/play zone/pasteClipboardDemo.py new file mode 100755 index 00000000..94c32cfc --- /dev/null +++ b/play zone/pasteClipboardDemo.py @@ -0,0 +1,11 @@ +#!/bin/python3 +import termios +import fcntl + +def injectTextToScreen(text): + useScreen = "/dev/tty5" + with open(useScreen, 'w') as fd: + for c in text: + fcntl.ioctl(fd, termios.TIOCSTI, c) + +injectTextToScreen('this is a test that works') diff --git a/setup.py b/setup.py index 61b6a497..38eb1abd 100755 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -#!/bin/python +#!/usr/bin/env python3 #https://python-packaging.readthedocs.io/en/latest/minimal.html import os, glob, sys import os.path diff --git a/src/fenrirscreenreader/commands/commands/cursor_read_line_to_cursor.py b/src/fenrirscreenreader/commands/commands/cursor_read_line_to_cursor.py new file mode 100644 index 00000000..b24d3b21 --- /dev/null +++ b/src/fenrirscreenreader/commands/commands/cursor_read_line_to_cursor.py @@ -0,0 +1,33 @@ +#!/bin/python +# -*- coding: utf-8 -*- + +# Fenrir TTY screen reader +# By Chrys, Storm Dragon, and contributers. + +from fenrirscreenreader.core import debug +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 _('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']) + + if currLine.isspace(): + 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'].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 3e72819b..3e2d2072 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 @@ -26,8 +26,8 @@ class command(): if currLine.isspace(): 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'].announceActiveCursor() + 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/export_clipboard_to_x.py b/src/fenrirscreenreader/commands/commands/export_clipboard_to_x.py index fba57a56..de73f68d 100644 --- a/src/fenrirscreenreader/commands/commands/export_clipboard_to_x.py +++ b/src/fenrirscreenreader/commands/commands/export_clipboard_to_x.py @@ -20,30 +20,37 @@ class command(): return _('Export current fenrir clipboard to X or GUI clipboard') def run(self): _thread.start_new_thread(self._threadRun , ()) - def _threadRun(self): 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') + return + + clipboard = self.env['runtime']['memoryManager'].getIndexListElement('clipboardHistory') + user = self.env['general']['currUser'] + for display in range(10): - p = Popen('su ' + self.env['general']['currUser'] + ' -c "cat << \\\"EOF\\\" | xclip -d :' + str(display) + ' -selection clipboard\n' + clipboard + '\nEOF\n"', stdout=PIPE, stderr=PIPE, shell=True) - stdout, stderr = p.communicate() + p = Popen( + ['su', user, '-c', f"xclip -d :{display} -selection clipboard"], + stdin=PIPE, stdout=PIPE, stderr=PIPE, preexec_fn=os.setpgrp + ) + stdout, stderr = p.communicate(input=clipboard.encode('utf-8')) + self.env['runtime']['outputManager'].interruptOutput() - #screenEncoding = self.env['runtime']['settingsManager'].getSetting('screen', 'encoding') + stderr = stderr.decode('utf-8') stdout = stdout.decode('utf-8') - if (stderr == ''): - break - #stderr = stderr.decode(screenEncoding, "replace").encode('utf-8').decode('utf-8') - #stdout = stdout.decode(screenEncoding, "replace").encode('utf-8').decode('utf-8') + + if stderr == '': + break + if stderr != '': - self.env['runtime']['outputManager'].presentText(stderr , soundIcon='', interrupt=False) + self.env['runtime']['outputManager'].presentText(stderr, soundIcon='', interrupt=False) else: - self.env['runtime']['outputManager'].presentText('exported to the X session.', interrupt=True) + self.env['runtime']['outputManager'].presentText('exported to the X session.', interrupt=True) + except Exception as e: - self.env['runtime']['outputManager'].presentText(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/review_bottom.py b/src/fenrirscreenreader/commands/commands/review_bottom.py index 1d2f3c1b..cbc9e833 100644 --- a/src/fenrirscreenreader/commands/commands/review_bottom.py +++ b/src/fenrirscreenreader/commands/commands/review_bottom.py @@ -14,11 +14,11 @@ class command(): def shutdown(self): pass def getDescription(self): - return _('Move review to the bottom of the screen') + 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['runtime']['outputManager'].presentText(_("Bottom"), interrupt=True, flush=False) 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 7c416eee..83c7a1aa 100644 --- a/src/fenrirscreenreader/commands/commands/review_line_begin.py +++ b/src/fenrirscreenreader/commands/commands/review_line_begin.py @@ -15,7 +15,7 @@ class command(): def shutdown(self): pass def getDescription(self): - return _('set review cursor to begin of current line and display the content') + return _('set review cursor to begin of current line and display the content') def run(self): cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor() diff --git a/src/fenrirscreenreader/commands/commands/review_screen_first_char.py b/src/fenrirscreenreader/commands/commands/review_screen_first_char.py new file mode 100644 index 00000000..460d38cc --- /dev/null +++ b/src/fenrirscreenreader/commands/commands/review_screen_first_char.py @@ -0,0 +1,30 @@ +#!/bin/python +# -*- coding: utf-8 -*- + +# Fenrir TTY screen reader +# By Chrys, Storm Dragon, and contributers. + +from fenrirscreenreader.core import debug +from fenrirscreenreader.utils import char_utils + +class command(): + def __init__(self): + pass + def initialize(self, environment): + self.env = environment + def shutdown(self): + 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['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], lastChar = \ + char_utils.getLastCharInLine(self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + + self.env['runtime']['outputManager'].presentText(lastChar ,interrupt=True, ignorePunctuation=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 new file mode 100644 index 00000000..cdd51058 --- /dev/null +++ b/src/fenrirscreenreader/commands/commands/review_screen_last_char.py @@ -0,0 +1,30 @@ +#!/bin/python +# -*- coding: utf-8 -*- + +# Fenrir TTY screen reader +# By Chrys, Storm Dragon, and contributers. + +from fenrirscreenreader.core import debug +from fenrirscreenreader.utils import char_utils + +class command(): + def __init__(self): + pass + def initialize(self, environment): + self.env = environment + def shutdown(self): + 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['screen']['newCursorReview']['x'], self.env['screen']['newCursorReview']['y'], lastChar = \ + char_utils.getLastCharInLine(self.env['screen']['newCursorReview']['y'], self.env['screen']['newContentText']) + + self.env['runtime']['outputManager'].presentText(lastChar ,interrupt=True, ignorePunctuation=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/onCursorChange/15000-char_echo.py b/src/fenrirscreenreader/commands/onCursorChange/15000-char_echo.py index dd62c658..8526f306 100644 --- a/src/fenrirscreenreader/commands/onCursorChange/15000-char_echo.py +++ b/src/fenrirscreenreader/commands/onCursorChange/15000-char_echo.py @@ -17,9 +17,15 @@ class command(): return 'No Description found' def run(self): - # enabled? - if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'charEcho'): + # enabled? + active = self.env['runtime']['settingsManager'].getSettingAsInt('keyboard', 'charEchoMode') + # 0 = off + if active == 0: return + # 2 = caps only + 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']) if xMove > 3: @@ -42,6 +48,7 @@ class command(): currDelta.strip() != '': currDelta = currDelta.strip() self.env['runtime']['outputManager'].presentText(currDelta, interrupt=True, ignorePunctuation=True, announceCapital=True, flush=False) + print(currDelta) def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/commands/onHeartBeat/76000-time.py b/src/fenrirscreenreader/commands/onHeartBeat/76000-time.py index e5237241..1d114dfd 100755 --- a/src/fenrirscreenreader/commands/onHeartBeat/76000-time.py +++ b/src/fenrirscreenreader/commands/onHeartBeat/76000-time.py @@ -1,5 +1,4 @@ #!/bin/python -import time # -*- coding: utf-8 -*- # Fenrir TTY screen reader @@ -12,63 +11,75 @@ 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): if not self.env['runtime']['settingsManager'].getSettingAsBool('time', 'enabled'): return - onMinutes = self.env['runtime']['settingsManager'].getSetting('time', 'onMinutes') + + onMinutes = self.env['runtime']['settingsManager'].getSetting('time', 'onMinutes') delaySec = self.env['runtime']['settingsManager'].getSettingAsInt('time', 'delaySec') + # no need if onMinutes == '' and delaySec <= 0: return + onMinutes = onMinutes.split(',') now = datetime.datetime.now() + # ignore onMinutes if there is a delaySec if delaySec > 0: - if int((now-self.lastTime).total_seconds()) < delaySec: - return + if int((now - self.lastTime).total_seconds()) < delaySec: + return else: - # shoul announce? + # should announce? if not str(now.minute).zfill(2) in onMinutes: return # already announced? if now.hour == self.lastTime.hour: if now.minute == self.lastTime.minute: return + 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') + self.lastDateString != dateString + presentTime = self.env['runtime']['settingsManager'].getSettingAsBool('time', 'presentTime') + # no changed value to announce if not (presentDate or presentTime): - return + return + 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'): - self.env['runtime']['outputManager'].playSoundIcon('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) - # and date if changes - if presentDate: - self.env['runtime']['outputManager'].presentText(dateString , soundIcon='', interrupt=False) - self.lastDateString = dateString + # 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.lastTime = datetime.datetime.now() - self.lastTimeString = timeString + self.lastTimeString = timeString + def setCallback(self, callback): pass diff --git a/src/fenrirscreenreader/core/fenrirManager.py b/src/fenrirscreenreader/core/fenrirManager.py index ae841000..5af7f70d 100644 --- a/src/fenrirscreenreader/core/fenrirManager.py +++ b/src/fenrirscreenreader/core/fenrirManager.py @@ -84,8 +84,10 @@ class fenrirManager(): self.environment['runtime']['inputManager'].writeEventBuffer() if self.environment['runtime']['inputManager'].noKeyPressed(): self.modifierInput = False - self.singleKeyCommand = False + self.singleKeyCommand = False + self.environment['runtime']['inputManager'].writeEventBuffer() self.environment['runtime']['inputManager'].handleDeviceGrab() + if self.environment['input']['keyForeward'] > 0: self.environment['input']['keyForeward'] -=1 self.environment['runtime']['commandManager'].executeDefaultTrigger('onKeyInput') diff --git a/src/fenrirscreenreader/core/inputManager.py b/src/fenrirscreenreader/core/inputManager.py index e658463c..9bcad4a7 100644 --- a/src/fenrirscreenreader/core/inputManager.py +++ b/src/fenrirscreenreader/core/inputManager.py @@ -139,6 +139,8 @@ class inputManager(): self.env['input']['prevInput'] = [] def handleLedStates(self, mEvent): + if self.currKeyIsModifier(): + return try: if mEvent['EventName'] == 'KEY_NUMLOCK': self.env['runtime']['inputDriver'].toggleLedState() diff --git a/src/fenrirscreenreader/core/settingsData.py b/src/fenrirscreenreader/core/settingsData.py index 373262d9..eb8bc41b 100644 --- a/src/fenrirscreenreader/core/settingsData.py +++ b/src/fenrirscreenreader/core/settingsData.py @@ -124,7 +124,7 @@ settingsData = { 'grabDevices': True, 'ignoreShortcuts': False, 'keyboardLayout': "desktop", - 'charEcho': False, + 'charEchoMode': 2, # while capslock 'charDeleteEcho': True, 'wordEcho': True, 'interruptOnKeyPress': True, diff --git a/src/fenrirscreenreader/screenDriver/vcsaDriver.py b/src/fenrirscreenreader/screenDriver/vcsaDriver.py index ca696534..9774baf6 100644 --- a/src/fenrirscreenreader/screenDriver/vcsaDriver.py +++ b/src/fenrirscreenreader/screenDriver/vcsaDriver.py @@ -34,6 +34,11 @@ class driver(screenDriver): 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 + os.system('sysctl dev.tty.legacy_tiocsti=1') + except: + pass def initialize(self, environment): self.env = environment self.env['runtime']['attributeManager'].appendDefaultAttributes([ @@ -95,8 +100,23 @@ class driver(screenDriver): 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) - - def updateWatchdog(self,active , eventQueue): + def readFile(self, file): + d = b'' + file.seek(0) + try: + d = file.read() + except: + file.seek(0) + while True: + # Read from file + try: + d += file.readline(1) + if not d: + break + except Exception as e: + break + return d + def updateWatchdog(self, active , eventQueue): try: useVCSU = os.access('/dev/vcsu', os.R_OK) vcsa = {} @@ -111,7 +131,7 @@ class driver(screenDriver): index = str(vcsaDev[9:]) vcsa[index] = open(vcsaDev,'rb') if index == currScreen: - lastScreenContent = vcsa[index].read() + lastScreenContent = self.readFile(vcsa[index]) if useVCSU: vcsuDevices = glob.glob('/dev/vcsu*') for vcsuDev in vcsuDevices: @@ -143,13 +163,13 @@ class driver(screenDriver): oldScreen = currScreen try: vcsa[currScreen].seek(0) - lastScreenContent = vcsa[currScreen].read() + lastScreenContent = self.readFile(vcsa[currScreen]) except: pass vcsuContent = None if useVCSU: vcsu[currScreen].seek(0) - vcsuContent = vcsu[currScreen].read() + vcsuContent = self.readFile(vcsu[currScreen]) eventQueue.put({"Type":fenrirEventType.ScreenChanged, "Data":self.createScreenEventData(currScreen, lastScreenContent, vcsuContent) }) @@ -157,7 +177,7 @@ class driver(screenDriver): self.env['runtime']['debug'].writeDebugOut('ScreenUpdate',debug.debugLevel.INFO) vcsa[currScreen].seek(0) time.sleep(0.01) - dirtyContent = vcsa[currScreen].read() + dirtyContent = self.readFile(vcsa[currScreen]) screenContent = dirtyContent vcsuContent = None timeout = time.time() @@ -183,7 +203,7 @@ class driver(screenDriver): #if not vcsa[currScreen] in r: # break vcsa[currScreen].seek(0) - dirtyContent = vcsa[currScreen].read() + dirtyContent = self.readFile(vcsa[currScreen]) if screenContent == dirtyContent: break if time.time() - timeout >= 0.1: @@ -191,7 +211,7 @@ class driver(screenDriver): break if useVCSU: vcsu[currScreen].seek(0) - vcsuContent = vcsu[currScreen].read() + vcsuContent = self.readFile(vcsu[currScreen]) lastScreenContent = screenContent eventQueue.put({"Type":fenrirEventType.ScreenUpdate, "Data":self.createScreenEventData(currScreen, screenContent, vcsuContent) diff --git a/tools/configure_pipewire.sh b/tools/configure_pipewire.sh new file mode 100755 index 00000000..0f079da7 --- /dev/null +++ b/tools/configure_pipewire.sh @@ -0,0 +1,275 @@ +#!/bin/bash + +# This script configures pipewire to work both in the graphical environment and in the console with root apps. + +if [[ $(whoami) != "root" ]]; then +# Get the current user's XDG_HOME +xdgPath="${XDG_CONFIG_HOME:-$HOME/.config}" +mkdir -p "$xdgPath/pipewire" +mkdir -p "$xdgPath/wireplumber/main.lua.d" +mkdir -p "$xdgPath/wireplumber/bluetooth.lua.d" + +#create the file that tells the pipewire-pulse server to use a second socket located at /tmp/pulse.sock +# Warn user if we are going to overwrite an existing pipewire-pulse.conf +if [ -f "$xdgPath/pipewire/pipewire-pulse.conf" ]; then + read -p "This will replace the current file located at $xdgPath/pipewire/pipewire-pulse.conf, press enter to continue or control+c to abort. " continue +fi +cat << "EOF" > "$xdgPath/pipewire/pipewire-pulse.conf" +# PulseAudio config file for PipeWire version "0.3.49" # +# +# Copy and edit this file in /etc/pipewire for system-wide changes +# or in ~/.config/pipewire for local changes. +# +# It is also possible to place a file with an updated section in +# /etc/pipewire/pipewire-pulse.conf.d/ for system-wide changes or in +# ~/.config/pipewire/pipewire-pulse.conf.d/ for local changes. +# + +context.properties = { + ## Configure properties in the system. + #mem.warn-mlock = false + #mem.allow-mlock = true + #mem.mlock-all = false + #log.level = 2 + + #default.clock.quantum-limit = 8192 +} + +context.spa-libs = { + audio.convert.* = audioconvert/libspa-audioconvert + support.* = support/libspa-support +} + +context.modules = [ + { name = libpipewire-module-rt + args = { + nice.level = -11 + #rt.prio = 88 + #rt.time.soft = -1 + #rt.time.hard = -1 + } + flags = [ ifexists nofail ] + } + { name = libpipewire-module-protocol-native } + { name = libpipewire-module-client-node } + { name = libpipewire-module-adapter } + { name = libpipewire-module-metadata } + + { name = libpipewire-module-protocol-pulse + args = { + # contents of pulse.properties can also be placed here + # to have config per server. + } + } +] + +# Extra modules can be loaded here. Setup in default.pa can be moved here +context.exec = [ + { path = "pactl" args = "load-module module-always-sink" } + { path = "pactl" args = "load-module module-switch-on-connect" } + #{ path = "/usr/bin/sh" args = "~/.config/pipewire/default.pw" } +] + +stream.properties = { + #node.latency = 1024/48000 + #node.autoconnect = true + #resample.quality = 4 + #channelmix.normalize = false + #channelmix.mix-lfe = false + #channelmix.upmix = true + #channelmix.upmix-method = simple # none, psd + #channelmix.lfe-cutoff = 120 + #channelmix.fc-cutoff = 6000 + #channelmix.rear-delay = 12.0 + #channelmix.stereo-widen = 0.1 + #channelmix.hilbert-taps = 0 +} + +pulse.properties = { + # the addresses this server listens on + server.address = [ + "unix:native" + "unix:/tmp/pulse.sock" # absolute paths may be used + #"tcp:4713" # IPv4 and IPv6 on all addresses + #"tcp:[::]:9999" # IPv6 on all addresses + #"tcp:127.0.0.1:8888" # IPv4 on a single address + # + #{ address = "tcp:4713" # address + # max-clients = 64 # maximum number of clients + # listen-backlog = 32 # backlog in the server listen queue + # client.access = "restricted" # permissions for clients + #} + ] + #pulse.min.req = 256/48000 # 5ms + #pulse.default.req = 960/48000 # 20 milliseconds + #pulse.min.frag = 256/48000 # 5ms + #pulse.default.frag = 96000/48000 # 2 seconds + #pulse.default.tlength = 96000/48000 # 2 seconds + #pulse.min.quantum = 256/48000 # 5ms + #pulse.default.format = F32 + #pulse.default.position = [ FL FR ] + # These overrides are only applied when running in a vm. + vm.overrides = { + pulse.min.quantum = 1024/48000 # 22ms + } +} + +# client/stream specific properties +pulse.rules = [ + { + matches = [ + { + # all keys must match the value. ~ starts regex. + #client.name = "Firefox" + #application.process.binary = "teams" + #application.name = "~speech-dispatcher.*" + } + ] + actions = { + update-props = { + #node.latency = 512/48000 + } + # Possible quirks:" + # force-s16-info forces sink and source info as S16 format + # remove-capture-dont-move removes the capture DONT_MOVE flag + #quirks = [ ] + } + } + { + # skype does not want to use devices that don't have an S16 sample format. + matches = [ + { application.process.binary = "teams" } + { application.process.binary = "skypeforlinux" } + ] + actions = { quirks = [ force-s16-info ] } + } + { + # firefox marks the capture streams as don't move and then they + # can't be moved with pavucontrol or other tools. + matches = [ { application.process.binary = "firefox" } ] + actions = { quirks = [ remove-capture-dont-move ] } + } + { + # speech dispatcher asks for too small latency and then underruns. + matches = [ { application.name = "~speech-dispatcher*" } ] + actions = { + update-props = { + pulse.min.req = 1024/48000 # 21ms + pulse.min.quantum = 1024/48000 # 21ms + } + } + } +] +EOF + +#Creates the file that tells pipewire not to suspend any sinks for all devices. This makes sure audio doesn't die after switching to the console. +# Warn user if we are going to overwrite an existing 50-do-not-suspend.lua +if [ -f "$xdgPath/wireplumber/main.lua.d/50-do-not-suspend.lua" ]; then + read -p "This will replace the current file located at $xdgPath/wireplumber/main.lua.d/50-do-not-suspend.lua, press enter to continue or control+c to abort. " continue +fi +echo 'alsa_monitor.rules = { + { + matches = { + { + { "device.name", "matches", "alsa_card.*" }, + }, + }, + apply_properties = { + ["api.alsa.use-acp"] = true, + ["api.acp.auto-profile"] = false, + ["api.acp.auto-port"] = false, +["session.suspend-timeout-seconds"] = 0 + }, + }, + { + matches = { + { + { "node.name", "matches", "alsa_input.*" }, + }, + { + { "node.name", "matches", "alsa_output.*" }, + }, + }, + apply_properties = { + ["session.suspend-timeout-seconds"] = 0 + }, + }, +}' > $xdgPath/wireplumber/main.lua.d/50-do-not-suspend.lua + +#Creates the file that disables the logind module for wireplumber which causes bluetooth to disconnect when switching tty +# Warn user if we are going to overwrite an existing 30-bluez-monitor.lua +if [ -f "$xdgPath/wireplumber/bluetooth.lua.d/30-bluez-monitor.lua" ]; then + read -p "This will replace the current file located at $xdgPath/wireplumber/bluetooth.lua.d/30-bluez-monitor.lua, press enter to continue or control+c to abort. " continue +fi +echo 'bluez_monitor = {} +bluez_monitor.properties = {} +bluez_monitor.rules = {} + +function bluez_monitor.enable() + load_monitor("bluez", { + properties = bluez_monitor.properties, + rules = bluez_monitor.rules, + }) + +end' > $xdgPath/wireplumber/bluetooth.lua.d/30-bluez-monitor.lua + +echo "Please ensure that your user is added to the audio group." +echo "If you have not yet done so, please run this script as root to write the client.conf file." +else +# This section does the root part: +xdgPath="/root/.config" +mkdir -p "$xdgPath/pulse" + +# Warn user if we are going to overwrite an existing default.pa +if [ -f "$xdgPath/pulse/default.pa" ]; then + read -p "This will replace the current file located at $xdgPath/pulse/default.pa, press enter to continue or control+c to abort. " continue +fi + +cat << EOF > "$xdgPath/pulse/client.conf" +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, see . + +## Configuration file for PulseAudio clients. See pulse-client.conf(5) for +## more information. Default values are commented out. Use either ; or # for +## commenting. + +; default-sink = +; default-source = +default-server = unix:/tmp/pulse.sock +; default-dbus-server = + +autospawn = no +; autospawn = yes +; daemon-binary = /usr/bin/pulseaudio +; extra-arguments = --log-target=syslog + +; cookie-file = + +; enable-shm = yes +; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB + +; auto-connect-localhost = no +; auto-connect-display = no +EOF +echo "If you have not yet done so, run this script as your normal user to write the user configs" +fi + +# If there were no errors tell user to restart, else warn them errors happened. +if [ $? -eq 0 ]; then +echo "Configuration created successfully, please restart both Pipewire-pulseaudio and Wireplumber or your system, for changes to take affect." +else +echo "Errors were encountered whilst writing the configuration, please correct them manually." +fi +exit 0 diff --git a/tools/configure_pulse.sh b/tools/configure_pulse.sh index 150ded1e..bad5f107 100755 --- a/tools/configure_pulse.sh +++ b/tools/configure_pulse.sh @@ -5,6 +5,7 @@ if [[ $(whoami) != "root" ]]; then # Get the current user's XDG_HOME xdgPath="${XDG_CONFIG_HOME:-$HOME/.config}" +mkdir -p "$xdgPath/pulse" # Warn user if we are going to overwrite an existing default.pa if [ -f "$xdgPath/pulse/default.pa" ]; then diff --git a/tools/fenrir-conf b/tools/fenrir-conf old mode 100644 new mode 100755 index 99b571ac..16c5c6a5 --- a/tools/fenrir-conf +++ b/tools/fenrir-conf @@ -1,216 +1,66 @@ -#!/bin/bash +#!/usr/bin/env python3 + +# Fenrir TTY screen reader +# By Chrys, Storm Dragon, and contributers. -# Get user input args are return variable, question, options -get_input() -{ -# Variable names are long, because we want absolutely no name conflicts. -local __get_input_input=$1 -shift -local __get_input_question="$1" -shift -local __get_input_answer="" -local __get_input_i="" -local __get_input_continue=false -for __get_input_i in $@; do -if [ "${__get_input_i:0:1}" = "-" ]; then -local __get_input_default="${__get_input_i:1}" -fi -done -while [ $__get_input_continue = false ]; do -echo -n "$__get_input_question (${@/#-/}) " -if [ -n "$__get_input_default" ]; then -read -e -i "$__get_input_default" __get_input_answer -else -read -e __get_input_answer -fi -for __get_input_i in $@; do -if [ "$__get_input_answer" = "${__get_input_i/#-/}" ]; then -__get_input_continue=true -break -fi -done -done -__get_input_answer="${__get_input_answer//no/False}" -__get_input_answer="${__get_input_answer//yes/True}" -eval $__get_input_input="'$__get_input_answer'" -} -configFile="/etc/fenrirscreenreader/settings/settings.conf" +import os +import configparser +import dialog -if [ "$(whoami)" != "root" ]; then -echo "Please run $0 as root." -exit 1 -fi +# Make sure dialog is accessible +os.environ['DIALOGOPTS'] = '--no-lines --visit-items' +# Initialize the dialog +tui = dialog.Dialog(dialog="dialog") -if [ -f "$configFile" ]; then -read -p "This will replace your current settings, press enter to continue or control+C to abort." continue -fi +# Define the path to the settings file +settings_file = '/etc/fenrirscreenreader/settings/settings.conf' -get_input sound "Enable sound?" -yes no -if [ "$sound" = "true" ]; then -get_input soundDriver "Select sound driver:" -generic gstreamer -else -soundDriver="generic" -fi -get_input speech "Enable speech?" -yes no -if [ "$speech" = "true" ]; then -get_input speechDriver "Select speech driver:" espeak -speechd -else -speechDriver="speechd" -fi -get_input charEcho "enable character echo?" -yes no -get_input wordEcho "enable word echo?" yes -no +# Check write permissions for the settings file +if not os.access(settings_file, os.W_OK): + tui.msgbox("Error: Insufficient permissions to modify the settings file. Please run as root or with sudo.") + exit() -cat << EOF > "$configFile" -[sound] -# Turn sound on or off: -enabled=$sound +while True: + # Load the settings file + config = configparser.ConfigParser() + config.read(settings_file) -# Select the driver used to play sounds, choices are generic and gstreamer. -# Sox is the default. -driver=$soundDriver + # Get a list of sections in the settings file + sections = config.sections() -# Sound themes. These are the pack of sounds used for sound alerts. -# Sound packs may be located at /usr/share/sounds -# For system wide availability, or ~/.local/share/fenrir/sounds -# For the current user. -theme=default + # Select a section. + code, section = tui.menu("Select a section:", choices=[(s, "") for s in sections] + [("Exit", " ")]) -# Sound volume controls how loud the sounds for your chosen soundpack are. -# 0 is quietest, 1.0 is loudest. -volume=1.0 + # Exit if the "Exit" option is chosen + if section == "Exit": + break -# shell commands for generic sound driver -# the folowing variables are substituted -# fenrirVolume = the current volume setting -# fenrirSoundFile = the soundfile for an soundicon -# fenrirFrequence = the frequence to play -# fenrirDuration = the duration of the frequency -# the following command is used for play a soundfile -genericPlayFileCommand=play -q -v fenrirVolume fenrirSoundFile -#the following command is used for generating a frequency beep -genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence + while True: + # Get the options in the selected section + options = config.options(section) -[speech] -# Turn speech on or off: -enabled=$speech + # Select a value to edit using dialog + code, option = tui.menu(f"Select a value to edit in '{section}':", choices=[(o, "") for o in options] + [("Go Back", " ")]) -# Select speech driver, options are speechd (default) or espeak: -driver=$speechDriver + # Go back to the section menu if the "Go Back" option is chosen + if option == "Go Back": + break + # If something is selected, prompt for a new value. + if code == tui.OK: + value = config.get(section, option) + code, new_value = tui.inputbox(f"Enter a new value for '{option}':", init=value) -# The rate selects how fast Fenrir will speak. Options range from 0, slowest, to 1.0, fastest. -rate=0.45 + # If a new setting is provided, update the configuration + if code == tui.OK: + config.set(section, option, new_value) -# Pitch controls the pitch of the voice, select from 0, lowest, to 1.0, highest. -pitch=0.5 -# Pitch for capital letters -capitalPitch=0.9 + # Save changes. + with open(settings_file, 'w') as configfile: + config.write(configfile) -# Volume controls the loudness of the voice, select from 0, quietest, to 1.0, loudest. -volume=1.0 - -# Module is used for Speech-dispatcher, to select the speech module you want to use. -# Consult Speech-dispatcher's configuration and help to find out which modules are available. -# The default is Espeak. -module=espeak - -# Voice selects the varient you want to use, for example, f5 will use the female voice #5 in espeak, -# or if using the espeak module in Speech-dispatcher. To find out which voices are available, consult the documentation provided with your selected synthesizer. -voice= - -# Select the language you want Fenrir to use. -language=english-us - -# Read new text as it happens? -autoReadIncoming=True - -[braille] -#Braille is not implemented yet -enabled=False -driver=brlapi -layout=en - -[screen] -driver=vcsa -encoding=auto -autodetectSuspendingScreen=True - -[keyboard] -driver=evdev -# filter input devices NOMICE, ALL or a DEVICE NAME -device=ALL -# gives Fenrir exclusive access to the keyboard and lets it absorb keystrokes. -grabDevices=True -ignoreShortcuts=False -# the current shortcut layout located in /etc/fenrir/keyboard -keyboardLayout=$keyboard -# echo chars while typing. -charEcho=$charEcho -# echo deleted chars -charDeleteEcho=True -# echo word after pressing space -wordEcho=$wordEcho -# interrupt speech on any keypress -interruptOnKeyPress=$enterupt -# you can filter the keys that the speech should interrupt (empty = all keys, otherwise the given keys) -interruptOnKeyPressFilter= -# timeout for double tap in sec -doubleTapTimeout=0.2 - -[general] -debugLevel=0 -# debugMode sets where the debug output should send to: -# debugMode=File writes to /var/log/fenrir.log -# debugMode=Print just prints on the screen -debugMode=File -punctuationProfile=default -punctuationLevel=some -respectPunctuationPause=True -newLinePause=True -numberOfClipboards=10 -emoticons=True -# define the current Fenrir key -fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT -scriptKey=KEY_COMPOSE -timeFormat=%H:%M:%P -dateFormat=%A, %B %d, %Y -autoSpellCheck=True -spellCheckLanguage=en_US -scriptPath=/usr/share/fenrirscreenreader/scripts - -[focus] -#follow the text cursor -cursor=True -#follow highlighted text changes -highlight=False - -[review] -lineBreak=True -endOfScreen=True - -[promote] -enabled=True -inactiveTimeoutSec=120 -list= - -[time] -# automatic time anouncement -enabled=False -# present time -presentTime=True -# present date (on change) -presentDate=True -# present time after a given period of seconds -delaySec=0 -# present time after to given minutes example every 15 minutes: 00,15,30,45 -# if delaySec is >0 onMinutes is ignored -onMinutes=00,30 -# announce via soundicon (not interrupting) -announce=True -# interrupt current speech for time announcement -interrupt=False -EOF - -echo "Settings saved to $configFile." - -exit 0 + tui.msgbox("Fenrir settings saved.") + else: + tui.msgbox("Changes discarded. Your Fenrir configuration has not been modified.") + else: + tui.msgbox("Canceled.") diff --git a/tools/make_fenrir_user.sh b/tools/make_fenrir_user.sh index 536f630d..d97609f2 100755 --- a/tools/make_fenrir_user.sh +++ b/tools/make_fenrir_user.sh @@ -6,47 +6,6 @@ if [[ "$(whoami)" != "root" ]]; then exit 1 fi -write_pulse() { -sudo -u fenrirscreenreader cat << EOF > "/var/fenrirscreenreader/.config/pulse/client.conf" -# This file is part of PulseAudio. -# -# PulseAudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# PulseAudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with PulseAudio; if not, see . - -## Configuration file for PulseAudio clients. See pulse-client.conf(5) for -## more information. Default values are commented out. Use either ; or # for -## commenting. - -; default-sink = -; default-source = -default-server = unix:/tmp/pulse.sock -; default-dbus-server = - -autospawn = no -; autospawn = yes -; daemon-binary = /usr/bin/pulseaudio -; extra-arguments = --log-target=syslog - -; cookie-file = - -; enable-shm = yes -; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB - -; auto-connect-localhost = no -; auto-connect-display = no -EOF -} - # This script checks for, and creates if needed, the fenrirscreenreader user. # Find out which group to use for uinput @@ -75,12 +34,8 @@ if ! [[ "$tty" =~ ^[a-zA-Z]+$ ]]; then fi # Add fenrirscreenreader -id fenrirscreenreader &> /dev/null || { - useradd -m -d /var/fenrirscreenreader -r -G $input,$tty,$uinput -s /bin/nologin -U fenrirscreenreader; - sleep 1; - sudo -u fenrirscreenreader mkdir -p /var/fenrirscreenreader/.config/pulse; - write_pulse; -} +id fenrirscreenreader &> /dev/null || + useradd -m -d /var/fenrirscreenreader -r -G $input,$tty,$uinput -s /bin/nologin -U fenrirscreenreader #configure directory structure. mkdir -p /var/log/fenrirscreenreader /etc/fenrirscreenreader @@ -95,4 +50,47 @@ for i in /dev/tty[0-9]* ; do chmod 660 "$i" done +sudo -Hu fenrirscreenreader mkdir /var/fenrirscreenreader/.config/pulse + +# Set up sound +cat << EOF > /var/fenrirscreenreader/.config/pulse/client.conf +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, see . + +## Configuration file for PulseAudio clients. See pulse-client.conf(5) for +## more information. Default values are commented out. Use either ; or # for +## commenting. + +; default-sink = +; default-source = +default-server = unix:/tmp/pulse.sock +; default-dbus-server = + +autospawn = no +; autospawn = yes +; daemon-binary = /usr/bin/pulseaudio +; extra-arguments = --log-target=syslog + +; cookie-file = + +; enable-shm = yes +; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB + +; auto-connect-localhost = no +; auto-connect-display = no +EOF + + exit 0