Resolved version conflict. I need to automate this somehow.

This commit is contained in:
Storm Dragon
2024-12-09 12:59:55 -05:00
28 changed files with 221 additions and 838 deletions

View File

@ -1,66 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.brailleDriver import brailleDriver
class driver(brailleDriver):
def __init__(self):
brailleDriver.__init__(self)
self._brl = None
def initialize(self, environment):
self.env = environment
try:
import brlapi
self._brl = brlapi.Connection()
self._deviceSize = self._brl.displaySize
except Exception as e:
print(e)
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
return
self._isInitialized = True
def getDeviceSize(self):
if not self._isInitialized:
return (0,0)
if not self._deviceSize:
return (0,0)
return self._deviceSize
def flush(self):
if not self._isInitialized:
return
try:
self._brl.writeText('',0)
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('BRAILLE.flush '+str(e),debug.debugLevel.ERROR)
def writeText(self,text):
if not self._isInitialized:
return
try:
self._brl.writeText(text)
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('BRAILLE.writeText '+str(e),debug.debugLevel.ERROR)
def connectDevice(self):
self._brl = brlapi.Connection()
def enterScreen(self, screen):
if not self._isInitialized:
return
self._brl.enterTtyMode(int(screen))
def leveScreen(self):
if not self._isInitialized:
return
self._brl.leaveTtyMode()
def shutdown(self):
if not self._isInitialized:
return
self.leveScreen()

View File

@ -1,49 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.brailleDriver import brailleDriver
class driver(brailleDriver):
def __init__(self):
brailleDriver.__init__(self)
def initialize(self, environment):
self.env = environment
self._isInitialized = True
self.deviceSize = (40,0)
print('Braille Debug Driver: Initialized')
def getDeviceSize(self):
if not self._isInitialized:
return (0,0)
print('Braille Debug Driver: getDeviceSize ' + str(self.deviceSize))
return self.deviceSize
def writeText(self,text):
if not self._isInitialized:
return
print('Braille Debug Driver: writeText:' + str(text))
print('Braille Debug Driver: -----------------------------------')
def connectDevice(self):
print('Braille Debug Driver: connectDevice')
def enterScreen(self, screen):
if not self._isInitialized:
return
print('Braille Debug Driver: enterScreen')
def leveScreen(self):
if not self._isInitialized:
return
print('Braille Debug Driver: leveScreen')
def shutdown(self):
if self._isInitialized:
self.leveScreen()
self._isInitialized = False
print('Braille Debug Driver: Shutdown')

View File

@ -1,12 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.brailleDriver import brailleDriver
class driver(brailleDriver):
def __init__(self):
brailleDriver.__init__(self)

View File

@ -1,21 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.core import debug
class command():
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Clear the Braille device if it is displaying a message')
def run(self):
self.env['runtime']['outputManager'].clearFlushTime()
def setCallback(self, callback):
pass

View File

@ -1,21 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.core import debug
class command():
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Move braille view to the left.')
def run(self):
panned = self.env['runtime']['outputManager'].setPanLeft()
def setCallback(self, callback):
pass

View File

@ -1,21 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.core import debug
class command():
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Move braille view to the right.')
def run(self):
panned = self.env['runtime']['outputManager'].setPanRight()
def setCallback(self, callback):
pass

View File

@ -1,21 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.core import debug
class command():
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Set the braille view back to cursor.')
def run(self):
self.env['runtime']['outputManager'].removePanning()
def setCallback(self, callback):
pass

View File

@ -1,27 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.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 and disables Braille output')
def run(self):
if self.env['runtime']['settingsManager'].getSettingAsBool('braille', 'enabled'):
self.env['runtime']['outputManager'].presentText(_('braille disabled'), soundIcon='BrailleOff', interrupt=True)
self.env['runtime']['settingsManager'].setSetting('braille', 'enabled', str(not self.env['runtime']['settingsManager'].getSettingAsBool('braille', 'enabled')))
if self.env['runtime']['settingsManager'].getSettingAsBool('braille', 'enabled'):
self.env['runtime']['outputManager'].presentText(_('braille enabled'), soundIcon='BrailleOn', interrupt=True)
def setCallback(self, callback):
pass

View File

@ -18,16 +18,13 @@ class command():
def run(self):
if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled') or \
self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled') or \
self.env['runtime']['settingsManager'].getSettingAsBool('braille', 'enabled'):
self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled'):
self.env['runtime']['outputManager'].presentText(_('Fenrir muted'), soundIcon='Accept', interrupt=True)
self.env['runtime']['settingsManager'].setSetting('speech', 'enabled','False')
self.env['runtime']['settingsManager'].setSetting('sound', 'enabled','False')
self.env['runtime']['settingsManager'].setSetting('braille', 'enabled','False')
else:
self.env['runtime']['settingsManager'].setSetting('speech', 'enabled','True')
self.env['runtime']['settingsManager'].setSetting('sound', 'enabled','True')
self.env['runtime']['settingsManager'].setSetting('braille', 'enabled','True')
self.env['runtime']['outputManager'].presentText(_('Fenrir unmuted'), soundIcon='Cancel', interrupt=True)
def setCallback(self, callback):

View File

