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)
- gstreamer [soundicons via gstreamer] # not working yet
- 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]
# installation

58
TODO
View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

20
install.sh Normal file → Executable file
View File

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

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 ''
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():

View File

@ -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():

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

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

View File

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

View File

@ -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'] == []

View File

@ -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': '',

View File

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

View File

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

View File

@ -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'])

View File

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

View File

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

View File

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

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