sync with master

This commit is contained in:
chrys 2016-11-05 02:07:48 +01:00
commit ad8589d9a5
27 changed files with 271 additions and 223 deletions

View File

@ -21,6 +21,7 @@ ReadWrite permission
- brltty, python-brlapi [using braille] # (not implemented yet) - brltty, python-brlapi [using braille] # (not implemented yet)
- gstreamer [soundicons via gstreamer] # not working yet - gstreamer [soundicons via gstreamer] # not working yet
- python-pyenchant [spell check functionality] - python-pyenchant [spell check functionality]
- aspell-<language> [your languagedata for spellchecker, english support "aspell-en"]
- python-daemonize [use fenrir as background service on Unix like systems] - python-daemonize [use fenrir as background service on Unix like systems]
# installation # installation

50
TODO
View File

@ -7,8 +7,19 @@ ToDos in Priority order:
For example, in screen, it just tells me bell in window, but doesn't tell me which one. (southernprince) 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) 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 spellcheck triggers twice if there are two spaces after an word and you arrow over them
fenrir is not able to detect the current application inside of screen.
- replace beep with a digital equivalent - 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 - implement braille
output to braille device output to braille device
@ -26,35 +37,14 @@ http://mielke.cc/brltty/doc/Manual-BrlAPI/English/BrlAPI.html
https://git.gnome.org/browse/orca/tree/src/orca/braille.py 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 - add perApplicationTrigger trigger
per application commands per application commands
per application onScreenChange per application onScreenChange
per application onInput per application onInput
- per application shortcuts - 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 - configuration should be overwriteable with parameter and alternative paths
- write settings - write settings
- menue for settings configuration #storm - 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", "papa", "quebec", "romeo", "sierra", "tango",
"uniform", "victor", "whisky", "x ray", "uniform", "victor", "whisky", "x ray",
"yankee", "zulu" "yankee", "zulu"
next_char_phonetic
prev_char_phonetic
next_word_phonetic
prev_word_phonetic
toggle_highlighted_mode
- implement onInput commands - implement onInput commands
read_line_if_cursor_change_vertical (needed if you arrow up and down, we want to announce the line) read_line_if_cursor_change_vertical (needed if you arrow up and down, we want to announce the line)
@ -208,6 +203,7 @@ 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_char (echos the last char on pressing space or return)
echo_word (echos the last word) echo_word (echos the last word)
echo_deleted_char (echos deleted char on screen echo_deleted_char (echos deleted char on screen
read highlighted
- implement onScreenChange commands - implement onScreenChange commands
promoted text promoted text
@ -256,3 +252,7 @@ https://web.archive.org/web/20131017130434/http://www.jejik.com/articles/2007/02
- announce capslock - announce capslock
- anounce numlock - anounce numlock
- anounce scroll - 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

View File

@ -75,6 +75,7 @@ KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check
KEY_FENRIR,KEY_BACKSLASH=toggle_output KEY_FENRIR,KEY_BACKSLASH=toggle_output
KEY_FENRIR,KEY_CTRL,KEY_E=toggle_emoticons KEY_FENRIR,KEY_CTRL,KEY_E=toggle_emoticons
key_FENRIR,KEY_KPENTER=toggle_auto_read key_FENRIR,KEY_KPENTER=toggle_auto_read
KEY_FENRIR,KEY_KPASTERISK=toggle_highlight_tracking
KEY_FENRIR,KEY_Q=quit_fenrir KEY_FENRIR,KEY_Q=quit_fenrir
KEY_FENRIR,KEY_T=time KEY_FENRIR,KEY_T=time
2,KEY_FENRIR,KEY_T=date 2,KEY_FENRIR,KEY_T=date

View File

@ -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_ENTER=toggle_output
KEY_FENRIR,KEY_SHIFT,KEY_E=toggle_emoticons KEY_FENRIR,KEY_SHIFT,KEY_E=toggle_emoticons
KEY_FENRIR,KEY_ENTER=toggle_auto_read KEY_FENRIR,KEY_ENTER=toggle_auto_read
KEY_FENRIR,KEY_Y=toggle_highlight_tracking
KEY_FENRIR,KEY_Q=quit_fenrir KEY_FENRIR,KEY_Q=quit_fenrir
KEY_FENRIR,KEY_T=time KEY_FENRIR,KEY_T=time
2,KEY_FENRIR,KEY_T=date 2,KEY_FENRIR,KEY_T=date

View File

@ -75,6 +75,7 @@ KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check
KEY_FENRIR,KEY_BACKSLASH=toggle_output KEY_FENRIR,KEY_BACKSLASH=toggle_output
#=toggle_emoticons #=toggle_emoticons
key_FENRIR,KEY_KPENTER=toggle_auto_read key_FENRIR,KEY_KPENTER=toggle_auto_read
#=toggle_highlight_tracking
KEY_FENRIR,KEY_Q=quit_fenrir KEY_FENRIR,KEY_Q=quit_fenrir
KEY_FENRIR,KEY_T=time KEY_FENRIR,KEY_T=time
2,KEY_FENRIR,KEY_T=date 2,KEY_FENRIR,KEY_T=date

View File

@ -77,9 +77,9 @@ autodetectSuspendingScreen=True
[keyboard] [keyboard]
driver=evdev driver=evdev
# filter input devices AUTO, ALL or a DEVICE NAME # filter input devices NOMICE, ALL or a DEVICE NAME
device=AUTO device=ALL
# gives fenrir exclusive access to the keyboard and let consume keystrokes. just disable on problems. # gives fenrir exclusive access to the keyboard and let consume keystrokes.
grabDevices=True grabDevices=True
ignoreShortcuts=False ignoreShortcuts=False
# the current shortcut layout located in /etc/fenrir/keyboard # the current shortcut layout located in /etc/fenrir/keyboard
@ -110,7 +110,13 @@ timeFormat=%H:%M:%P
dateFormat=%A, %B %d, %Y dateFormat=%A, %B %d, %Y
autoSpellCheck=True autoSpellCheck=True
spellCheckLanguage=en_US 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] [promote]
enabled=True enabled=True

View File

@ -77,8 +77,8 @@ autodetectSuspendingScreen=True
[keyboard] [keyboard]
driver=evdev driver=evdev
# filter input devices AUTO, ALL or a DEVICE NAME # filter input devices NOMICE, ALL or a DEVICE NAME
device=AUTO device=ALL
# gives fenrir exclusive access to the keyboard and let consume keystrokes. just disable on problems. # gives fenrir exclusive access to the keyboard and let consume keystrokes. just disable on problems.
grabDevices=True grabDevices=True
ignoreShortcuts=False ignoreShortcuts=False
@ -110,7 +110,13 @@ timeFormat=%H:%M:%P
dateFormat=%A, %B %d, %Y dateFormat=%A, %B %d, %Y
autoSpellCheck=True autoSpellCheck=True
spellCheckLanguage=en_US 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] [promote]
enabled=True enabled=True

