Removed Braille. BrlTTY does a great job already in the console. Also, Fenrir's implementation was only partially done and not working.

This commit is contained in:
Storm Dragon 2024-12-08 06:43:22 -05:00
parent 3757a1ceeb
commit baa4c9a937
22 changed files with 58 additions and 810 deletions

View File

@ -16,7 +16,7 @@ This software is licensed under the LGPL v3.
# Core Requirements # Core Requirements
- python3 >= 3.3 - python3 >= 3.3
- screen, input, speech, sound or braille drivers dependencies see "Features, Drivers, Extras". - screen, input, speech, sound drivers dependencies see "Features, Drivers, Extras".
# Features, Drivers, Extras, Dependencies # Features, Drivers, Extras, Dependencies
@ -59,13 +59,6 @@ This software is licensed under the LGPL v3.
- emacspeak - emacspeak
# Braille Drivers:
1. "BrlttyDriver" braille driver (WIP):
- brltty (configured and running)
- python-brlapi
# Sound Drivers: # Sound Drivers:
1. "genericDriver" (default) sound driver for sound as subprocess: 1. "genericDriver" (default) sound driver for sound as subprocess:
@ -113,7 +106,6 @@ Take care to use drivers from the config matching your installed drivers.
By default it uses: By default it uses:
- sound driver: genericDriver (via sox, could configured in settings.conf) - sound driver: genericDriver (via sox, could configured in settings.conf)
- speech driver: genericDriver (via espeak or espeak-ng, could configured in settings.conf) - speech driver: genericDriver (via espeak or espeak-ng, could configured in settings.conf)
- braille driver: brlttyDriver (WIP)
- input driver: evdevDriver - input driver: evdevDriver

View File

