Detected screen reader now show in the menu instead of generic phrase screen reader.
This commit is contained in:
@@ -741,7 +741,6 @@ class BookReader:
|
||||
else:
|
||||
message = f"Screen reader engine active: {self.readingEngine.get_active_reader_name()}"
|
||||
print(message)
|
||||
self.speechEngine.speak(message)
|
||||
else:
|
||||
# Reload piper-tts with new voice (check if available first)
|
||||
if not TtsEngine.is_available():
|
||||
|
||||
+42
-12
@@ -9,6 +9,7 @@ Inspired by soundstorm's hierarchical menu system.
|
||||
|
||||
from pathlib import Path
|
||||
from src.tts_engine import TtsEngine
|
||||
from src.screen_reader_engine import ScreenReaderEngine
|
||||
|
||||
|
||||
class OptionsMenu:
|
||||
@@ -32,6 +33,40 @@ class OptionsMenu:
|
||||
self.ttsReloadCallback = ttsReloadCallback
|
||||
self.currentSelection = 0
|
||||
self.inMenu = False
|
||||
self.screenReaderName = None
|
||||
self._refresh_screen_reader_target()
|
||||
|
||||
def _refresh_screen_reader_target(self):
|
||||
"""Detect active supported screen reader for optional engine entry."""
|
||||
self.screenReaderName = None
|
||||
try:
|
||||
detectionEngine = ScreenReaderEngine(quiet=True)
|
||||
if detectionEngine.is_available():
|
||||
activeName = detectionEngine.get_active_reader_name()
|
||||
if activeName and activeName != "Unavailable":
|
||||
self.screenReaderName = activeName
|
||||
else:
|
||||
self.screenReaderName = "Screen Reader"
|
||||
detectionEngine.close()
|
||||
except Exception:
|
||||
self.screenReaderName = None
|
||||
|
||||
def _get_engine_labels(self):
|
||||
"""Return user-facing labels for available engine values."""
|
||||
engineLabels = {
|
||||
'piper': 'Piper-TTS',
|
||||
'speechd': 'Speech-Dispatcher'
|
||||
}
|
||||
if self.screenReaderName:
|
||||
engineLabels['screenreader'] = self.screenReaderName
|
||||
return engineLabels
|
||||
|
||||
def _get_engine_cycle_order(self):
|
||||
"""Return engine cycle order, skipping screen-reader mode when unavailable."""
|
||||
engineOrder = ['piper', 'speechd']
|
||||
if self.screenReaderName:
|
||||
engineOrder.append('screenreader')
|
||||
return engineOrder
|
||||
|
||||
def show_main_menu(self):
|
||||
"""
|
||||
@@ -41,11 +76,7 @@ class OptionsMenu:
|
||||
Menu items as list of dicts
|
||||
"""
|
||||
readerEngine = self.config.get_reader_engine()
|
||||
engineLabels = {
|
||||
'piper': 'Piper-TTS',
|
||||
'speechd': 'Speech-Dispatcher',
|
||||
'screenreader': 'Screen Reader'
|
||||
}
|
||||
engineLabels = self._get_engine_labels()
|
||||
readerEngineText = engineLabels.get(readerEngine, 'Piper-TTS')
|
||||
|
||||
menuItems = [
|
||||
@@ -147,13 +178,10 @@ class OptionsMenu:
|
||||
|
||||
def _toggle_reader_engine(self):
|
||||
"""Cycle reader engine: piper-tts, speech-dispatcher, screen reader."""
|
||||
self._refresh_screen_reader_target()
|
||||
currentEngine = self.config.get_reader_engine()
|
||||
engineOrder = ['piper', 'speechd', 'screenreader']
|
||||
engineLabels = {
|
||||
'piper': 'Piper-TTS',
|
||||
'speechd': 'Speech-Dispatcher',
|
||||
'screenreader': 'Screen Reader'
|
||||
}
|
||||
engineOrder = self._get_engine_cycle_order()
|
||||
engineLabels = self._get_engine_labels()
|
||||
|
||||
if currentEngine not in engineOrder:
|
||||
currentEngine = 'piper'
|
||||
@@ -203,7 +231,8 @@ class OptionsMenu:
|
||||
if readerEngine == 'speechd':
|
||||
return self._select_speechd_voice()
|
||||
|
||||
self.speechEngine.speak("Voice selection is managed by your active screen reader.")
|
||||
readerName = self.screenReaderName if self.screenReaderName else "your active screen reader"
|
||||
self.speechEngine.speak(f"Voice selection is managed by {readerName}.")
|
||||
return True
|
||||
|
||||
def _select_piper_voice(self):
|
||||
@@ -481,6 +510,7 @@ class OptionsMenu:
|
||||
|
||||
def enter_menu(self):
|
||||
"""Enter the options menu"""
|
||||
self._refresh_screen_reader_target()
|
||||
self.inMenu = True
|
||||
self.currentSelection = 0
|
||||
self.inVoiceMenu = False
|
||||
|
||||
@@ -167,11 +167,12 @@ class ScreenReaderRemoteController:
|
||||
class ScreenReaderEngine:
|
||||
"""Book reading engine that speaks via active screen reader D-Bus APIs."""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, quiet=False):
|
||||
self.speechLock = threading.Lock()
|
||||
self.isAvailable = False
|
||||
self.activeController = None
|
||||
self.availableControllers = []
|
||||
self.quiet = quiet
|
||||
|
||||
self.isReading = False
|
||||
self.isPausedReading = False
|
||||
@@ -185,7 +186,8 @@ class ScreenReaderEngine:
|
||||
def _initialize_controllers(self):
|
||||
"""Discover available screen reader remote controllers."""
|
||||
if not HAS_DASBUS:
|
||||
print("Warning: python-dasbus not installed. Screen reader engine unavailable.")
|
||||
if not self.quiet:
|
||||
print("Warning: python-dasbus not installed. Screen reader engine unavailable.")
|
||||
return
|
||||
|
||||
controllerCandidates = [
|
||||
@@ -207,10 +209,11 @@ class ScreenReaderEngine:
|
||||
self.activeController = self._select_active_controller()
|
||||
self.isAvailable = self.activeController is not None
|
||||
|
||||
if self.activeController:
|
||||
print(f"Screen reader engine connected to {self.activeController.displayName}.")
|
||||
else:
|
||||
print("Warning: No supported screen reader D-Bus service detected (Orca/Cthulhu).")
|
||||
if not self.quiet:
|
||||
if self.activeController:
|
||||
print(f"Screen reader engine connected to {self.activeController.displayName}.")
|
||||
else:
|
||||
print("Warning: No supported screen reader D-Bus service detected (Orca/Cthulhu).")
|
||||
|
||||
def _is_process_running(self, processName):
|
||||
"""Return True when the process name is running."""
|
||||
|
||||
Reference in New Issue
Block a user