View File

@ -34,8 +34,8 @@ autodetectSuspendingScreen=False
[keyboard] [keyboard]
driver=evdev driver=evdev
# filter input devices AUTO, ALL or a DEVICE NAME # filter input devices NOMICE, ALL or a DEVICE NAME
device=AUTO device=ALL
grabDevices=True grabDevices=True
ignoreShortcuts=False ignoreShortcuts=False
keyboardLayout=desktop keyboardLayout=desktop
@ -60,7 +60,14 @@ timeFormat=%H:%M:%P
dateFormat="%A, %B %d, %Y" dateFormat="%A, %B %d, %Y"
autoSpellCheck=True autoSpellCheck=True
spellCheckLanguage=en_US 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] [promote]
enabled=True enabled=True

View File

@ -3,17 +3,19 @@
_gitname='fenrir' _gitname='fenrir'
pkgname="${_gitname}-git" pkgname="${_gitname}-git"
pkgver=v0.1.2.gb72614a pkgver=v0.2.5.g33af5b6
pkgrel=1 pkgrel=3
pkgdesc='A user space console screen reader written in python3' pkgdesc='A user space console screen reader written in python3'
arch=('any') arch=('any')
url='https://github.com/chrys87/${_pkgname}' url='https://github.com/chrys87/${_pkgname}'
license=('MIT') license=('MIT')
depends=('python' 'python-espeak' 'python-evdev') depends=('python' 'python-daemonize' 'python-evdev')
optdepends=('brltty: For Braille support' optdepends=('brltty: For Braille support'
'gstreamer: for soundicons via gstreamer' 'gstreamer: for soundicons via gstreamer'
'sox: The default sound driver' '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') makedepends=('git')
provides=('fenrir') provides=('fenrir')
conflicts=('fenrir') conflicts=('fenrir')
@ -21,7 +23,7 @@ install="$pkgname".install
source=("git+https://github.com/chrys87/${_gitname}.git" source=("git+https://github.com/chrys87/${_gitname}.git"
'fenrir-git.install') 'fenrir-git.install')
md5sums=('SKIP' md5sums=('SKIP'
'9d1e82fce2e02ae2a1216a18ca576bfb') '1387fd3851040d03816e2fb6b8fa631f')
pkgver() pkgver()
{ {
@ -33,17 +35,19 @@ pkgver()
package() package()
{ {
cd "$srcdir/$_gitname" cd "$srcdir/$_gitname"
install -d "$pkgdir/usr/bin" install -m755 -d "$pkgdir/opt/fenrir"
install -d "$pkgdir/etc/fenrir/keyboard" install -m755 -d "$pkgdir/usr/share/fenrir/scripts"
install -d "$pkgdir/etc/fenrir/settings" install -m755 -d "$pkgdir/usr/share/fenrir/tools"
install -d "$pkgdir/etc/fenrir/substitution" 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 -d "$pkgdir/usr/share/sounds/fenrir"
install -m644 -D "autostart/systemd/fenrir.service" "$pkgdir/usr/lib/systemd/system/fenrir.service" install -m644 -D "autostart/systemd/fenrir.service" "$pkgdir/usr/lib/systemd/system/fenrir.service"
python setup.py install --root="${pkgdir}/" --optimize=1 cp -a src/fenrir/* "$pkgdir/opt/fenrir"
cp -a config/keyboard/* "$pkgdir/etc/fenrir/keyboard" cp -a config/scripts/* "$pkgdir/usr/share/fenrir/scripts"
cp -a config/settings/* "$pkgdir/etc/fenrir/settings" cp -a tools/* "$pkgdir/usr/share/fenrir/tools"
cp -a config/sound/* "$pkgdir/usr/share/sounds/fenrir" cp -a config/sound/* "$pkgdir/usr/share/sounds/fenrir"
cp -a config/substitution/* "$pkgdir/etc/fenrir/substitution"
} }
# vim: set ts=2 sw=2 et: # vim: set ts=2 sw=2 et:

View File

@ -1,4 +1,5 @@
post_install() { post_install() {
ln -s /opt/fenrir/fenrir-daemon /usr/bin/fenrir
_alert _alert
} }
@ -6,6 +7,9 @@ _alert() {
cat << EOF cat << EOF
To have fenrir start at boot: To have fenrir start at boot:
sudo systemctl enable fenrir 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 EOF
} }

20
install.sh Normal file → Executable file
View File

@ -2,16 +2,16 @@
#Basic install script for fenrir. #Basic install script for fenrir.
read -p "This will install fenrir. Press ctrl+c to cancil, or enter to continue." continue read -p "This will install fenrir. Press ctrl+c to cancil, or enter to continue." continue
install -m755 -d /opt/fenrir install -m755 -d /opt/fenrir
install -m755 -d /usr/share/fenrir/scripts 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/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/punctuation/default.conf" /etc/fenrir/punctuation/default.conf
install -m644 -D "config/settings/settings.conf" /etc/fenrir/settings/settings.conf install -m644 -D "config/settings/settings.conf" /etc/fenrir/settings/settings.conf
install -d /usr/share/sounds/fenrir install -d /usr/share/sounds/fenrir
install -m644 -D "autostart/systemd/fenrir.service" /usr/lib/systemd/system/fenrir.service install -m644 -D "autostart/systemd/fenrir.service" /usr/lib/systemd/system/fenrir.service
cp -a src/fenrir/* /opt/fenrir cp -a src/fenrir/* /opt/fenrir
cp -a config/scripts/* /usr/share/fenrir/scripts cp -a config/scripts/* /usr/share/fenrir/scripts
cp -a config/sound/* /usr/share/sounds/fenrir cp -a config/sound/* /usr/share/sounds/fenrir
ln -s /opt/fenrir/fenrir-daemon /usr/bin/fenrir ln -s /opt/fenrir/fenrir-daemon /usr/bin/fenrir
cat << EOF cat << EOF
To have fenrir start at boot: To have fenrir start at boot:

View File

@ -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

View File

@ -18,6 +18,8 @@ class command():
return '' return ''
def run(self): def run(self):
if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'cursor'):
return
if self.env['runtime']['screenManager'].isScreenChange(): if self.env['runtime']['screenManager'].isScreenChange():
return return
if self.env['runtime']['inputManager'].noKeyPressed(): if self.env['runtime']['inputManager'].noKeyPressed():

View File

@ -18,6 +18,8 @@ class command():
return '' return ''
def run(self): def run(self):
if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'cursor'):
return
if self.env['runtime']['inputManager'].noKeyPressed(): if self.env['runtime']['inputManager'].noKeyPressed():
return return
if self.env['runtime']['screenManager'].isScreenChange(): if self.env['runtime']['screenManager'].isScreenChange():

View File

@ -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

View File

@ -19,6 +19,8 @@ class command():
def run(self): def run(self):
if self.env['runtime']['inputManager'].noKeyPressed(): if self.env['runtime']['inputManager'].noKeyPressed():
return return
if self.env['screenData']['newAttribDelta'] != '':
return
if self.env['runtime']['screenManager'].isScreenChange(): if self.env['runtime']['screenManager'].isScreenChange():
return return
if self.env['runtime']['cursorManager'].isCursorVerticalMove(): if self.env['runtime']['cursorManager'].isCursorVerticalMove():
@ -29,9 +31,7 @@ class command():
return return
prevLine = self.env['screenData']['oldContentText'].split('\n')[self.env['screenData']['newCursor']['y']] prevLine = self.env['screenData']['oldContentText'].split('\n')[self.env['screenData']['newCursor']['y']]
currLine = self.env['screenData']['newContentText'].split('\n')[self.env['screenData']['newCursor']['y']] currLine = self.env['screenData']['newContentText'].split('\n')[self.env['screenData']['newCursor']['y']]
if currLine.isspace(): if not currLine.isspace():
self.env['runtime']['outputManager'].presentText("blank", soundIcon='EmptyLine', interrupt=True)
else:
currPrompt = currLine.find('$') currPrompt = currLine.find('$')
rootPrompt = currLine.find('#') rootPrompt = currLine.find('#')
if currPrompt <= 0: if currPrompt <= 0:

View File

@ -63,6 +63,11 @@ class cursorManager():
self.env['screenData']['oldCursorReview'] = self.env['screenData']['newCursorReview'] self.env['screenData']['oldCursorReview'] = self.env['screenData']['newCursorReview']
if not self.env['screenData']['newCursorReview']: if not self.env['screenData']['newCursorReview']:
self.env['screenData']['newCursorReview'] = self.env['screenData']['newCursor'].copy() 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): def setReviewCursorPosition(self, x, y):
if not self.isReviewMode(): if not self.isReviewMode():

View File

@ -43,7 +43,7 @@ class inputManager():
if len(self.env['input']['currInput']) == 0: if len(self.env['input']['currInput']) == 0:
self.env['input']['prevDeepestInput'] = [] self.env['input']['prevDeepestInput'] = []
self.env['input']['shortcutRepeat'] = 1 self.env['input']['shortcutRepeat'] = 1
self.handleLedStates(mEvent) self.setLedState = self.handleLedStates(mEvent)
self.env['input']['lastInputTime'] = time.time() self.env['input']['lastInputTime'] = time.time()
elif mEvent['EventState'] == 1: elif mEvent['EventState'] == 1:
if not mEvent['EventName'] in self.env['input']['currInput']: if not mEvent['EventName'] in self.env['input']['currInput']:
@ -57,7 +57,7 @@ class inputManager():
self.env['input']['shortcutRepeat'] += 1 self.env['input']['shortcutRepeat'] += 1
else: else:
self.env['input']['shortcutRepeat'] = 1 self.env['input']['shortcutRepeat'] = 1
self.handleLedStates(mEvent) self.setLedState = self.handleLedStates(mEvent)
self.env['input']['lastInputTime'] = time.time() self.env['input']['lastInputTime'] = time.time()
elif mEvent['EventState'] == 2: elif mEvent['EventState'] == 2:
self.env['input']['lastInputTime'] = time.time() self.env['input']['lastInputTime'] = time.time()
@ -77,34 +77,29 @@ class inputManager():
def handleLedStates(self, mEvent): def handleLedStates(self, mEvent):
if not self.setLedState: if not self.setLedState:
return return self.setLedState
if mEvent['EventName'] == 'KEY_NUMLOCK': if mEvent['EventName'] == 'KEY_NUMLOCK':
if mEvent['EventState'] == 1 and not self.env['input']['newNumLock'] == 1: if mEvent['EventState'] == 1 and not self.env['input']['newNumLock'] == 1:
self.env['runtime']['inputDriver'].toggleLedState() self.env['runtime']['inputDriver'].toggleLedState()
self.setLedState = False return False
return
if mEvent['EventState'] == 0 and not self.env['input']['newNumLock'] == 0: if mEvent['EventState'] == 0 and not self.env['input']['newNumLock'] == 0:
self.env['runtime']['inputDriver'].toggleLedState() self.env['runtime']['inputDriver'].toggleLedState()
self.setLedState = False return False
return
if mEvent['EventName'] == 'KEY_CAPSLOCK': if mEvent['EventName'] == 'KEY_CAPSLOCK':
if mEvent['EventState'] == 1 and not self.env['input']['newCapsLock'] == 1: if mEvent['EventState'] == 1 and not self.env['input']['newCapsLock'] == 1:
self.env['runtime']['inputDriver'].toggleLedState(1) self.env['runtime']['inputDriver'].toggleLedState(1)
self.setLedState = False return False
return
if mEvent['EventState'] == 0 and not self.env['input']['newCapsLock'] == 0: if mEvent['EventState'] == 0 and not self.env['input']['newCapsLock'] == 0:
self.env['runtime']['inputDriver'].toggleLedState(1) self.env['runtime']['inputDriver'].toggleLedState(1)
self.setLedState = False return False
return
if mEvent['EventName'] == 'KEY_SCROLLLOCK': if mEvent['EventName'] == 'KEY_SCROLLLOCK':
if mEvent['EventState'] == 1 and not self.env['input']['newScrollLock'] == 1: if mEvent['EventState'] == 1 and not self.env['input']['newScrollLock'] == 1:
self.env['runtime']['inputDriver'].toggleLedState(2) self.env['runtime']['inputDriver'].toggleLedState(2)
self.setLedState = False return False
return
if mEvent['EventState'] == 0 and not self.env['input']['newScrollLock'] == 0: if mEvent['EventState'] == 0 and not self.env['input']['newScrollLock'] == 0:
self.env['runtime']['inputDriver'].toggleLedState(2) self.env['runtime']['inputDriver'].toggleLedState(2)
self.setLedState = False return False
return return self.setLedState
def grabDevices(self): def grabDevices(self):
if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'): if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'):
@ -168,10 +163,10 @@ class inputManager():
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR) self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
def isFenrirKeyPressed(self): def isFenrirKeyPressed(self):
return 'KEY_FENRIR' in self.env['input']['currInput'] return 'KEY_FENRIR' in self.env['input']['prevDeepestInput']
def isScriptKeyPressed(self): def isScriptKeyPressed(self):
return 'KEY_SCRIPT' in self.env['input']['currInput'] return 'KEY_SCRIPT' in self.env['input']['prevDeepestInput']
def noKeyPressed(self): def noKeyPressed(self):
return self.env['input']['currInput'] == [] return self.env['input']['currInput'] == []

View File

@ -11,8 +11,10 @@ screenData = {
'columns': 0, 'columns': 0,
'lines': 0, 'lines': 0,
'oldDelta': '', 'oldDelta': '',
'oldAttribDelta': '',
'oldNegativeDelta': '', 'oldNegativeDelta': '',
'oldCursorReview':None, 'oldCursorReview':None,
'oldCursorAttrib':None,
'oldCursor':{'x':0,'y':0}, 'oldCursor':{'x':0,'y':0},
'oldContentBytes': b'', 'oldContentBytes': b'',
'oldContentText': '', 'oldContentText': '',
@ -21,7 +23,9 @@ screenData = {
'oldTTY':None, 'oldTTY':None,
'newDelta': '', 'newDelta': '',
'newNegativeDelta': '', 'newNegativeDelta': '',
'newAttribDelta': '',
'newCursorReview':None, 'newCursorReview':None,
'newCursorAttrib':None,
'newCursor':{'x':0,'y':0}, 'newCursor':{'x':0,'y':0},
'newContentBytes': b'', 'newContentBytes': b'',
'newContentText': '', 'newContentText': '',

View File

@ -55,6 +55,10 @@ settings = {
'spellCheckLanguage': 'en_US', 'spellCheckLanguage': 'en_US',
'scriptPath':'/etc/fenrir/scripts', 'scriptPath':'/etc/fenrir/scripts',
}, },
'focus':{
'cursor': True,
'highlight': False,
},
'promote':{ 'promote':{
'enabled': True, 'enabled': True,
'inactiveTimeoutSec': 120, 'inactiveTimeoutSec': 120,

View File

@ -43,8 +43,6 @@ class driver():
return currMapEvent return currMapEvent
if currMapEvent['EventState'] in [0,1,2]: if currMapEvent['EventState'] in [0,1,2]:
return currMapEvent return currMapEvent
event = self.iDevices[fd].read_one() event = self.iDevices[fd].read_one()
return None return None
@ -77,7 +75,7 @@ class driver():
if self.env['runtime']['settingsManager'].getSetting('keyboard', 'device').upper() == 'ALL': 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.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()} 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.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()} 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: else:
@ -102,10 +100,10 @@ class driver():
# 0 = Numlock # 0 = Numlock
# 1 = Capslock # 1 = Capslock
# 2 = Rollen # 2 = Rollen
if self.ledDevices == {}:
return False
if self.ledDevices == None: if self.ledDevices == None:
return False return False
if self.ledDevices == {}:
return False
for fd, dev in self.ledDevices.items(): for fd, dev in self.ledDevices.items():
return led in dev.leds() return led in dev.leds()
return False return False

View File

@ -8,6 +8,7 @@ import difflib
import re import re
import subprocess import subprocess
from core import debug from core import debug
from utils import screen_utils
class driver(): class driver():
def __init__(self): def __init__(self):
@ -16,9 +17,6 @@ class driver():
self.env = environment self.env = environment
def shutdown(self): def shutdown(self):
pass 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): def getCurrScreen(self):
self.env['screenData']['oldTTY'] = self.env['screenData']['newTTY'] self.env['screenData']['oldTTY'] = self.env['screenData']['newTTY']
try: try:
@ -85,10 +83,12 @@ class driver():
# set new "old" values # set new "old" values
self.env['screenData']['oldContentBytes'] = self.env['screenData']['newContentBytes'] self.env['screenData']['oldContentBytes'] = self.env['screenData']['newContentBytes']
self.env['screenData']['oldContentText'] = self.env['screenData']['newContentText'] self.env['screenData']['oldContentText'] = self.env['screenData']['newContentText']
self.env['screenData']['oldContentTextAttrib'] = self.env['screenData']['newContentAttrib'] self.env['screenData']['oldContentAttrib'] = self.env['screenData']['newContentAttrib']
self.env['screenData']['oldCursor']['x'] = self.env['screenData']['newCursor']['x'] self.env['screenData']['oldCursor'] = self.env['screenData']['newCursor'].copy()
self.env['screenData']['oldCursor']['y'] = self.env['screenData']['newCursor']['y'] 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']['oldDelta'] = self.env['screenData']['newDelta']
self.env['screenData']['oldAttribDelta'] = self.env['screenData']['newAttribDelta']
self.env['screenData']['oldNegativeDelta'] = self.env['screenData']['newNegativeDelta'] self.env['screenData']['oldNegativeDelta'] = self.env['screenData']['newNegativeDelta']
self.env['screenData']['newContentBytes'] = newContentBytes self.env['screenData']['newContentBytes'] = newContentBytes
# get metadata like cursor or screensize # get metadata like cursor or screensize
@ -98,8 +98,9 @@ class driver():
self.env['screenData']['newCursor']['y'] = int( self.env['screenData']['newContentBytes'][3]) self.env['screenData']['newCursor']['y'] = int( self.env['screenData']['newContentBytes'][3])
# analyze content # 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'] = 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']['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']: if self.env['screenData']['newTTY'] != self.env['screenData']['oldTTY']:
self.env['screenData']['oldContentBytes'] = b'' self.env['screenData']['oldContentBytes'] = b''
@ -108,10 +109,15 @@ class driver():
self.env['screenData']['oldCursor']['x'] = 0 self.env['screenData']['oldCursor']['x'] = 0
self.env['screenData']['oldCursor']['y'] = 0 self.env['screenData']['oldCursor']['y'] = 0
self.env['screenData']['oldDelta'] = '' self.env['screenData']['oldDelta'] = ''
self.env['screenData']['oldAttribDelta'] = ''
self.env['screenData']['oldCursorAttrib'] = None
self.env['screenData']['newCursorAttrib'] = None
self.env['screenData']['oldNegativeDelta'] = '' self.env['screenData']['oldNegativeDelta'] = ''
# always clear current deltas # initialize current deltas
self.env['screenData']['newNegativeDelta'] = '' self.env['screenData']['newNegativeDelta'] = ''
self.env['screenData']['newDelta'] = '' self.env['screenData']['newDelta'] = ''
self.env['screenData']['newAttribDelta'] = ''
# changes on the screen # changes on the screen
oldScreenText = re.sub(' +',' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screenData']['oldContentText'])) oldScreenText = re.sub(' +',' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screenData']['oldContentText']))
newScreenText = re.sub(' +',' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screenData']['newContentText'])) newScreenText = re.sub(' +',' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screenData']['newContentText']))
@ -146,3 +152,8 @@ class driver():
self.env['screenData']['newDelta'] = ''.join(x[2:] for x in diffList if x[0] == '+') 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] == '-') 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'])

View File

@ -21,12 +21,10 @@ class driver():
if self.soundFileCommand == '': if self.soundFileCommand == '':
self.soundFileCommand = 'play -q -v fenrirVolume fenrirSoundFile' self.soundFileCommand = 'play -q -v fenrirVolume fenrirSoundFile'
if self.frequenceCommand == '': if self.frequenceCommand == '':
self.frequenceCommand = '=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence' self.frequenceCommand = 'play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence'
return
def shutdown(self): def shutdown(self):
self.cancel() self.cancel()
return def playFrequence(self, frequence = 1000, duration = 0.3, adjustVolume = 0):
def playFrequence(self, frequence, duration, adjustVolume):
if interrupt: if interrupt:
self.cancel() self.cancel()
popenFrequenceCommand = self.frequenceCommand.replace('fenrirVolume', str(self.volume + adjustVolume )) popenFrequenceCommand = self.frequenceCommand.replace('fenrirVolume', str(self.volume + adjustVolume ))

View File

@ -33,6 +33,8 @@ class driver():
return return
def speak(self,text, queueable=True): def speak(self,text, queueable=True):
if not self._isInitialized:
self.initialize(self.env)
if not self._isInitialized: if not self._isInitialized:
return False return False
if queueable == False: self.cancel() if queueable == False: self.cancel()
@ -40,7 +42,7 @@ class driver():
self._sd.set_synthesis_voice(self._language) self._sd.set_synthesis_voice(self._language)
self._sd.set_punctuation(self._punct.NONE) self._sd.set_punctuation(self._punct.NONE)
except Exception as e: except Exception as e:
pass self._isInitialized = False
self._sd.speak(text) self._sd.speak(text)
return True return True

View File

@ -5,6 +5,7 @@
# By Chrys, Storm Dragon, and contributers. # By Chrys, Storm Dragon, and contributers.
from core import debug from core import debug
from collections import Counter
def getPrevLine(currX,currY, currText): def getPrevLine(currX,currY, currText):
endOfScreen = False endOfScreen = False

View File

@ -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

View File

@ -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