@ -8,7 +8,7 @@ from typing import List, Optional
@dataclass @dataclass
class Dependency: class Dependency:
name: str name: str
depType: str # screen, braille, input, sound, speech, core depType: str # screen, input, sound, speech, core
moduleName: str moduleName: str
checkCommands: Optional[List[str]] = None # Command-line tools to check checkCommands: Optional[List[str]] = None # Command-line tools to check
pythonImports: Optional[List[str]] = None # Python packages to check pythonImports: Optional[List[str]] = None # Python packages to check
@ -60,12 +60,6 @@ dependencyList = [
Dependency('PTY', 'screen', 'ptyDriver', Dependency('PTY', 'screen', 'ptyDriver',
pythonImports=['pyte']), pythonImports=['pyte']),
# Braille drivers
Dependency('DummyBraille', 'braille', 'dummyDriver'),
Dependency('DebugBraille', 'braille', 'debugDriver'),
Dependency('BRLAPI', 'braille', 'brlapiDriver',
pythonImports=['brlapi']),
# Input drivers # Input drivers
Dependency('DummyInput', 'input', 'dummyDriver'), Dependency('DummyInput', 'input', 'dummyDriver'),
Dependency('DebugInput', 'input', 'debugDriver'), Dependency('DebugInput', 'input', 'debugDriver'),
@ -94,7 +88,6 @@ dependencyList = [
defaultModules = { defaultModules = {
'FenrirCore', 'FenrirCore',
'VCSA', 'VCSA',
'DummyBraille',
'Evdev', 'Evdev',
'GenericSpeech', 'GenericSpeech',
'GenericSound' 'GenericSound'
@ -105,7 +98,7 @@ def check_all_dependencies():
availableModules = [] availableModules = []
# Group dependencies by type for organized output # Group dependencies by type for organized output
for depType in ['core', 'screen', 'braille', 'input', 'sound', 'speech']: for depType in ['core', 'screen', 'input', 'sound', 'speech']:
print(f'{depType.upper()} DRIVERS') print(f'{depType.upper()} DRIVERS')
print('-' * 20) print('-' * 20)

View File

@ -91,37 +91,6 @@ fenrirMaxPitch=99
fenrirMinRate=80 fenrirMinRate=80
fenrirMaxRate=450 fenrirMaxRate=450
[braille]
enabled=False
driver=dummyDriver
layout=en
# to what should the flush timeout relate to
# word = flush after (number of words to display) * seconds
# char = flush after (number of chars to display) * seconds
# fix = flush after X seconds
# none = no automatic flush (manual via shortcut)
flushMode=word
# seconds to flush or
# -1 = no automatic flush (manual via shortcut)
flushTimeout=3
# how should the cursor be focused?
# page = if cursor cross the border move to next page and start at beginn
# fixCell = ajust the cursor on an special cell where it is always placed. the display scroll here more smooth.
cursorFocusMode=page
# define the cell on the Braille device where fenrir should scroll and keep the cursor
# 0 = first cell on device
# -1 = last cell on device
# >0 = fix cell number
fixCursorOnCell=-1
#How should the braille follow the focus
# none = no automatic toggle command used
# review = priority to review
# last = follow last used cursor
cursorFollowMode=review
# number of cells in panning (horizontal)
# 0 = display size, >0 number of cells
panSizeHorizontal=0
[screen] [screen]
driver=vcsaDriver driver=vcsaDriver
encoding=auto encoding=auto

View File

@ -119,5 +119,4 @@ print('once as their user account and once as root to configure Pulseaudio.')
print('Please install the following packages manually:') print('Please install the following packages manually:')
print('- Speech-dispatcher: for the default speech driver') print('- Speech-dispatcher: for the default speech driver')
print('- Espeak: as basic TTS engine') print('- Espeak: as basic TTS engine')
print('- BrlTTY: for Braille')
print('- sox: is a player for the generic sound driver') print('- sox: is a player for the generic sound driver')

View File

@ -1,176 +0,0 @@
#!/bin/python
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.brailleDriver import brailleDriver
class driver(brailleDriver):
"""BRLAPI implementation of the braille driver interface."""
def __init__(self):
"""Initialize the BRLAPI driver."""
brailleDriver.__init__(self)
self._brl = None
self._last_written_text = ""
def initialize(self, environment):
"""Initialize the braille driver with BRLAPI connection."""
self.env = environment
try:
import brlapi
self._brl = brlapi.Connection()
self._deviceSize = self._brl.displaySize
self._brl.acceptKeys(brlapi.rangeType_all, [0, brlapi.KEY_MAX])
self._current_cursor_pos = 0
except Exception as e:
self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)
return
self._isInitialized = True
def getDeviceSize(self):
"""Get the size of the connected braille display."""
if not self._isInitialized or not self._deviceSize:
return (0, 0)
return self._deviceSize
def writeText(self, text):
"""Write text to the braille display.
Handles both flush and non-flush text from the output manager."""
if not self._isInitialized:
return
try:
# Remove the 'flush ' or 'notflush ' prefix
if text.startswith('flush '):
text = text[6:] # Remove 'flush ' prefix
elif text.startswith('notflush '):
text = text[9:] # Remove 'notflush ' prefix
self._last_written_text = text
# Handle unicode properly for international braille
if isinstance(text, str):
self._brl.writeText(text)
else:
self._brl.writeText(text.decode('utf-8', 'replace'))
# Update cursor if needed
if 'screen' in self.env and 'newCursorReview' in self.env['screen']:
new_pos = self.env['screen']['newCursorReview']['x']
if new_pos != self._current_cursor_pos:
self.setCursor(new_pos)
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('BRAILLE.writeText ' + str(e), debug.debugLevel.ERROR)
def connectDevice(self):
"""Establish connection with BRLAPI."""
try:
import brlapi
self._brl = brlapi.Connection()
self._brl.acceptKeys(brlapi.rangeType_all, [0, brlapi.KEY_MAX])
return True
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('BRAILLE.connectDevice ' + str(e), debug.debugLevel.ERROR)
return False
def enterScreen(self, screen):
"""Enter a specific TTY mode."""
if not self._isInitialized:
return
try:
self._brl.enterTtyMode(int(screen))
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('BRAILLE.enterScreen ' + str(e), debug.debugLevel.ERROR)
def leaveScreen(self):
"""Leave the current TTY mode."""
if not self._isInitialized:
return
try:
self._brl.leaveTtyMode()
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('BRAILLE.leaveScreen ' + str(e), debug.debugLevel.ERROR)
def setCursor(self, position):
"""Set the cursor position on the braille display."""
if not self._isInitialized:
return
try:
max_pos = self.getDeviceSize()[0] - 1
self._current_cursor_pos = max(0, min(position, max_pos))
self._brl.writeDots(1 << self._current_cursor_pos)
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('BRAILLE.setCursor ' + str(e), debug.debugLevel.ERROR)
def getCursorPosition(self):
"""Get the current cursor position."""
if not self._isInitialized:
return 0
return self._current_cursor_pos
def clear(self):
"""Clear the braille display."""
if not self._isInitialized:
return
try:
self._brl.writeText('')
self._last_written_text = ""
self._current_cursor_pos = 0
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('BRAILLE.clear ' + str(e), debug.debugLevel.ERROR)
def flush(self):
"""Force an update of the physical display."""
if not self._isInitialized:
return
try:
if self._last_written_text:
self._brl.writeText(self._last_written_text)
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('BRAILLE.flush ' + str(e), debug.debugLevel.ERROR)
def handleKeyInput(self, key):
"""Handle input from any BRLTTY-compatible braille display."""
if not self._isInitialized:
return False
try:
key_code = self._brl.readKey(wait=0)
if not key_code:
return False
if self.env['runtime']['debug'].debugLevel >= debug.debugLevel.INFO:
self.env['runtime']['debug'].writeDebugOut(
'BRAILLE.keyPressed: ' + str(key_code),
debug.debugLevel.INFO
)
return True
except brlapi.ConnectionError:
self.env['runtime']['debug'].writeDebugOut(
'BRAILLE: Connection lost. Attempting to reconnect...',
debug.debugLevel.ERROR
)
self.connectDevice()
return False
except Exception as e:
self.env['runtime']['debug'].writeDebugOut(
'BRAILLE.handleKeyInput ' + str(e),
debug.debugLevel.ERROR
)
return False
def shutdown(self):
"""Shut down the BRLAPI driver."""
if not self._isInitialized:
return
try:
self.clear()
self.leaveScreen()
if self._brl:
self._brl.closeConnection()
self._brl = None
self._isInitialized = False
except Exception as e:
self.env['runtime']['debug'].writeDebugOut('BRAILLE.shutdown ' + str(e), debug.debugLevel.ERROR)

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): def run(self):
if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled') or \ if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled') or \
self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled') or \ self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled'):
self.env['runtime']['settingsManager'].getSettingAsBool('braille', 'enabled'):
self.env['runtime']['outputManager'].presentText(_('Fenrir muted'), soundIcon='Accept', interrupt=True) self.env['runtime']['outputManager'].presentText(_('Fenrir muted'), soundIcon='Accept', interrupt=True)
self.env['runtime']['settingsManager'].setSetting('speech', 'enabled','False') self.env['runtime']['settingsManager'].setSetting('speech', 'enabled','False')
self.env['runtime']['settingsManager'].setSetting('sound', 'enabled','False') self.env['runtime']['settingsManager'].setSetting('sound', 'enabled','False')
self.env['runtime']['settingsManager'].setSetting('braille', 'enabled','False')
else: else:
self.env['runtime']['settingsManager'].setSetting('speech', 'enabled','True') self.env['runtime']['settingsManager'].setSetting('speech', 'enabled','True')
self.env['runtime']['settingsManager'].setSetting('sound', '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) self.env['runtime']['outputManager'].presentText(_('Fenrir unmuted'), soundIcon='Cancel', interrupt=True)
def setCallback(self, callback): def setCallback(self, callback):

View File

@ -1,156 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
from abc import ABC, abstractmethod
from fenrirscreenreader.core import debug
class brailleDriver(ABC):
"""Base class for Fenrir braille display drivers.
This abstract base class defines the interface that all braille drivers must implement.
It provides basic initialization state tracking and defines the required methods
for interacting with braille displays.
"""
def __init__(self):
"""Initialize the driver with default state."""
self._isInitialized = False
self.deviceSize = None
self.env = None
self._current_cursor_pos = 0
self._display_content = ""
@abstractmethod
def initialize(self, environment):
"""Initialize the braille driver with the given environment.
Args:
environment (dict): The Fenrir environment dictionary containing runtime settings
and helper objects.
"""
self.env = environment
self._isInitialized = True
@abstractmethod
def getDeviceSize(self):
"""Get the size of the connected braille display.
Returns:
tuple: A (columns, rows) tuple indicating the display dimensions.
Returns (0, 0) if no display is connected or not initialized.
"""
if not self._isInitialized:
return (0, 0)
return (0, 0)
@abstractmethod
def writeText(self, text):
"""Write text to the braille display.
Args:
text (str): The text to be written to the display.
"""
if not self._isInitialized:
return
@abstractmethod
def connectDevice(self):
"""Establish connection with the braille display.
This method should handle the initial connection setup with the display.
It should be called before any other display operations.
"""
pass
@abstractmethod
def enterScreen(self, screen):
"""Enter a specific screen/TTY mode.
Args:
screen (int): The screen/TTY number to enter.
"""
if not self._isInitialized:
return
@abstractmethod
def leaveScreen(self):
"""Leave the current screen/TTY mode.
This method should clean up any screen-specific state and
prepare for potential screen switches.
"""
if not self._isInitialized:
return
@abstractmethod
def setCursor(self, position):
"""Set the cursor position on the braille display.
Args:
position (int): The position where the cursor should be placed.
"""
if not self._isInitialized:
return
self._current_cursor_pos = max(0, min(position, self.getDeviceSize()[0] - 1))
@abstractmethod
def getCursorPosition(self):
"""Get the current cursor position on the braille display.
Returns:
int: The current cursor position.
"""
if not self._isInitialized:
return 0
return self._current_cursor_pos
@abstractmethod
def clear(self):
"""Clear the braille display."""
if not self._isInitialized:
return
self._display_content = ""
self._current_cursor_pos = 0
@abstractmethod
def flush(self):
"""Force an update of the physical display with current content."""
if not self._isInitialized:
return
def shutdown(self):
"""Shut down the braille driver and clean up resources.
This method ensures proper cleanup of resources and
disconnection from the braille display.
"""
if not self._isInitialized:
return
self.clear()
self.leaveScreen()
self._isInitialized = False
@property
def is_initialized(self):
"""Check if the driver is initialized.
Returns:
bool: True if the driver is initialized, False otherwise.
"""
return self._isInitialized
@abstractmethod
def handleKeyInput(self, key):
"""Handle input from the braille display's keys.
Args:
key: The key event from the braille display.
Returns:
bool: True if the key was handled, False otherwise.
"""
if not self._isInitialized:
return False
return False

View File

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

View File

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

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python3 #!/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers. # By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import line_utils from fenrirscreenreader.utils import line_utils
@ -11,20 +11,19 @@ import string, time, re
class outputManager(): class outputManager():
def __init__(self): def __init__(self):
self.lastEcho = '' self.lastEcho = ''
def initialize(self, environment): def initialize(self, environment):
self.env = environment self.env = environment
self.env['runtime']['settingsManager'].loadDriver(\ self.env['runtime']['settingsManager'].loadDriver(
self.env['runtime']['settingsManager'].getSetting('speech', 'driver'), 'speechDriver') self.env['runtime']['settingsManager'].getSetting('speech', 'driver'), 'speechDriver')
self.env['runtime']['settingsManager'].loadDriver(\ self.env['runtime']['settingsManager'].loadDriver(
self.env['runtime']['settingsManager'].getSetting('sound', 'driver'), 'soundDriver') self.env['runtime']['settingsManager'].getSetting('sound', 'driver'), 'soundDriver')
self.env['runtime']['settingsManager'].loadDriver(\
self.env['runtime']['settingsManager'].getSetting('braille', 'driver'), 'brailleDriver')
def shutdown(self): def shutdown(self):
self.env['runtime']['settingsManager'].shutdownDriver('soundDriver') self.env['runtime']['settingsManager'].shutdownDriver('soundDriver')
self.env['runtime']['settingsManager'].shutdownDriver('speechDriver') 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 == '': if text == '':
return return
if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'readNumbersAsDigits') and len(text.strip()) > 1: if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'readNumbersAsDigits') and len(text.strip()) > 1:
@ -41,14 +40,10 @@ class outputManager():
toAnnounceCapital = False toAnnounceCapital = False
self.lastEcho = text self.lastEcho = text
self.speakText(text, interrupt, ignorePunctuation, toAnnounceCapital) self.speakText(text, interrupt, ignorePunctuation, toAnnounceCapital)
if flush:
if brailleAlternative != '':
brlText = brailleAlternative
else:
brlText = text
self.brailleText(brlText, flush)
def getLastEcho(self): def getLastEcho(self):
return self.lastEcho return self.lastEcho
def speakText(self, text, interrupt=True, ignorePunctuation=False, announceCapital=False): def speakText(self, text, interrupt=True, ignorePunctuation=False, announceCapital=False):
if not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled'): 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)
@ -112,132 +107,6 @@ class outputManager():
self.env['runtime']['debug'].writeDebugOut("\"speak\" in outputManager.speakText ", 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) 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): def interruptOutput(self):
try: try:
self.env['runtime']['speechDriver'].cancel() self.env['runtime']['speechDriver'].cancel()
@ -245,24 +114,6 @@ class outputManager():
except: except:
pass 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 == '': if soundIcon == '':
return False return False
@ -335,9 +186,9 @@ class outputManager():
self.env['commandBuffer']['enableSpeechOnKeypress'] = True self.env['commandBuffer']['enableSpeechOnKeypress'] = True
self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', str(not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled'))) self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', str(not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled')))
self.interruptOutput() self.interruptOutput()
def announceActiveCursor(self, interrupt_p=False): def announceActiveCursor(self, interrupt_p=False):
if self.env['runtime']['cursorManager'].isReviewMode(): if self.env['runtime']['cursorManager'].isReviewMode():
self.presentText(' review cursor ', interrupt=interrupt_p) self.presentText(' review cursor ', interrupt=interrupt_p)
else: else:
self.presentText(' text cursor ', interrupt=interrupt_p) self.presentText(' text cursor ', interrupt=interrupt_p)

