sync with master
This commit is contained in:
commit
ad8589d9a5
@ -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
|
||||
|
50
TODO
50
TODO
@ -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)
|
||||
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
|
||||
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
|
||||
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://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,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_word (echos the last word)
|
||||
echo_deleted_char (echos deleted char on screen
|
||||
read highlighted
|
||||
|
||||
- implement onScreenChange commands
|
||||
promoted text
|
||||
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
'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:
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
2
install.sh
Normal file → Executable file
2
install.sh
Normal file → Executable file
@ -3,7 +3,7 @@
|
||||
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/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
|
||||
|
29
src/fenrir/commands/commands/toggle_highlight_tracking.py
Normal file
29
src/fenrir/commands/commands/toggle_highlight_tracking.py
Normal 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
|
@ -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():
|
||||
|
@ -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():
|
||||
|
24
src/fenrir/commands/onInput/56000-highlight_tracking.py
Normal file
24
src/fenrir/commands/onInput/56000-highlight_tracking.py
Normal 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
|
@ -19,6 +19,8 @@ class command():
|
||||
def run(self):
|
||||
if self.env['runtime']['inputManager'].noKeyPressed():
|
||||
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:
|
||||
|
@ -63,6 +63,11 @@ 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():
|
||||
|
@ -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
|
||||
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
|
||||
return False
|
||||
if mEvent['EventState'] == 0 and not self.env['input']['newCapsLock'] == 0:
|
||||
self.env['runtime']['inputDriver'].toggleLedState(1)
|
||||
self.setLedState = False
|
||||
return
|
||||
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
|
||||
return False
|
||||
if mEvent['EventState'] == 0 and not self.env['input']['newScrollLock'] == 0:
|
||||
self.env['runtime']['inputDriver'].toggleLedState(2)
|
||||
self.setLedState = False
|
||||
return
|
||||
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'] == []
|
||||
|
@ -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': '',
|
||||
|
@ -55,6 +55,10 @@ settings = {
|
||||
'spellCheckLanguage': 'en_US',
|
||||
'scriptPath':'/etc/fenrir/scripts',
|
||||
},
|
||||
'focus':{
|
||||
'cursor': True,
|
||||
'highlight': False,
|
||||
},
|
||||
'promote':{
|
||||
'enabled': True,
|
||||
'inactiveTimeoutSec': 120,
|
||||
|
@ -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
|
||||
if self.ledDevices == {}:
|
||||
return False
|
||||
for fd, dev in self.ledDevices.items():
|
||||
return led in dev.leds()
|
||||
return False
|
||||
|
@ -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']['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']))
|
||||
@ -146,3 +152,8 @@ class driver():
|
||||
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'])
|
||||
|
||||
|
@ -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 ))
|
||||
|
@ -33,6 +33,8 @@ class driver():
|
||||
return
|
||||
|
||||
def speak(self,text, queueable=True):
|
||||
if not self._isInitialized:
|
||||
self.initialize(self.env)
|
||||
if not self._isInitialized:
|
||||
return False
|
||||
if queueable == False: self.cancel()
|
||||
@ -40,7 +42,7 @@ class driver():
|
||||
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
|
||||
|
||||
|
@ -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
|
||||
|
54
src/fenrir/utils/screen_utils.py
Normal file
54
src/fenrir/utils/screen_utils.py
Normal 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
|
@ -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
|
Loading…
Reference in New Issue
Block a user