diff --git a/README.md b/README.md index db1af81d..39f10454 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ ReadWrite permission - brltty, python-brlapi [using braille] # (not implemented yet) - gstreamer [soundicons via gstreamer] # not working yet - python-pyenchant [spell check functionality] +- aspell- [your languagedata for spellchecker, english support "aspell-en"] - python-daemonize [use fenrir as background service on Unix like systems] # installation diff --git a/TODO b/TODO index 7ca7a3f0..f5227b30 100644 --- a/TODO +++ b/TODO @@ -7,9 +7,20 @@ ToDos in Priority order: For example, in screen, it just tells me bell in window, but doesn't tell me which one. (southernprince) in special cases next word skipps a word, "word<12 spaces>word2<12 spaces>word3 (storm_dragon) spellcheck triggers twice if there are two spaces after an word and you arrow over them - -- replace beep with a digital equivalent - + fenrir is not able to detect the current application inside of screen. + +- implement onScreenUpdate commands + read highlighted text mode + +- implement commands + attributes_curr_char + generic list command (convert clipboard management) + next item + pref item + curr item + first item + last item + - implement braille output to braille device virtual buffer area for scroll left/right if the line is to long for device @@ -24,37 +35,16 @@ ToDos in Priority order: tweak current commands and output http://mielke.cc/brltty/doc/Manual-BrlAPI/English/BrlAPI.html https://git.gnome.org/browse/orca/tree/src/orca/braille.py -https://wiki.gnome.org/Attic/LSR/ScratchPad/Braille/BrlAPI +https://wiki.gnome.org/Attic/LSR/ScratchPad/Braille/BrlAPI + +- implement autodetection of plugged and removed input devices (python-pyudev) +http://askubuntu.com/questions/508236/how-can-i-run-code-whenever-a-usb-device-is-unplugged-without-requiring-root - add perApplicationTrigger trigger per application commands per application onScreenChange per application onInput - per application shortcuts -- implement commands - next_char_phonetic - prev_char_phonetic - next_word_phonetic - prev_word_phonetic - attributes_curr_char - - toggle_highlighted_mode - generic list command (convert clipboard management) - next item - pref item - curr item - first item - last item - -- implement onScreenUpdate commands - read highlighted text mode -- add the debugging to core -- autostart systemd -https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/sect-Managing_Services_with_systemd-Unit_Files.html - -- implement autodetection of plugged and removed input devices (python-pyudev) -http://askubuntu.com/questions/508236/how-can-i-run-code-whenever-a-usb-device-is-unplugged-without-requiring-root - - configuration should be overwriteable with parameter and alternative paths - write settings - menue for settings configuration #storm @@ -201,6 +191,11 @@ ps a -o tty,comm | grep -e Xorg | grep -v "grep -e Xorg" "papa", "quebec", "romeo", "sierra", "tango", "uniform", "victor", "whisky", "x ray", "yankee", "zulu" + next_char_phonetic + prev_char_phonetic + next_word_phonetic + prev_word_phonetic + toggle_highlighted_mode - implement onInput commands read_line_if_cursor_change_vertical (needed if you arrow up and down, we want to announce the line) @@ -208,7 +203,8 @@ ps a -o tty,comm | grep -e Xorg | grep -v "grep -e Xorg" echo_char (echos the last char on pressing space or return) echo_word (echos the last word) echo_deleted_char (echos deleted char on screen - + read highlighted + - implement onScreenChange commands promoted text clear_marks_on_screen_change @@ -256,3 +252,7 @@ https://web.archive.org/web/20131017130434/http://www.jejik.com/articles/2007/02 - announce capslock - anounce numlock - anounce scroll +- add the debugging to core + +- autostart systemd +https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/sect-Managing_Services_with_systemd-Unit_Files.html diff --git a/config/keyboard/desktop.conf b/config/keyboard/desktop.conf index 99f2e789..0eb82837 100644 --- a/config/keyboard/desktop.conf +++ b/config/keyboard/desktop.conf @@ -75,6 +75,7 @@ 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_KPASTERISK=toggle_highlight_tracking KEY_FENRIR,KEY_Q=quit_fenrir KEY_FENRIR,KEY_T=time 2,KEY_FENRIR,KEY_T=date diff --git a/config/keyboard/laptop.conf b/config/keyboard/laptop.conf index 7b19304f..be214ad7 100644 --- a/config/keyboard/laptop.conf +++ b/config/keyboard/laptop.conf @@ -75,6 +75,7 @@ KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check KEY_FENRIR,KEY_SHIFT,KEY_ENTER=toggle_output KEY_FENRIR,KEY_SHIFT,KEY_E=toggle_emoticons KEY_FENRIR,KEY_ENTER=toggle_auto_read +KEY_FENRIR,KEY_Y=toggle_highlight_tracking KEY_FENRIR,KEY_Q=quit_fenrir KEY_FENRIR,KEY_T=time 2,KEY_FENRIR,KEY_T=date diff --git a/config/keyboard/test.conf b/config/keyboard/test.conf index c882114d..2c1e4867 100644 --- a/config/keyboard/test.conf +++ b/config/keyboard/test.conf @@ -75,6 +75,7 @@ KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check KEY_FENRIR,KEY_BACKSLASH=toggle_output #=toggle_emoticons key_FENRIR,KEY_KPENTER=toggle_auto_read +#=toggle_highlight_tracking KEY_FENRIR,KEY_Q=quit_fenrir KEY_FENRIR,KEY_T=time 2,KEY_FENRIR,KEY_T=date diff --git a/config/settings/settings.conf b/config/settings/settings.conf index 4c2e50ef..4053ce65 100644 --- a/config/settings/settings.conf +++ b/config/settings/settings.conf @@ -77,9 +77,9 @@ autodetectSuspendingScreen=True [keyboard] driver=evdev -# filter input devices AUTO, ALL or a DEVICE NAME -device=AUTO -# gives fenrir exclusive access to the keyboard and let consume keystrokes. just disable on problems. +# filter input devices NOMICE, ALL or a DEVICE NAME +device=ALL +# gives fenrir exclusive access to the keyboard and let consume keystrokes. grabDevices=True ignoreShortcuts=False # the current shortcut layout located in /etc/fenrir/keyboard @@ -110,7 +110,13 @@ timeFormat=%H:%M:%P dateFormat=%A, %B %d, %Y autoSpellCheck=True spellCheckLanguage=en_US -scriptPath=/etc/fenrir/scripts +scriptPath=/usr/share/fenrir/scripts + +[focus] +#follow the text cursor +cursor=True +#follow highlighted text changes +highlight=False [promote] enabled=True diff --git a/config/settings/settings.conf.chrys b/config/settings/settings.conf.chrys index d690dffc..ba13d46a 100644 --- a/config/settings/settings.conf.chrys +++ b/config/settings/settings.conf.chrys @@ -77,8 +77,8 @@ autodetectSuspendingScreen=True [keyboard] driver=evdev -# filter input devices AUTO, ALL or a DEVICE NAME -device=AUTO +# filter input devices NOMICE, ALL or a DEVICE NAME +device=ALL # gives fenrir exclusive access to the keyboard and let consume keystrokes. just disable on problems. grabDevices=True ignoreShortcuts=False @@ -110,7 +110,13 @@ timeFormat=%H:%M:%P dateFormat=%A, %B %d, %Y autoSpellCheck=True spellCheckLanguage=en_US -scriptPath=/etc/fenrir/scripts +scriptPath=/usr/share/fenrir/scripts + +[focus] +#follow the text cursor +cursor=True +#follow highlighted text changes +highlight=False [promote] enabled=True diff --git a/config/settings/settings.conf.storm b/config/settings/settings.conf.storm index 1fbe784e..4d2a2c3a 100644 --- a/config/settings/settings.conf.storm +++ b/config/settings/settings.conf.storm @@ -34,8 +34,8 @@ autodetectSuspendingScreen=False [keyboard] driver=evdev -# filter input devices AUTO, ALL or a DEVICE NAME -device=AUTO +# filter input devices NOMICE, ALL or a DEVICE NAME +device=ALL grabDevices=True ignoreShortcuts=False keyboardLayout=desktop @@ -60,7 +60,14 @@ timeFormat=%H:%M:%P dateFormat="%A, %B %d, %Y" autoSpellCheck=True spellCheckLanguage=en_US -scriptPath=/etc/fenrir/scripts +scriptPath=/usr/share/fenrir/scripts + +[focus] +#follow the text cursor +cursor=True +#follow highlighted text changes +highlight=False + [promote] enabled=True diff --git a/contrib/fenrir-git/PKGBUILD b/contrib/fenrir-git/PKGBUILD index 09fbdcf5..73c71042 100644 --- a/contrib/fenrir-git/PKGBUILD +++ b/contrib/fenrir-git/PKGBUILD @@ -3,17 +3,19 @@ _gitname='fenrir' pkgname="${_gitname}-git" -pkgver=v0.1.2.gb72614a -pkgrel=1 +pkgver=v0.2.5.g33af5b6 +pkgrel=3 pkgdesc='A user space console screen reader written in python3' arch=('any') url='https://github.com/chrys87/${_pkgname}' license=('MIT') -depends=('python' 'python-espeak' 'python-evdev') +depends=('python' 'python-daemonize' 'python-evdev') optdepends=('brltty: For Braille support' - 'gstreamer: for soundicons via gstreamer' +'gstreamer: for soundicons via gstreamer' 'sox: The default sound driver' - 'python-enchant: for spell check functionality') + 'python-espeak: TTS support' + 'python-pyenchant: for spell check functionality' + 'speech-dispatcher: TTS support') makedepends=('git') provides=('fenrir') conflicts=('fenrir') @@ -21,7 +23,7 @@ install="$pkgname".install source=("git+https://github.com/chrys87/${_gitname}.git" 'fenrir-git.install') md5sums=('SKIP' - '9d1e82fce2e02ae2a1216a18ca576bfb') + '1387fd3851040d03816e2fb6b8fa631f') pkgver() { @@ -33,17 +35,19 @@ pkgver() package() { cd "$srcdir/$_gitname" - install -d "$pkgdir/usr/bin" - install -d "$pkgdir/etc/fenrir/keyboard" - install -d "$pkgdir/etc/fenrir/settings" - install -d "$pkgdir/etc/fenrir/substitution" + install -m755 -d "$pkgdir/opt/fenrir" + install -m755 -d "$pkgdir/usr/share/fenrir/scripts" + install -m755 -d "$pkgdir/usr/share/fenrir/tools" + install -m644 -D "config/keyboard/desktop.conf" "$pkgdir/etc/fenrir/keyboard/desktop.conf" + install -m644 -D "config/keyboard/laptop.conf" "$pkgdir/etc/fenrir/keyboard/laptop.conf" + install -m644 -D "config/punctuation/default.conf" "$pkgdir/etc/fenrir/punctuation/default.conf" + install -m644 -D "config/settings/settings.conf" "$pkgdir/etc/fenrir/settings/settings.conf" install -d "$pkgdir/usr/share/sounds/fenrir" install -m644 -D "autostart/systemd/fenrir.service" "$pkgdir/usr/lib/systemd/system/fenrir.service" - python setup.py install --root="${pkgdir}/" --optimize=1 - cp -a config/keyboard/* "$pkgdir/etc/fenrir/keyboard" - cp -a config/settings/* "$pkgdir/etc/fenrir/settings" + cp -a src/fenrir/* "$pkgdir/opt/fenrir" + cp -a config/scripts/* "$pkgdir/usr/share/fenrir/scripts" + cp -a tools/* "$pkgdir/usr/share/fenrir/tools" cp -a config/sound/* "$pkgdir/usr/share/sounds/fenrir" - cp -a config/substitution/* "$pkgdir/etc/fenrir/substitution" } # vim: set ts=2 sw=2 et: diff --git a/contrib/fenrir-git/fenrir-git.install b/contrib/fenrir-git/fenrir-git.install index 973d87ac..8d6d9877 100644 --- a/contrib/fenrir-git/fenrir-git.install +++ b/contrib/fenrir-git/fenrir-git.install @@ -1,4 +1,5 @@ post_install() { +ln -s /opt/fenrir/fenrir-daemon /usr/bin/fenrir _alert } @@ -6,6 +7,9 @@ _alert() { cat << EOF To have fenrir start at boot: sudo systemctl enable fenrir +Pulseaudio users may want to run +/usr/share/fenrir/tools/configure-pulseaudio +once as their user account and once as root. EOF } diff --git a/install.sh b/install.sh old mode 100644 new mode 100755 index 4bd95d5a..61795eb7 --- a/install.sh +++ b/install.sh @@ -2,16 +2,16 @@ #Basic install script for fenrir. read -p "This will install fenrir. Press ctrl+c to cancil, or enter to continue." continue install -m755 -d /opt/fenrir - install -m755 -d /usr/share/fenrir/scripts - install -m644 -D "config/keyboard/desktop.conf" /etc/fenrir/keyboard/desktop.conf" - install -m644 -D "config/keyboard/desktop.conf" /etc/fenrir/keyboard/desktop.conf - install -m644 -D "config/punctuation/default.conf" /etc/fenrir/punctuation/default.conf - install -m644 -D "config/settings/settings.conf" /etc/fenrir/settings/settings.conf - install -d /usr/share/sounds/fenrir - install -m644 -D "autostart/systemd/fenrir.service" /usr/lib/systemd/system/fenrir.service - cp -a src/fenrir/* /opt/fenrir - cp -a config/scripts/* /usr/share/fenrir/scripts - cp -a config/sound/* /usr/share/sounds/fenrir +install -m755 -d /usr/share/fenrir/scripts +install -m644 -D "config/keyboard/desktop.conf" /etc/fenrir/keyboard/desktop.conf +install -m644 -D "config/keyboard/desktop.conf" /etc/fenrir/keyboard/desktop.conf +install -m644 -D "config/punctuation/default.conf" /etc/fenrir/punctuation/default.conf +install -m644 -D "config/settings/settings.conf" /etc/fenrir/settings/settings.conf +install -d /usr/share/sounds/fenrir +install -m644 -D "autostart/systemd/fenrir.service" /usr/lib/systemd/system/fenrir.service +cp -a src/fenrir/* /opt/fenrir +cp -a config/scripts/* /usr/share/fenrir/scripts +cp -a config/sound/* /usr/share/sounds/fenrir ln -s /opt/fenrir/fenrir-daemon /usr/bin/fenrir cat << EOF To have fenrir start at boot: diff --git a/src/fenrir/commands/commands/toggle_highlight_tracking.py b/src/fenrir/commands/commands/toggle_highlight_tracking.py new file mode 100644 index 00000000..6a987d9b --- /dev/null +++ b/src/fenrir/commands/commands/toggle_highlight_tracking.py @@ -0,0 +1,29 @@ +#!/bin/python +# -*- coding: utf-8 -*- + +# Fenrir TTY screen reader +# By Chrys, Storm Dragon, and contributers. + +from core import debug +class command(): + def __init__(self): + pass + def initialize(self, environment): + self.env = environment + def shutdown(self): + pass + def getDescription(self): + return 'enables or disables tracking of highlighted' + + def run(self): + currMode=self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'highlight') + + self.env['runtime']['settingsManager'].setSetting('focus', 'highlight', str(not currMode)) + self.env['runtime']['settingsManager'].setSetting('focus', 'cursor', str(currMode)) + if self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'highlight'): + self.env['runtime']['outputManager'].presentText("highlight tracking", soundIcon='', interrupt=True) + else: + self.env['runtime']['outputManager'].presentText("cursor tracking", soundIcon='', interrupt=True) + + def setCallback(self, callback): + pass diff --git a/src/fenrir/commands/onInput/45000-present_char_if_cursor_change_horizontal.py b/src/fenrir/commands/onInput/45000-present_char_if_cursor_change_horizontal.py index 52890f3c..0926b53e 100644 --- a/src/fenrir/commands/onInput/45000-present_char_if_cursor_change_horizontal.py +++ b/src/fenrir/commands/onInput/45000-present_char_if_cursor_change_horizontal.py @@ -18,6 +18,8 @@ class command(): return '' def run(self): + if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'cursor'): + return if self.env['runtime']['screenManager'].isScreenChange(): return if self.env['runtime']['inputManager'].noKeyPressed(): diff --git a/src/fenrir/commands/onInput/55000-present_line_if_cursor_change_vertical.py b/src/fenrir/commands/onInput/55000-present_line_if_cursor_change_vertical.py index ce95e65e..14a840c3 100644 --- a/src/fenrir/commands/onInput/55000-present_line_if_cursor_change_vertical.py +++ b/src/fenrir/commands/onInput/55000-present_line_if_cursor_change_vertical.py @@ -18,6 +18,8 @@ class command(): return '' def run(self): + if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'cursor'): + return if self.env['runtime']['inputManager'].noKeyPressed(): return if self.env['runtime']['screenManager'].isScreenChange(): diff --git a/src/fenrir/commands/onInput/56000-highlight_tracking.py b/src/fenrir/commands/onInput/56000-highlight_tracking.py new file mode 100644 index 00000000..4f75f498 --- /dev/null +++ b/src/fenrir/commands/onInput/56000-highlight_tracking.py @@ -0,0 +1,24 @@ +#!/bin/python +# -*- coding: utf-8 -*- + +# Fenrir TTY screen reader +# By Chrys, Storm Dragon, and contributers. + +from core import debug +class command(): + def __init__(self): + pass + def initialize(self, environment): + self.env = environment + def shutdown(self): + pass + def getDescription(self): + return 'enables or disables tracking of highlighted' + + def run(self): + if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'highlight'): + return + self.env['runtime']['outputManager'].presentText(self.env['screenData']['newAttribDelta'], soundIcon='', interrupt=True) + + def setCallback(self, callback): + pass diff --git a/src/fenrir/commands/onInput/72000-history.py b/src/fenrir/commands/onInput/72000-history.py index 41ac8a4e..4437ce7a 100644 --- a/src/fenrir/commands/onInput/72000-history.py +++ b/src/fenrir/commands/onInput/72000-history.py @@ -18,7 +18,9 @@ class command(): def run(self): if self.env['runtime']['inputManager'].noKeyPressed(): - return + return + if self.env['screenData']['newAttribDelta'] != '': + return if self.env['runtime']['screenManager'].isScreenChange(): return if self.env['runtime']['cursorManager'].isCursorVerticalMove(): @@ -29,9 +31,7 @@ class command(): return prevLine = self.env['screenData']['oldContentText'].split('\n')[self.env['screenData']['newCursor']['y']] currLine = self.env['screenData']['newContentText'].split('\n')[self.env['screenData']['newCursor']['y']] - if currLine.isspace(): - self.env['runtime']['outputManager'].presentText("blank", soundIcon='EmptyLine', interrupt=True) - else: + if not currLine.isspace(): currPrompt = currLine.find('$') rootPrompt = currLine.find('#') if currPrompt <= 0: diff --git a/src/fenrir/core/cursorManager.py b/src/fenrir/core/cursorManager.py index 1fcaad0a..4995a167 100644 --- a/src/fenrir/core/cursorManager.py +++ b/src/fenrir/core/cursorManager.py @@ -63,7 +63,12 @@ class cursorManager(): self.env['screenData']['oldCursorReview'] = self.env['screenData']['newCursorReview'] if not self.env['screenData']['newCursorReview']: self.env['screenData']['newCursorReview'] = self.env['screenData']['newCursor'].copy() - + if self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'highlight') and \ + self.env['screenData']['newCursorAttrib'] != None: + if self.env['screenData']['newCursorAttrib']['x'] != 0 and \ + self.env['screenData']['newCursorAttrib']['y'] != 0: + self.env['screenData']['newCursorReview'] = self.env['screenData']['newCursorAttrib'].copy() + def setReviewCursorPosition(self, x, y): if not self.isReviewMode(): self.enterReviewModeCurrTextCursor() diff --git a/src/fenrir/core/inputManager.py b/src/fenrir/core/inputManager.py index a8464fda..fbd300db 100644 --- a/src/fenrir/core/inputManager.py +++ b/src/fenrir/core/inputManager.py @@ -43,7 +43,7 @@ class inputManager(): if len(self.env['input']['currInput']) == 0: self.env['input']['prevDeepestInput'] = [] self.env['input']['shortcutRepeat'] = 1 - self.handleLedStates(mEvent) + self.setLedState = self.handleLedStates(mEvent) self.env['input']['lastInputTime'] = time.time() elif mEvent['EventState'] == 1: if not mEvent['EventName'] in self.env['input']['currInput']: @@ -57,7 +57,7 @@ class inputManager(): self.env['input']['shortcutRepeat'] += 1 else: self.env['input']['shortcutRepeat'] = 1 - self.handleLedStates(mEvent) + self.setLedState = self.handleLedStates(mEvent) self.env['input']['lastInputTime'] = time.time() elif mEvent['EventState'] == 2: self.env['input']['lastInputTime'] = time.time() @@ -77,34 +77,29 @@ class inputManager(): def handleLedStates(self, mEvent): if not self.setLedState: - return + return self.setLedState if mEvent['EventName'] == 'KEY_NUMLOCK': if mEvent['EventState'] == 1 and not self.env['input']['newNumLock'] == 1: self.env['runtime']['inputDriver'].toggleLedState() - self.setLedState = False - return + return False if mEvent['EventState'] == 0 and not self.env['input']['newNumLock'] == 0: - self.env['runtime']['inputDriver'].toggleLedState() - self.setLedState = False - return + self.env['runtime']['inputDriver'].toggleLedState() + return False if mEvent['EventName'] == 'KEY_CAPSLOCK': if mEvent['EventState'] == 1 and not self.env['input']['newCapsLock'] == 1: - self.env['runtime']['inputDriver'].toggleLedState(1) - self.setLedState = False - return + self.env['runtime']['inputDriver'].toggleLedState(1) + return False if mEvent['EventState'] == 0 and not self.env['input']['newCapsLock'] == 0: - self.env['runtime']['inputDriver'].toggleLedState(1) - self.setLedState = False - return + self.env['runtime']['inputDriver'].toggleLedState(1) + return False if mEvent['EventName'] == 'KEY_SCROLLLOCK': if mEvent['EventState'] == 1 and not self.env['input']['newScrollLock'] == 1: - self.env['runtime']['inputDriver'].toggleLedState(2) - self.setLedState = False - return + self.env['runtime']['inputDriver'].toggleLedState(2) + return False if mEvent['EventState'] == 0 and not self.env['input']['newScrollLock'] == 0: - self.env['runtime']['inputDriver'].toggleLedState(2) - self.setLedState = False - return + self.env['runtime']['inputDriver'].toggleLedState(2) + return False + return self.setLedState def grabDevices(self): if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'): @@ -168,10 +163,10 @@ class inputManager(): self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR) def isFenrirKeyPressed(self): - return 'KEY_FENRIR' in self.env['input']['currInput'] + return 'KEY_FENRIR' in self.env['input']['prevDeepestInput'] def isScriptKeyPressed(self): - return 'KEY_SCRIPT' in self.env['input']['currInput'] + return 'KEY_SCRIPT' in self.env['input']['prevDeepestInput'] def noKeyPressed(self): return self.env['input']['currInput'] == [] diff --git a/src/fenrir/core/screenData.py b/src/fenrir/core/screenData.py index da6e771d..d3521508 100644 --- a/src/fenrir/core/screenData.py +++ b/src/fenrir/core/screenData.py @@ -11,8 +11,10 @@ screenData = { 'columns': 0, 'lines': 0, 'oldDelta': '', +'oldAttribDelta': '', 'oldNegativeDelta': '', 'oldCursorReview':None, +'oldCursorAttrib':None, 'oldCursor':{'x':0,'y':0}, 'oldContentBytes': b'', 'oldContentText': '', @@ -21,7 +23,9 @@ screenData = { 'oldTTY':None, 'newDelta': '', 'newNegativeDelta': '', +'newAttribDelta': '', 'newCursorReview':None, +'newCursorAttrib':None, 'newCursor':{'x':0,'y':0}, 'newContentBytes': b'', 'newContentText': '', diff --git a/src/fenrir/core/settings.py b/src/fenrir/core/settings.py index 0d295577..f4c6780a 100644 --- a/src/fenrir/core/settings.py +++ b/src/fenrir/core/settings.py @@ -55,6 +55,10 @@ settings = { 'spellCheckLanguage': 'en_US', 'scriptPath':'/etc/fenrir/scripts', }, +'focus':{ + 'cursor': True, + 'highlight': False, +}, 'promote':{ 'enabled': True, 'inactiveTimeoutSec': 120, diff --git a/src/fenrir/inputDriver/evdev.py b/src/fenrir/inputDriver/evdev.py index bfe193f7..5805d346 100644 --- a/src/fenrir/inputDriver/evdev.py +++ b/src/fenrir/inputDriver/evdev.py @@ -43,8 +43,6 @@ class driver(): return currMapEvent if currMapEvent['EventState'] in [0,1,2]: return currMapEvent - - event = self.iDevices[fd].read_one() return None @@ -77,7 +75,7 @@ class driver(): if self.env['runtime']['settingsManager'].getSetting('keyboard', 'device').upper() == 'ALL': self.iDevices = {dev.fd: dev for dev in self.iDevices if 1 in dev.capabilities()} self.ledDevices = {dev.fd: dev for dev in self.ledDevices if 1 in dev.capabilities() and 17 in dev.capabilities()} - elif self.env['runtime']['settingsManager'].getSetting('keyboard', 'device').upper() == 'AUTO': + elif self.env['runtime']['settingsManager'].getSetting('keyboard', 'device').upper() == 'NOMICE': self.iDevices = {dev.fd: dev for dev in self.iDevices if 1 in dev.capabilities() and not 3 in dev.capabilities() and not 2 in dev.capabilities()} self.ledDevices = {dev.fd: dev for dev in self.ledDevices if 1 in dev.capabilities() and 17 in dev.capabilities() and not 3 in dev.capabilities() and not 2 in dev.capabilities()} else: @@ -102,10 +100,10 @@ class driver(): # 0 = Numlock # 1 = Capslock # 2 = Rollen - if self.ledDevices == {}: - return False if self.ledDevices == None: - return False + return False + if self.ledDevices == {}: + return False for fd, dev in self.ledDevices.items(): return led in dev.leds() return False diff --git a/src/fenrir/screenDriver/linux.py b/src/fenrir/screenDriver/linux.py index a471fc96..7c5d396f 100644 --- a/src/fenrir/screenDriver/linux.py +++ b/src/fenrir/screenDriver/linux.py @@ -8,6 +8,7 @@ import difflib import re import subprocess from core import debug +from utils import screen_utils class driver(): def __init__(self): @@ -16,9 +17,6 @@ class driver(): self.env = environment def shutdown(self): pass - def insert_newlines(self, string, every=64): - return '\n'.join(string[i:i+every] for i in range(0, len(string), every)) - def getCurrScreen(self): self.env['screenData']['oldTTY'] = self.env['screenData']['newTTY'] try: @@ -85,10 +83,12 @@ class driver(): # set new "old" values self.env['screenData']['oldContentBytes'] = self.env['screenData']['newContentBytes'] self.env['screenData']['oldContentText'] = self.env['screenData']['newContentText'] - self.env['screenData']['oldContentTextAttrib'] = self.env['screenData']['newContentAttrib'] - self.env['screenData']['oldCursor']['x'] = self.env['screenData']['newCursor']['x'] - self.env['screenData']['oldCursor']['y'] = self.env['screenData']['newCursor']['y'] + self.env['screenData']['oldContentAttrib'] = self.env['screenData']['newContentAttrib'] + self.env['screenData']['oldCursor'] = self.env['screenData']['newCursor'].copy() + if self.env['screenData']['newCursorAttrib']: + self.env['screenData']['oldCursorAttrib'] = self.env['screenData']['newCursorAttrib'].copy() self.env['screenData']['oldDelta'] = self.env['screenData']['newDelta'] + self.env['screenData']['oldAttribDelta'] = self.env['screenData']['newAttribDelta'] self.env['screenData']['oldNegativeDelta'] = self.env['screenData']['newNegativeDelta'] self.env['screenData']['newContentBytes'] = newContentBytes # get metadata like cursor or screensize @@ -98,8 +98,9 @@ class driver(): self.env['screenData']['newCursor']['y'] = int( self.env['screenData']['newContentBytes'][3]) # analyze content self.env['screenData']['newContentText'] = self.env['screenData']['newContentBytes'][4:][::2].decode(screenEncoding, "replace").encode('utf-8').decode('utf-8') + self.env['screenData']['newContentText'] = screen_utils.removeNonprintable(self.env['screenData']['newContentText']) self.env['screenData']['newContentAttrib'] = self.env['screenData']['newContentBytes'][5:][::2] - self.env['screenData']['newContentText'] = self.insert_newlines(self.env['screenData']['newContentText'], self.env['screenData']['columns']) + self.env['screenData']['newContentText'] = screen_utils.insertNewlines(self.env['screenData']['newContentText'], self.env['screenData']['columns']) if self.env['screenData']['newTTY'] != self.env['screenData']['oldTTY']: self.env['screenData']['oldContentBytes'] = b'' @@ -108,10 +109,15 @@ class driver(): self.env['screenData']['oldCursor']['x'] = 0 self.env['screenData']['oldCursor']['y'] = 0 self.env['screenData']['oldDelta'] = '' + self.env['screenData']['oldAttribDelta'] = '' + self.env['screenData']['oldCursorAttrib'] = None + self.env['screenData']['newCursorAttrib'] = None self.env['screenData']['oldNegativeDelta'] = '' - # always clear current deltas + # initialize current deltas self.env['screenData']['newNegativeDelta'] = '' - self.env['screenData']['newDelta'] = '' + self.env['screenData']['newDelta'] = '' + self.env['screenData']['newAttribDelta'] = '' + # changes on the screen oldScreenText = re.sub(' +',' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screenData']['oldContentText'])) newScreenText = re.sub(' +',' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screenData']['newContentText'])) @@ -145,4 +151,9 @@ class driver(): else: self.env['screenData']['newDelta'] = ''.join(x[2:] for x in diffList if x[0] == '+') self.env['screenData']['newNegativeDelta'] = ''.join(x[2:] for x in diffList if x[0] == '-') + + # track highlighted + if self.env['screenData']['oldContentAttrib'] != self.env['screenData']['newContentAttrib']: + if self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'highlight'): + self.env['screenData']['newAttribDelta'], self.env['screenData']['newCursorAttrib'] = screen_utils.trackHighlights(self.env['screenData']['oldContentAttrib'], self.env['screenData']['newContentAttrib'], self.env['screenData']['newContentText'], self.env['screenData']['columns']) diff --git a/src/fenrir/soundDriver/generic.py b/src/fenrir/soundDriver/generic.py index ebbe1dc7..e0155531 100644 --- a/src/fenrir/soundDriver/generic.py +++ b/src/fenrir/soundDriver/generic.py @@ -21,12 +21,10 @@ class driver(): if self.soundFileCommand == '': self.soundFileCommand = 'play -q -v fenrirVolume fenrirSoundFile' if self.frequenceCommand == '': - self.frequenceCommand = '=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence' - return + self.frequenceCommand = 'play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence' def shutdown(self): self.cancel() - return - def playFrequence(self, frequence, duration, adjustVolume): + def playFrequence(self, frequence = 1000, duration = 0.3, adjustVolume = 0): if interrupt: self.cancel() popenFrequenceCommand = self.frequenceCommand.replace('fenrirVolume', str(self.volume + adjustVolume )) diff --git a/src/fenrir/speechDriver/speechd.py b/src/fenrir/speechDriver/speechd.py index ca8daa15..49fc7894 100644 --- a/src/fenrir/speechDriver/speechd.py +++ b/src/fenrir/speechDriver/speechd.py @@ -34,13 +34,15 @@ class driver(): def speak(self,text, queueable=True): if not self._isInitialized: - return False + self.initialize(self.env) + if not self._isInitialized: + return False if queueable == False: self.cancel() try: self._sd.set_synthesis_voice(self._language) self._sd.set_punctuation(self._punct.NONE) except Exception as e: - pass + self._isInitialized = False self._sd.speak(text) return True diff --git a/src/fenrir/utils/line_utils.py b/src/fenrir/utils/line_utils.py index 763b9042..ac6b442e 100644 --- a/src/fenrir/utils/line_utils.py +++ b/src/fenrir/utils/line_utils.py @@ -5,6 +5,7 @@ # By Chrys, Storm Dragon, and contributers. from core import debug +from collections import Counter def getPrevLine(currX,currY, currText): endOfScreen = False diff --git a/src/fenrir/utils/screen_utils.py b/src/fenrir/utils/screen_utils.py new file mode 100644 index 00000000..54190ffe --- /dev/null +++ b/src/fenrir/utils/screen_utils.py @@ -0,0 +1,54 @@ +#!/bin/python +# -*- coding: utf-8 -*- + +# Fenrir TTY screen reader +# By Chrys, Storm Dragon, and contributers. + +from core import debug +from collections import Counter +import string + +def removeNonprintable(text): + # Get the difference of all ASCII characters from the set of printable characters + nonprintable = set([chr(i) for i in range(128)]).difference(string.printable) + # Use translate to remove all non-printable characters + return text.translate({ord(character):None for character in nonprintable}) + +def insertNewlines(string, every=64): + return '\n'.join(string[i:i+every] for i in range(0, len(string), every)) + +def splitEvery(string, every=64): + return list(string[i:i+every] for i in range(0, len(string), every)) + +def trackHighlights(oldAttr, newAttr, text, lenght): + result = '' + currCursor = None + if oldAttr == newAttr: + return result, currCursor + if len(newAttr) == 0: + return result, currCursor + if len(oldAttr) != len(newAttr): + return result, currCursor + old = splitEvery(oldAttr,lenght) + new = splitEvery(newAttr,lenght) + textLines = text.split('\n') + if len(textLines) != len(new): + return result, currCursor + + try: + background = Counter(newAttr).most_common(1) + background = background[0][0] + except Exception as e: + background = chr(7) + for line in range(len(new)): + if old[line] != new[line]: + for column in range(len(new[line])): + if old[line][column] != new[line][column]: + if new[line][column] != background: + if not currCursor: + currCursor = {} + currCursor['x'] = column + currCursor['y'] = line + result += textLines[line][column] + result += ' ' + return result, currCursor diff --git a/src/fenrir/utils/word_utils.py.bak b/src/fenrir/utils/word_utils.py.bak deleted file mode 100644 index aa4d30d3..00000000 --- a/src/fenrir/utils/word_utils.py.bak +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/python -# -*- coding: utf-8 -*- - -# Fenrir TTY screen reader -# By Chrys, Storm Dragon, and contributers. - -from core import debug - -def getPrevWord(currX,currY, currText): - if currText == '': - return -1, -1, '' - x, y, currWord = getCurrentWord(currX,currY,currText) - wrappedLines = currText.split('\n') - if (currWord == ''): - return currX, currY, '' - while True: - if x < 2: - if y != 0: - y -= 1 - else: - return currX, currY, '' - x = len(wrappedLines[y]) - 1 - else: - x -= 1 - if wrappedLines[y] != '': - break - x, y, currWord = getCurrentWord(x, y, currText) - if currWord == '': - return currX, currY, '' - return x, y, currWord - -def getCurrentWord(currX,currY, currText): - if currText == '': - return -1, -1, '' - x = currX - y = currY - wrappedLines = currText.split('\n') - wordFound = False - currWord = '' - currLine = wrappedLines[y].replace("\t"," ") - if currLine[x] == ' ' and x > 1: - x = x - 2 - while not wordFound: - x = currLine[:x].rfind(" ") - if x == -1: - x = 0 - else: - x += 1 - wordEnd = currLine[x + 1:].find(" ") - if wordEnd == -1: - wordEnd = len(currLine) - else: - wordEnd += x + 1 - currWord = currLine[x:wordEnd] - wordFound = currWord.strip(" \t\n") != '' - if wordFound: - break - if x == 0: - if y != 0: - y -= 1 - currLine = wrappedLines[y].replace("\t"," ") - else: - return currX, currY, '' - x = len(wrappedLines[y]) - 1 - else: - x -= 1 - return x, y, currWord - -def getNextWord(currX,currY, currText): - if currText == '': - return -1, -1, '' - x = currX - y = currY - wrappedLines = currText.split('\n') - wordFound = False - currWord = '' - currLine = wrappedLines[y].replace("\t"," ") - while not wordFound: - xtmp = 0 - if x + 1 >= len(currLine): - if y < len(wrappedLines): - y += 1 - currLine = wrappedLines[y].replace("\t"," ") - else: - return currX, currY, '' - x = 0 - else: - x += 1 - xtmp = x - x = currLine[x:].find(" ") - if x == -1: - x = len(currLine) - continue - else: - if xtmp != 0: - xtmp += 1 - x += xtmp - if x + 1 < len(currLine): - wordEnd = currLine[x + 1:].find(" ") - else: - wordEnd = -1 - if wordEnd == -1: - wordEnd = len(currLine) - else: - wordEnd += x + 1 - if wordEnd >= len(currLine) and y + 1 >= len(wrappedLines): - return currX, currY, '' - currWord = currLine[x:wordEnd] - wordFound = currWord.strip(" \t\n") != '' - if not wordFound: - x = wordEnd - return x, y, currWord