View File

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

View File

@ -59,8 +59,6 @@ class screenManager():
if self.isCurrScreenIgnoredChanged(): if self.isCurrScreenIgnoredChanged():
self.env['runtime']['inputManager'].setExecuteDeviceGrab() self.env['runtime']['inputManager'].setExecuteDeviceGrab()
self.env['runtime']['inputManager'].handleDeviceGrab() self.env['runtime']['inputManager'].handleDeviceGrab()
if self.isScreenChange():
self.changeBrailleScreen()
if not self.isSuspendingScreen(self.env['screen']['newTTY']): if not self.isSuspendingScreen(self.env['screen']['newTTY']):
self.update(eventData, 'onScreenChange') self.update(eventData, 'onScreenChange')
self.env['screen']['lastScreenUpdate'] = time.time() self.env['screen']['lastScreenUpdate'] = time.time()
@ -74,9 +72,6 @@ class screenManager():
self.env['runtime']['inputManager'].handleDeviceGrab() self.env['runtime']['inputManager'].handleDeviceGrab()
if not self.getCurrScreenIgnored(): if not self.getCurrScreenIgnored():
self.update(eventData, 'onScreenUpdate') 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() self.env['screen']['lastScreenUpdate'] = time.time()
elif self.isCurrScreenIgnoredChanged(): elif self.isCurrScreenIgnoredChanged():
self.env['runtime']['outputManager'].interruptOutput() self.env['runtime']['outputManager'].interruptOutput()
@ -145,14 +140,10 @@ class screenManager():
self.env['screen']['newContentText'][cursorLineEnd:] == self.env['screen']['oldContentText'][cursorLineEnd:]: self.env['screen']['newContentText'][cursorLineEnd:] == self.env['screen']['oldContentText'][cursorLineEnd:]:
cursorLineStartOffset = cursorLineStart cursorLineStartOffset = cursorLineStart
cursorLineEndOffset = cursorLineEnd 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: if cursorLineEnd > cursorLineStart + self.env['screen']['newCursor']['x'] + 3:
cursorLineEndOffset = cursorLineStart + self.env['screen']['newCursor']['x'] + 3 cursorLineEndOffset = cursorLineStart + self.env['screen']['newCursor']['x'] + 3
oldScreenText = self.env['screen']['oldContentText'][cursorLineStartOffset:cursorLineEndOffset] oldScreenText = self.env['screen']['oldContentText'][cursorLineStartOffset:cursorLineEndOffset]
# oldScreenText = re.sub(' +',' ',oldScreenText)
newScreenText = self.env['screen']['newContentText'][cursorLineStartOffset:cursorLineEndOffset] newScreenText = self.env['screen']['newContentText'][cursorLineStartOffset:cursorLineEndOffset]
#newScreenText = re.sub(' +',' ',newScreenText)
diff = self.differ.compare(oldScreenText, newScreenText) diff = self.differ.compare(oldScreenText, newScreenText)
diffList = list(diff) diffList = list(diff)
typing = True typing = True
@ -222,20 +213,3 @@ class screenManager():
self.env['runtime']['screenDriver'].injectTextToScreen(text, screen) self.env['runtime']['screenDriver'].injectTextToScreen(text, screen)
except Exception as e: except Exception as e:
self.env['runtime']['debug'].writeDebugOut('screenManager:injectTextToScreen ' + str(e),debug.debugLevel.ERROR) 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)