@ -1,82 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
import brlapi
from fenrirscreenreader.core import debug
class brailleDriver():
def __init__(self):
self._isInitialized = False
self._brl = None
self.deviceSize = None
def initialize(self, environment):
"""Initialize the BRLTTY connection."""
self.env = environment
try:
self._brl = brlapi.Connection()
self._brl.enterTtyMode()
self.deviceSize = self._brl.displaySize
self._isInitialized = True
return True
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('ERROR: Initializing braille failed:' + str(e),debug.debugLevel.ERROR)
return False
def getDeviceSize(self):
"""Get the size of the braille display."""
if not self._isInitialized:
return (0, 0)
return self.deviceSize if self.deviceSize else (0, 0)
def writeText(self, text):
"""Write text to the braille display."""
if not self._isInitialized:
return
try:
self._brl.writeText(text)
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('ERROR: Writing braille failed:' + str(e),debug.debugLevel.ERROR)
def readKeypress(self):
"""Read a keypress from the braille display."""
if not self._isInitialized:
return None
try:
return self._brl.readKey(wait=0)
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('ERROR: Reading key failed:' + str(e),debug.debugLevel.ERROR)
return None
def enterScreen(self, screen):
"""Enter a new screen context."""
if not self._isInitialized:
return
try:
self._brl.enterTtyModeWithPath(screen)
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('ERROR: Entering screen failed:' + str(e),debug.debugLevel.ERROR)
def leaveScreen(self):
"""Leave the current screen context."""
if not self._isInitialized:
return
try:
self._brl.leaveTtyMode()
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('ERROR: Leaving screen failed:' + str(e),debug.debugLevel.ERROR)
def shutdown(self):
"""Shutdown the braille driver."""
if not self._isInitialized:
return
try:
self.leaveScreen()
if self._brl:
self._brl.closeConnection()
self._brl = None
self._isInitialized = False
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('ERROR: Shutting down braille failed:' + str(e),debug.debugLevel.ERROR)

View File

@ -12,14 +12,12 @@ class fenrirEventType(Enum):
StopMainLoop = 1
ScreenUpdate = 2
KeyboardInput = 3
BrailleInput = 4
PlugInputDevice = 5
BrailleFlush = 6
ScreenChanged = 7
HeartBeat = 8 # for time based scheduling
ExecuteCommand = 9
ByteInput = 10
RemoteIncomming = 11
PlugInputDevice = 4
ScreenChanged = 5
HeartBeat = 6
ExecuteCommand = 7
ByteInput = 8
RemoteIncomming = 9
def __int__(self):
return self.value
def __str__(self):

View File

@ -42,12 +42,8 @@ class eventManager():
self.env['runtime']['fenrirManager'].handleScreenUpdate(event)
elif event['Type'] == fenrirEventType.KeyboardInput:
self.env['runtime']['fenrirManager'].handleInput(event)
elif event['Type'] == fenrirEventType.BrailleInput:
pass
elif event['Type'] == fenrirEventType.PlugInputDevice:
self.env['runtime']['fenrirManager'].handlePlugInputDevice(event)
elif event['Type'] == fenrirEventType.BrailleFlush:
pass
elif event['Type'] == fenrirEventType.ScreenChanged:
self.env['runtime']['fenrirManager'].handleScreenChange(event)
elif event['Type'] == fenrirEventType.HeartBeat:

View File

@ -2,109 +2,50 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
import signal, time, argparse, os, sys
import signal
import time
import os
import sys
from fenrirscreenreader.core import i18n
from fenrirscreenreader.core import settingsManager
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.eventData import fenrirEventType
from fenrirscreenreader import fenrirVersion
class fenrirManager():
def __init__(self):
self.initialized = False
cliArgs = self.handleArgs()
if not cliArgs:
return
def __init__(self, cliArgs):
self.isInitialized = False
try:
self.environment = settingsManager.settingsManager().initFenrirConfig(cliArgs, self)
if not self.environment:
raise RuntimeError('Cannot Initialize. Maybe the configfile is not available or not parseable')
except RuntimeError:
raise
self.environment['runtime']['outputManager'].presentText(_("Start Fenrir"), soundIcon='ScreenReaderOn', interrupt=True)
signal.signal(signal.SIGINT, self.captureSignal)
signal.signal(signal.SIGTERM, self.captureSignal)
self.initialized = True
self.isInitialized = True
self.modifierInput = False
self.singleKeyCommand = False
self.command = ''
self.setProcessName()
def handleArgs(self):
"""
Parse and handle command line arguments for Fenrir.
Returns:
argparse.Namespace: Parsed command line arguments
None: If argument parsing fails
"""
parser = argparse.ArgumentParser(
description="Fenrir - A console screen reader for Linux",
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
'-v', '--version',
action='version',
version=f'Fenrir screen reader version {fenrirVersion.version}-{fenrirVersion.codeName}',
help='Show version information and exit'
)
parser.add_argument(
'-s', '--setting',
metavar='SETTING-FILE',
default='/etc/fenrir/settings/settings.conf',
help='Path to custom settings file'
)
parser.add_argument(
'-o', '--options',
metavar='SECTION#SETTING=VALUE;..',
default='',
help='Override settings file options. Format: SECTION#SETTING=VALUE;... (case sensitive)'
)
parser.add_argument(
'-d', '--debug',
action='store_true',
help='Enable debug mode'
)
parser.add_argument(
'-p', '--print',
action='store_true',
help='Print debug messages to screen'
)
parser.add_argument(
'-e', '--emulated-pty',
action='store_true',
help='Use PTY emulation with escape sequences for input (enables desktop/X/Wayland usage)'
)
parser.add_argument(
'-E', '--emulated-evdev',
action='store_true',
help='Use PTY emulation with evdev for input (single instance)'
)
try:
args = parser.parse_args()
# Only do format validation, let file existence be handled by the config initialization
if args.options:
for option in args.options.split(';'):
if option and ('#' not in option or '=' not in option):
parser.error(f"Invalid option format: {option}\nExpected format: SECTION#SETTING=VALUE")
if args.emulated_pty and args.emulated_evdev:
parser.error("Cannot use both --emulated-pty and --emulated-evdev simultaneously")
return args
except Exception as e:
print(f"Error parsing arguments: {str(e)}", file=sys.stderr)
return None
def proceed(self):
if not self.initialized:
if not self.isInitialized:
return
self.environment['runtime']['eventManager'].startMainEventLoop()
self.shutdown()
def handleInput(self, event):
#startTime = time.time()
self.environment['runtime']['debug'].writeDebugOut('DEBUG INPUT fenrirMan:' + str(event),debug.debugLevel.INFO)
self.environment['runtime']['debug'].writeDebugOut('DEBUG INPUT fenrirMan:' + str(event), debug.debugLevel.INFO)
if not event['Data']:
event['Data'] = self.environment['runtime']['inputManager'].getInputEvent()
if event['Data']:
event['Data']['EventName'] = self.environment['runtime']['inputManager'].convertEventName(event['Data']['EventName'])
self.environment['runtime']['inputManager'].handleInputEvent(event['Data'])
@ -113,6 +54,7 @@ class fenrirManager():
if self.environment['runtime']['inputManager'].noKeyPressed():
self.environment['runtime']['inputManager'].clearLastDeepInput()
if self.environment['runtime']['screenManager'].isSuspendingScreen():
self.environment['runtime']['inputManager'].writeEventBuffer()
else:
@ -132,6 +74,7 @@ class fenrirManager():
self.environment['runtime']['inputManager'].clearEventBuffer()
else:
self.environment['runtime']['inputManager'].writeEventBuffer()
if self.environment['runtime']['inputManager'].noKeyPressed():
self.modifierInput = False
self.singleKeyCommand = False
@ -139,73 +82,59 @@ class fenrirManager():
self.environment['runtime']['inputManager'].handleDeviceGrab()
if self.environment['input']['keyForeward'] > 0:
self.environment['input']['keyForeward'] -=1
self.environment['input']['keyForeward'] -= 1
self.environment['runtime']['commandManager'].executeDefaultTrigger('onKeyInput')
#print('handleInput:',time.time() - startTime)
def handleByteInput(self, event):
if not event['Data']:
return
if event['Data'] == b'':
if not event['Data'] or event['Data'] == b'':
return
self.environment['runtime']['byteManager'].handleByteInput(event['Data'])
self.environment['runtime']['commandManager'].executeDefaultTrigger('onByteInput')
def handleExecuteCommand(self, event):
if not event['Data']:
def handleExecuteCommand(self, event):
if not event['Data'] or event['Data'] == '':
return
if event['Data'] == '':
return
command = event['Data']
currentCommand = event['Data']
# special modes
if self.environment['runtime']['helpManager'].isTutorialMode():
if self.environment['runtime']['commandManager'].commandExists( command, 'help'):
self.environment['runtime']['commandManager'].executeCommand( command, 'help')
if self.environment['runtime']['commandManager'].commandExists(currentCommand, 'help'):
self.environment['runtime']['commandManager'].executeCommand(currentCommand, 'help')
return
elif self.environment['runtime']['vmenuManager'].getActive():
if self.environment['runtime']['commandManager'].commandExists( command, 'vmenu-navigation'):
self.environment['runtime']['commandManager'].executeCommand( command, 'vmenu-navigation')
if self.environment['runtime']['commandManager'].commandExists(currentCommand, 'vmenu-navigation'):
self.environment['runtime']['commandManager'].executeCommand(currentCommand, 'vmenu-navigation')
return
# default
self.environment['runtime']['commandManager'].executeCommand( command, 'commands')
self.environment['runtime']['commandManager'].executeCommand(currentCommand, 'commands')
def handleRemoteIncomming(self, event):
if not event['Data']:
return
self.environment['runtime']['remoteManager'].handleRemoteIncomming(event['Data'])
def handleScreenChange(self, event):
self.environment['runtime']['screenManager'].hanldeScreenChange(event['Data'])
'''
if self.environment['runtime']['applicationManager'].isApplicationChange():
self.environment['runtime']['commandManager'].executeDefaultTrigger('onApplicationChange')
self.environment['runtime']['commandManager'].executeSwitchTrigger('onSwitchApplicationProfile', \
self.environment['runtime']['applicationManager'].getPrevApplication(), \
self.environment['runtime']['applicationManager'].getCurrentApplication())
'''
if self.environment['runtime']['vmenuManager'].getActive():
return
self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenChanged')
self.environment['runtime']['screenDriver'].getCurrScreen()
def handleScreenUpdate(self, event):
#startTime = time.time()
self.environment['runtime']['screenManager'].handleScreenUpdate(event['Data'])
'''
if self.environment['runtime']['applicationManager'].isApplicationChange():
self.environment['runtime']['commandManager'].executeDefaultTrigger('onApplicationChange')
self.environment['runtime']['commandManager'].executeSwitchTrigger('onSwitchApplicationProfile', \
self.environment['runtime']['applicationManager'].getPrevApplication(), \
self.environment['runtime']['applicationManager'].getCurrentApplication())
'''
# timout for the last keypress
if time.time() - self.environment['runtime']['inputManager'].getLastInputTime() >= 0.3:
self.environment['runtime']['inputManager'].clearLastDeepInput()
# has cursor changed?
if self.environment['runtime']['cursorManager'].isCursorVerticalMove() or \
self.environment['runtime']['cursorManager'].isCursorHorizontalMove():
if (self.environment['runtime']['cursorManager'].isCursorVerticalMove() or
self.environment['runtime']['cursorManager'].isCursorHorizontalMove()):
self.environment['runtime']['commandManager'].executeDefaultTrigger('onCursorChange')
self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenUpdate')
self.environment['runtime']['inputManager'].clearLastDeepInput()
#print('handleScreenUpdate:',time.time() - startTime)
def handlePlugInputDevice(self, event):
try:
self.environment['runtime']['inputManager'].setLastDetectedDevices(event['Data'])
@ -214,26 +143,27 @@ class fenrirManager():
self.environment['runtime']['inputManager'].handlePlugInputDevice(event['Data'])
self.environment['runtime']['commandManager'].executeDefaultTrigger('onPlugInputDevice', force=True)
self.environment['runtime']['inputManager'].setLastDetectedDevices(None)
def handleHeartBeat(self, event):
self.environment['runtime']['commandManager'].executeDefaultTrigger('onHeartBeat',force=True)
#self.environment['runtime']['outputManager'].brailleText(flush=False)
def handleHeartBeat(self, event):
self.environment['runtime']['commandManager'].executeDefaultTrigger('onHeartBeat', force=True)
def detectShortcutCommand(self):
if self.environment['input']['keyForeward'] > 0:
return
if len(self.environment['input']['prevInput']) > len(self.environment['input']['currInput']):
return
if self.environment['runtime']['inputManager'].isKeyPress():
self.modifierInput = self.environment['runtime']['inputManager'].currKeyIsModifier()
else:
if not self.environment['runtime']['inputManager'].noKeyPressed():
if self.singleKeyCommand:
self.singleKeyCommand = len(self.environment['input']['currInput'])== 1
# key is already released. we need the old one
if not( self.singleKeyCommand and self.environment['runtime']['inputManager'].noKeyPressed()):
shortcut = self.environment['runtime']['inputManager'].getCurrShortcut()
self.command = self.environment['runtime']['inputManager'].getCommandForShortcut(shortcut)
self.singleKeyCommand = len(self.environment['input']['currInput']) == 1
if not(self.singleKeyCommand and self.environment['runtime']['inputManager'].noKeyPressed()):
currentShortcut = self.environment['runtime']['inputManager'].getCurrShortcut()
self.command = self.environment['runtime']['inputManager'].getCommandForShortcut(currentShortcut)
if not self.modifierInput:
if self.environment['runtime']['inputManager'].isKeyPress():
@ -252,7 +182,8 @@ class fenrirManager():
if self.singleKeyCommand:
self.environment['runtime']['eventManager'].putToEventQueue(fenrirEventType.ExecuteCommand, self.command)
self.command = ''
def setProcessName(self, name = 'fenrir'):
def setProcessName(self, name='fenrir'):
"""Attempts to set the process name to 'fenrir'."""
try:
from setproctitle import setproctitle
@ -273,12 +204,14 @@ class fenrirManager():
pass
return False
def shutdownRequest(self):
try:
self.environment['runtime']['eventManager'].stopMainEventLoop()
except:
pass
def captureSignal(self, siginit, frame):
def captureSignal(self, sigInit, frame):
self.shutdownRequest()
def shutdown(self):
@ -287,10 +220,10 @@ class fenrirManager():
self.environment['runtime']['outputManager'].presentText(_("Quit Fenrir"), soundIcon='ScreenReaderOff', interrupt=True)
self.environment['runtime']['eventManager'].cleanEventQueue()
time.sleep(0.6)
for currManager in self.environment['general']['managerList']:
if self.environment['runtime'][currManager]:
self.environment['runtime'][currManager].shutdown()
del self.environment['runtime'][currManager]
for currentManager in self.environment['general']['managerList']:
if self.environment['runtime'][currentManager]:
self.environment['runtime'][currentManager].shutdown()
del self.environment['runtime'][currentManager]
self.environment = None

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python3
#!/bin/python
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import line_utils
@ -11,27 +11,26 @@ import string, time, re
class outputManager():
def __init__(self):
self.lastEcho = ''
def initialize(self, environment):
self.env = environment
self.env['runtime']['settingsManager'].loadDriver(\
self.env['runtime']['settingsManager'].getSetting('speech', 'driver'), 'speechDriver')
self.env['runtime']['settingsManager'].loadDriver(\
self.env['runtime']['settingsManager'].getSetting('sound', 'driver'), 'soundDriver')
self.env['runtime']['settingsManager'].loadDriver(\
self.env['runtime']['settingsManager'].getSetting('braille', 'driver'), 'brailleDriver')
self.env['runtime']['settingsManager'].loadDriver(
self.env['runtime']['settingsManager'].getSetting('speech', 'driver'), 'speechDriver')
self.env['runtime']['settingsManager'].loadDriver(
self.env['runtime']['settingsManager'].getSetting('sound', 'driver'), 'soundDriver')
def shutdown(self):
self.env['runtime']['settingsManager'].shutdownDriver('soundDriver')
self.env['runtime']['settingsManager'].shutdownDriver('speechDriver')
self.env['runtime']['settingsManager'].shutdownDriver('brailleDriver')
def presentText(self, text, interrupt=True, soundIcon = '', ignorePunctuation=False, announceCapital=False, flush=True, brailleAlternative = ''):
def presentText(self, text, interrupt=True, soundIcon='', ignorePunctuation=False, announceCapital=False, flush=True):
if text == '':
return
if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'readNumbersAsDigits') and len(text.strip()) > 1:
text = re.sub(r"(\d)", r"\1 ", text).rstrip()
self.env['runtime']['debug'].writeDebugOut("presentText:\nsoundIcon:'"+soundIcon+"'\nText:\n" + text ,debug.debugLevel.INFO)
self.env['runtime']['debug'].writeDebugOut("presentText:\nsoundIcon:'"+soundIcon+"'\nText:\n" + text, debug.debugLevel.INFO)
if self.playSoundIcon(soundIcon, interrupt):
self.env['runtime']['debug'].writeDebugOut("soundIcon found" ,debug.debugLevel.INFO)
self.env['runtime']['debug'].writeDebugOut("soundIcon found", debug.debugLevel.INFO)
return
if (len(text) > 1) and (text.strip(string.whitespace) == ''):
return
@ -40,35 +39,31 @@ class outputManager():
if self.playSoundIcon('capital', False):
toAnnounceCapital = False
self.lastEcho = text
self.speakText(text, interrupt, ignorePunctuation,toAnnounceCapital)
if flush:
if brailleAlternative != '':
brlText = brailleAlternative
else:
brlText = text
self.brailleText(brlText, flush)
self.speakText(text, interrupt, ignorePunctuation, toAnnounceCapital)
def getLastEcho(self):
return self.lastEcho
def speakText(self, text, interrupt=True, ignorePunctuation=False, announceCapital=False):
if not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled'):
self.env['runtime']['debug'].writeDebugOut("Speech disabled in outputManager.speakText",debug.debugLevel.INFO)
self.env['runtime']['debug'].writeDebugOut("Speech disabled in outputManager.speakText", debug.debugLevel.INFO)
return
if self.env['runtime']['speechDriver'] == None:
self.env['runtime']['debug'].writeDebugOut("No speechDriver in outputManager.speakText",debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("No speechDriver in outputManager.speakText", debug.debugLevel.ERROR)
return
if interrupt:
self.interruptOutput()
try:
self.env['runtime']['speechDriver'].setLanguage(self.env['runtime']['settingsManager'].getSetting('speech', 'language'))
except Exception as e:
self.env['runtime']['debug'].writeDebugOut("setting speech language in outputManager.speakText",debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("setting speech language in outputManager.speakText", debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)
try:
self.env['runtime']['speechDriver'].setVoice(self.env['runtime']['settingsManager'].getSetting('speech', 'voice'))
except Exception as e:
self.env['runtime']['debug'].writeDebugOut("Error while setting speech voice in outputManager.speakText",debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("Error while setting speech voice in outputManager.speakText", debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)
try:
if announceCapital:
@ -76,199 +71,55 @@ class outputManager():
else:
self.env['runtime']['speechDriver'].setPitch(self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'pitch'))
except Exception as e:
self.env['runtime']['debug'].writeDebugOut("setting speech pitch in outputManager.speakText",debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("setting speech pitch in outputManager.speakText", debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)
try:
self.env['runtime']['speechDriver'].setRate(self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'rate'))
except Exception as e:
self.env['runtime']['debug'].writeDebugOut("setting speech rate in outputManager.speakText",debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("setting speech rate in outputManager.speakText", debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)
try:
self.env['runtime']['speechDriver'].setModule(self.env['runtime']['settingsManager'].getSetting('speech', 'module'))
except Exception as e:
self.env['runtime']['debug'].writeDebugOut("setting speech module in outputManager.speakText",debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("setting speech module in outputManager.speakText", debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)
try:
self.env['runtime']['speechDriver'].setVolume(self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'volume'))
except Exception as e:
self.env['runtime']['debug'].writeDebugOut("setting speech volume in outputManager.speakText ",debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("setting speech volume in outputManager.speakText ", debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)
try:
if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'newLinePause'):
cleanText = text.replace('\n',' , ')
cleanText = text.replace('\n', ' , ')
else:
cleanText = text.replace('\n',' ')
cleanText = text.replace('\n', ' ')
cleanText = self.env['runtime']['textManager'].replaceHeadLines(cleanText)
cleanText = self.env['runtime']['punctuationManager'].proceedPunctuation(cleanText, ignorePunctuation)
cleanText = re.sub(' +$',' ', cleanText)
cleanText = re.sub(' +$', ' ', cleanText)
self.env['runtime']['speechDriver'].speak(cleanText)
self.env['runtime']['debug'].writeDebugOut("Speak: "+ cleanText,debug.debugLevel.INFO)
self.env['runtime']['debug'].writeDebugOut("Speak: "+ cleanText, debug.debugLevel.INFO)
except Exception as e:
self.env['runtime']['debug'].writeDebugOut("\"speak\" in outputManager.speakText ",debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("\"speak\" in outputManager.speakText ", debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)
def brailleText(self, text='', flush=True):
if not self.env['runtime']['settingsManager'].getSettingAsBool('braille', 'enabled'):
return
if self.env['runtime']['brailleDriver'] == None:
return
if flush:
self.env['output']['nextFlush'] = time.time() + self.getFlushTime(text)
self.env['output']['messageOffset'] = {'x':0,'y':0}
self.env['output']['messageText'] = text
displayText = self.getBrailleTextWithOffset(self.env['output']['messageText'], self.env['output']['messageOffset'])
self.env['runtime']['brailleDriver'].writeText('flush '+ displayText)
else:
if self.env['output']['nextFlush'] < time.time():
if self.env['output']['messageText'] != '':
self.env['output']['messageText'] = ''
if self.env['output']['messageOffset'] != None:
self.env['output']['messageOffset'] = None
cursor = self.getBrailleCursor()
x, y, self.env['output']['brlText'] = \
line_utils.getCurrentLine(cursor['x'], cursor['y'], self.env['screen']['newContentText'])
displayText = self.getBrailleTextWithOffset(self.env['screen']['newContentText'], self.env['output']['cursorOffset'], cursor)
self.env['runtime']['brailleDriver'].writeText('notflush ' + displayText)
else:
displayText = self.getBrailleTextWithOffset(self.env['output']['messageText'], self.env['output']['messageOffset'])
self.env['runtime']['brailleDriver'].writeText('flush'+displayText)
def resetSpeechDriver(self):
try:
self.env['runtime']['speechDriver'].reset()
except Exception as e:
self.env['runtime']['debug'].writeDebugOut("reset " + str(e),debug.debugLevel.ERROR)
def getBrailleCursor(self):
if self.env['runtime']['settingsManager'].getSetting('braille', 'cursorFollowMode').upper() == 'REVIEW':
return self.env['runtime']['cursorManager'].getReviewOrTextCursor()
if self.env['runtime']['settingsManager'].getSetting('braille', 'cursorFollowMode').upper() == 'MANUAL':
return self.env['runtime']['cursorManager'].getReviewOrTextCursor()
if self.env['runtime']['settingsManager'].getSetting('braille', 'cursorFollowMode').upper() == 'LAST':
return self.env['runtime']['cursorManager'].getReviewOrTextCursor()
return self.env['runtime']['cursorManager'].getReviewOrTextCursor()
def getFixCursorCell(self):
size = self.env['runtime']['brailleDriver'].getDeviceSize()[0]
fixCell = self.env['runtime']['settingsManager'].getSettingAsInt('braille', 'fixCursorOnCell')
if fixCell <= -1:
return size[0]
if fixCell >= size[0]:
return size[0]
return fixCell
def getActiveOffsetAndText(self):
if self.env['output']['messageOffset']:
return self.env['output']['messageOffset'], self.env['output']['messageText']
if not self.env['output']['cursorOffset']:
return self.getBrailleCursor(), self.env['screen']['newContentText']
return self.env['output']['cursorOffset'], self.env['screen']['newContentText']
def getHorizontalPanSize(self):
size = self.env['runtime']['brailleDriver'].getDeviceSize()
if self.env['runtime']['settingsManager'].getSettingAsInt('braille', 'panSizeHorizontal') <= 0:
return size[0]
if self.env['runtime']['settingsManager'].getSettingAsInt('braille', 'panSizeHorizontal') >= size[0]:
return size[0]
return self.env['runtime']['settingsManager'].getSettingAsInt('braille', 'panSizeHorizontal')
def getHorizontalPanLevel(self,offsetChange = 0):
panned = True
panSize = self.getHorizontalPanSize()
offset, text = self.getActiveOffsetAndText()
currline = text.split('\n')[offset['y']]
newOffsetStart = (int(offset['x'] / panSize) + offsetChange) * panSize
if newOffsetStart < 0:
newOffsetStart = 0
panned = False
if newOffsetStart >= len(text):
newOffsetStart = int((len(text) - panSize - 1) / panSize)
panned = False
return newOffsetStart, panned
def setPanLeft(self):
newPan, panned = self.getHorizontalPanLevel(-1)
if self.env['output']['messageOffset']:
self.env['output']['messageOffset'] = newPan.copy()
else:
self.env['output']['cursorOffset'] = newPan.copy()
return panned
def setPanRight(self):
newPan, panned = self.getHorizontalPanLevel(1)
if self.env['output']['messageOffset']:
self.env['output']['messageOffset'] = newPan.copy()
else:
self.env['output']['cursorOffset'] = newPan.copy()
return panned
def removePanning(self):
if self.env['output']['messageOffset']:
self.env['output']['messageOffset'] = None
else:
self.env['output']['cursorOffset'] = None
def getBrailleTextWithOffset(self, text, offset = None, cursor = None):
if text == '':
return ''
size = self.env['runtime']['brailleDriver'].getDeviceSize()
offsetText = text
if cursor and not offset:
if self.env['runtime']['settingsManager'].getSetting('braille', 'cursorFollowMode').upper() == 'FIXCELL':
#fix cell
cursorCell = self.getFixCursorCell()
offsetStart = cursor['x']
if offsetStart < size[0]:
if offsetStart <= cursorCell:
return offsetText[0: size[0]]
offsetStart -= cursorCell
if offsetStart >= len(offsetText):
offsetStart = len(offsetText) - 1
else:
# page and fallback
offsetStart = int(cursor['x'] / size[0]) * size[0]
else:
if not offset:
offset = {'x':0,'y':0}
offsetStart = offset['x']
if offsetStart >= len(offsetText):
offsetStart = len(offsetText) - size[0]
if offsetStart < 0:
offsetStart = 0
offsetEnd = offsetStart + size[0]
offsetText = offsetText[offsetStart: offsetEnd]
return offsetText
def interruptOutput(self):
try:
self.env['runtime']['speechDriver'].cancel()
self.env['runtime']['debug'].writeDebugOut("Interrupt speech",debug.debugLevel.INFO)
self.env['runtime']['debug'].writeDebugOut("Interrupt speech", debug.debugLevel.INFO)
except:
pass
def clearFlushTime(self):
self.setFlushTime(0.0)
def setFlushTime(self,newTime):
self.env['output']['nextFlush'] = newTime
def getFlushTime(self,text=''):
if self.env['runtime']['settingsManager'].getSettingAsFloat('braille', 'flushTimeout') < 0 or \
self.env['runtime']['settingsManager'].getSetting('braille', 'flushMode').upper() == 'NONE':
return 999999999999
if self.env['runtime']['settingsManager'].getSetting('braille', 'flushMode').upper() == 'FIX':
return self.env['runtime']['settingsManager'].getSettingAsFloat('braille', 'flushTimeout')
if self.env['runtime']['settingsManager'].getSetting('braille', 'flushMode').upper() == 'CHAR':
return self.env['runtime']['settingsManager'].getSettingAsFloat('braille', 'flushTimeout') * len(text)
if self.env['runtime']['settingsManager'].getSetting('braille', 'flushMode').upper() == 'WORD':
wordsList = text.split(' ')
return self.env['runtime']['settingsManager'].getSettingAsFloat('braille', 'flushTimeout') * len( list( filter(None, wordsList) ) )
def playSoundIcon(self, soundIcon = '', interrupt=True):
def playSoundIcon(self, soundIcon='', interrupt=True):
if soundIcon == '':
return False
soundIcon = soundIcon.upper()
if not self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled'):
self.env['runtime']['debug'].writeDebugOut("Sound disabled in outputManager.playSoundIcon",debug.debugLevel.INFO)
self.env['runtime']['debug'].writeDebugOut("Sound disabled in outputManager.playSoundIcon", debug.debugLevel.INFO)
return False
try:
@ -278,40 +129,40 @@ class outputManager():
return False
if self.env['runtime']['soundDriver'] == None:
self.env['runtime']['debug'].writeDebugOut("No soundDriver in outputManager.playSoundIcon: soundDriver not loaded",debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("No soundDriver in outputManager.playSoundIcon: soundDriver not loaded", debug.debugLevel.ERROR)
return False
try:
self.env['runtime']['soundDriver'].setVolume(self.env['runtime']['settingsManager'].getSettingAsFloat('sound', 'volume'))
except Exception as e:
self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::setVolume: " + str(e),debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::setVolume: " + str(e), debug.debugLevel.ERROR)
try:
self.env['runtime']['soundDriver'].playSoundFile(self.env['soundIcons'][soundIcon], interrupt)
return True
except Exception as e:
self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::playSoundFile: " + str(e),debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::playSoundFile: " + str(e), debug.debugLevel.ERROR)
return False
return False
def playFrequence(self, frequence, duration, interrupt=True):
if not self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled'):
self.env['runtime']['debug'].writeDebugOut("Sound disabled in outputManager.playFrequence",debug.debugLevel.INFO)
self.env['runtime']['debug'].writeDebugOut("Sound disabled in outputManager.playFrequence", debug.debugLevel.INFO)
return False
if frequence < 1 or frequence > 20000:
self.env['runtime']['debug'].writeDebugOut("outputManager.playFrequence::Filefrequence is out of range:" + str(frequence),debug.debugLevel.INFO)
self.env['runtime']['debug'].writeDebugOut("outputManager.playFrequence::Filefrequence is out of range:" + str(frequence), debug.debugLevel.INFO)
return False
if self.env['runtime']['soundDriver'] == None:
self.env['runtime']['debug'].writeDebugOut("No soundDriver in outputManager.playFrequence: soundDriver not loaded",debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("No soundDriver in outputManager.playFrequence: soundDriver not loaded", debug.debugLevel.ERROR)
return False
try:
self.env['runtime']['soundDriver'].setVolume(self.env['runtime']['settingsManager'].getSettingAsFloat('sound', 'volume'))
except Exception as e:
self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::setVolume: " + str(e),debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::setVolume: " + str(e), debug.debugLevel.ERROR)
adjustVolume = 0.0
try:
adjustVolume = 1.0 - (frequence / 20000)
@ -324,7 +175,7 @@ class outputManager():
self.env['runtime']['soundDriver'].playFrequence(frequence, duration, adjustVolume, interrupt)
return True
except Exception as e:
self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::playSoundFile: " + str(e),debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::playSoundFile: " + str(e), debug.debugLevel.ERROR)
return False
return False
@ -335,9 +186,9 @@ class outputManager():
self.env['commandBuffer']['enableSpeechOnKeypress'] = True
self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', str(not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled')))
self.interruptOutput()
def announceActiveCursor(self, interrupt_p=False):
if self.env['runtime']['cursorManager'].isReviewMode():
self.presentText(' review cursor ', interrupt=interrupt_p)
else:
self.presentText(' text cursor ', interrupt=interrupt_p)

View File

@ -12,7 +12,6 @@ runtimeData = {
'soundDriver': None,
'inputDriver': None,
'remoteDriver': None,
'brailleDriver': None,
'inputManager': None,
'commandManager': None,
'screenManager': None,

View File

@ -59,8 +59,6 @@ class screenManager():
if self.isCurrScreenIgnoredChanged():
self.env['runtime']['inputManager'].setExecuteDeviceGrab()
self.env['runtime']['inputManager'].handleDeviceGrab()
if self.isScreenChange():
self.changeBrailleScreen()
if not self.isSuspendingScreen(self.env['screen']['newTTY']):
self.update(eventData, 'onScreenChange')
self.env['screen']['lastScreenUpdate'] = time.time()
@ -74,9 +72,6 @@ class screenManager():
self.env['runtime']['inputManager'].handleDeviceGrab()
if not self.getCurrScreenIgnored():
self.update(eventData, 'onScreenUpdate')
#if trigger == 'onUpdate' or self.isScreenChange() \
# or len(self.env['screen']['newDelta']) > 6:
# self.env['runtime']['screenDriver'].getCurrApplication()
self.env['screen']['lastScreenUpdate'] = time.time()
elif self.isCurrScreenIgnoredChanged():
self.env['runtime']['outputManager'].interruptOutput()
@ -145,14 +140,10 @@ class screenManager():
self.env['screen']['newContentText'][cursorLineEnd:] == self.env['screen']['oldContentText'][cursorLineEnd:]:
cursorLineStartOffset = cursorLineStart
cursorLineEndOffset = cursorLineEnd
#if cursorLineStart < cursorLineStart + self.env['screen']['newCursor']['x'] - 4:
# cursorLineStartOffset = cursorLineStart + self.env['screen']['newCursor']['x'] - 4
if cursorLineEnd > cursorLineStart + self.env['screen']['newCursor']['x'] + 3:
cursorLineEndOffset = cursorLineStart + self.env['screen']['newCursor']['x'] + 3
oldScreenText = self.env['screen']['oldContentText'][cursorLineStartOffset:cursorLineEndOffset]
# oldScreenText = re.sub(' +',' ',oldScreenText)
newScreenText = self.env['screen']['newContentText'][cursorLineStartOffset:cursorLineEndOffset]
#newScreenText = re.sub(' +',' ',newScreenText)
diff = self.differ.compare(oldScreenText, newScreenText)
diffList = list(diff)
typing = True
@ -221,21 +212,4 @@ class screenManager():
try:
self.env['runtime']['screenDriver'].injectTextToScreen(text, screen)
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('screenManager:injectTextToScreen ' + str(e),debug.debugLevel.ERROR)
def changeBrailleScreen(self):
if not self.env['runtime']['settingsManager'].getSettingAsBool('braille', 'enabled'):
return
if not self.env['runtime']['brailleDriver']:
return
if self.env['screen']['oldTTY']:
if not self.isSuspendingScreen(self.env['screen']['oldTTY']):
try:
self.env['runtime']['brailleDriver'].leveScreen()
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('screenManager:changeBrailleScreen:leveScreen ' + str(e),debug.debugLevel.ERROR)
if not self.isSuspendingScreen():
try:
self.env['runtime']['brailleDriver'].enterScreen(self.env['screen']['newTTY'])
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('screenManager:changeBrailleScreen:enterScreen ' + str(e),debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut('screenManager:injectTextToScreen ' + str(e),debug.debugLevel.ERROR)

View File

@ -36,17 +36,6 @@ settingsData = {
'fenrirMinRate':80,
'fenrirMaxRate':450,
},
'braille':{
'enabled': False,
'driver':'brlapiDriver',
'layout': 'en',
'flushMode': 'word', #NONE,FIX,CHAR,WORD
'flushTimeout': 3,
'cursorFocusMode':'page', # page,fixCell
'fixCursorOnCell': -1,
'cursorFollowMode': 'review', # none, review, last, text
'panSizeHorizontal': 0 # 0 = display size
},
'screen':{
'driver': 'vcsaDriver',
'encoding': 'auto',