Updated Braille support now that I'm more familiar with how it should work.

This commit is contained in:
Storm Dragon
2024-12-08 04:37:53 -05:00
parent 84514edc96
commit 1696d62526
2 changed files with 249 additions and 73 deletions

View File

@ -1,82 +1,156 @@
#!/usr/bin/python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
import brlapi
from abc import ABC, abstractmethod
from fenrirscreenreader.core import debug
class brailleDriver():
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._brl = None
self.deviceSize = None
self.env = None
self._current_cursor_pos = 0
self._display_content = ""
@abstractmethod
def initialize(self, environment):
"""Initialize the BRLTTY connection."""
"""Initialize the braille driver with the given environment.
Args:
environment (dict): The Fenrir environment dictionary containing runtime settings
and helper objects.
"""
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
self._isInitialized = True
@abstractmethod
def getDeviceSize(self):
"""Get the size of the braille display."""
"""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 self.deviceSize if self.deviceSize else (0, 0)
return (0, 0)
@abstractmethod
def writeText(self, text):
"""Write text to the braille display."""
"""Write text to the braille display.
Args:
text (str): The text to be written to the 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
@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 new screen context."""
"""Enter a specific screen/TTY mode.
Args:
screen (int): The screen/TTY number to enter.
"""
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)
@abstractmethod
def leaveScreen(self):
"""Leave the current screen context."""
"""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
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."""
"""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
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)
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