View File

@ -36,17 +36,6 @@ settingsData = {
'fenrirMinRate':80, 'fenrirMinRate':80,
'fenrirMaxRate':450, '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':{ 'screen':{
'driver': 'vcsaDriver', 'driver': 'vcsaDriver',
'encoding': 'auto', 'encoding': 'auto',

View File

@ -31,13 +31,9 @@ class FenrirConfigTool:
self.presetOptions = { self.presetOptions = {
'sound.driver': ['genericDriver', 'gstreamerDriver'], 'sound.driver': ['genericDriver', 'gstreamerDriver'],
'speech.driver': ['speechdDriver', 'genericDriver'], 'speech.driver': ['speechdDriver', 'genericDriver'],
'braille.driver': ['dummyDriver', 'brailttyDriver', 'brlapiDriver'],
'screen.driver': ['vcsaDriver', 'dummyDriver', 'ptyDriver', 'debugDriver'], 'screen.driver': ['vcsaDriver', 'dummyDriver', 'ptyDriver', 'debugDriver'],
'keyboard.driver': ['evdevDriver', 'dummyDriver'], 'keyboard.driver': ['evdevDriver', 'dummyDriver'],
'remote.driver': ['unixDriver', 'tcpDriver'], 'remote.driver': ['unixDriver', 'tcpDriver'],
'braille.flushMode': ['word', 'char', 'fix', 'none'],
'braille.cursorFocusMode': ['page', 'fixCell'],
'braille.cursorFollowMode': ['review', 'last', 'none'],
'keyboard.charEchoMode': ['0', '1', '2'], 'keyboard.charEchoMode': ['0', '1', '2'],
'general.punctuationLevel': ['none', 'some', 'most', 'all'], 'general.punctuationLevel': ['none', 'some', 'most', 'all'],
'general.debugMode': ['File', 'Print'] 'general.debugMode': ['File', 'Print']
@ -47,8 +43,7 @@ class FenrirConfigTool:
'sound.volume': 'Volume level from 0 (quietest) to 1.0 (loudest)', 'sound.volume': 'Volume level from 0 (quietest) to 1.0 (loudest)',
'speech.rate': 'Speech rate from 0 (slowest) to 1.0 (fastest)', 'speech.rate': 'Speech rate from 0 (slowest) to 1.0 (fastest)',
'speech.pitch': 'Voice pitch from 0 (lowest) to 1.0 (highest)', 'speech.pitch': 'Voice pitch from 0 (lowest) to 1.0 (highest)',
'keyboard.charEchoMode': '0 = None, 1 = always, 2 = only while capslock', 'keyboard.charEchoMode': '0 = None, 1 = always, 2 = only while capslock'
'braille.flushMode': 'word = flush after words, char = flush after chars, fix = flush after time, none = manual flush'
} }
def check_root(self) -> bool: def check_root(self) -> bool: