Speech settings added to cthulhu+arrow keys.
This commit is contained in:
@@ -450,6 +450,21 @@ INCREASE_SPEECH_VOLUME = _("Increase the speech volume")
|
|||||||
# speech synthesis engine will generate speech.
|
# speech synthesis engine will generate speech.
|
||||||
DECREASE_SPEECH_VOLUME = _("Decrease the speech volume")
|
DECREASE_SPEECH_VOLUME = _("Decrease the speech volume")
|
||||||
|
|
||||||
|
# Translators: This string describes the command to select the previous speech setting.
|
||||||
|
SPEECH_SETTING_PREVIOUS = _("Select the previous speech setting")
|
||||||
|
|
||||||
|
# Translators: This string describes the command to select the next speech setting.
|
||||||
|
SPEECH_SETTING_NEXT = _("Select the next speech setting")
|
||||||
|
|
||||||
|
# Translators: This string describes the command to decrease the current speech setting.
|
||||||
|
SPEECH_SETTING_DECREASE = _("Decrease the current speech setting")
|
||||||
|
|
||||||
|
# Translators: This string describes the command to increase the current speech setting.
|
||||||
|
SPEECH_SETTING_INCREASE = _("Increase the current speech setting")
|
||||||
|
|
||||||
|
# Translators: This string describes the command to save speech settings.
|
||||||
|
SPEECH_SETTINGS_SAVE = _("Save speech settings")
|
||||||
|
|
||||||
# Translators: Cthulhu allows the user to turn speech synthesis on or off.
|
# Translators: Cthulhu allows the user to turn speech synthesis on or off.
|
||||||
# We call it 'silencing'.
|
# We call it 'silencing'.
|
||||||
TOGGLE_SPEECH = _("Toggle the silencing of speech")
|
TOGGLE_SPEECH = _("Toggle the silencing of speech")
|
||||||
|
|||||||
@@ -2275,6 +2275,33 @@ SPEECH_LOUDER = _("louder.")
|
|||||||
# Translators: This string announces speech volume change.
|
# Translators: This string announces speech volume change.
|
||||||
SPEECH_SOFTER = _("softer.")
|
SPEECH_SOFTER = _("softer.")
|
||||||
|
|
||||||
|
# Translators: This string announces the current speech rate value.
|
||||||
|
SPEECH_RATE_VALUE = _("Rate %d")
|
||||||
|
|
||||||
|
# Translators: This string announces the current speech pitch value.
|
||||||
|
SPEECH_PITCH_VALUE = _("Pitch %s")
|
||||||
|
|
||||||
|
# Translators: This string announces the current speech volume value.
|
||||||
|
SPEECH_VOLUME_VALUE = _("Volume %s")
|
||||||
|
|
||||||
|
# Translators: This string announces the current speech-dispatcher module.
|
||||||
|
SPEECH_MODULE_VALUE = _("Speech-dispatcher module %s")
|
||||||
|
|
||||||
|
# Translators: This string announces the current speech-dispatcher voice.
|
||||||
|
SPEECH_VOICE_VALUE = _("Speech-dispatcher voice %s")
|
||||||
|
|
||||||
|
# Translators: This string is presented when speech-dispatcher modules are unavailable.
|
||||||
|
SPEECH_MODULES_UNAVAILABLE = _("No speech-dispatcher modules available")
|
||||||
|
|
||||||
|
# Translators: This string is presented when speech-dispatcher voices are unavailable.
|
||||||
|
SPEECH_VOICES_UNAVAILABLE = _("No speech-dispatcher voices available")
|
||||||
|
|
||||||
|
# Translators: This string confirms speech settings have been saved.
|
||||||
|
SPEECH_SETTINGS_SAVED = _("Speech settings saved")
|
||||||
|
|
||||||
|
# Translators: This string is presented when speech settings cannot be saved.
|
||||||
|
SPEECH_SETTINGS_SAVE_FAILED = _("Speech settings could not be saved")
|
||||||
|
|
||||||
# Translators: Cthulhu's verbosity levels control how much (or how little)
|
# Translators: Cthulhu's verbosity levels control how much (or how little)
|
||||||
# Cthulhu will speak when presenting objects as the user navigates within
|
# Cthulhu will speak when presenting objects as the user navigates within
|
||||||
# applications and reads content. The two levels are "brief" and "verbose".
|
# applications and reads content. The two levels are "brief" and "verbose".
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ from . import input_event
|
|||||||
from . import keybindings
|
from . import keybindings
|
||||||
from . import messages
|
from . import messages
|
||||||
from . import cthulhu_state
|
from . import cthulhu_state
|
||||||
|
from . import script_manager
|
||||||
|
from . import speechserver
|
||||||
from . import settings
|
from . import settings
|
||||||
from . import settings_manager
|
from . import settings_manager
|
||||||
from . import speech
|
from . import speech
|
||||||
@@ -49,6 +51,17 @@ class SpeechAndVerbosityManager:
|
|||||||
"""Configures speech and verbosity settings."""
|
"""Configures speech and verbosity settings."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self._speech_settings_order = [
|
||||||
|
"rate",
|
||||||
|
"pitch",
|
||||||
|
"volume",
|
||||||
|
"module",
|
||||||
|
"voice",
|
||||||
|
]
|
||||||
|
self._current_speech_setting_index = 0
|
||||||
|
self._rate_step = 1
|
||||||
|
self._pitch_step = 0.1
|
||||||
|
self._volume_step = 0.1
|
||||||
self._handlers = self._setup_handlers()
|
self._handlers = self._setup_handlers()
|
||||||
self._bindings = self._setup_bindings()
|
self._bindings = self._setup_bindings()
|
||||||
|
|
||||||
@@ -149,6 +162,31 @@ class SpeechAndVerbosityManager:
|
|||||||
self.increase_volume,
|
self.increase_volume,
|
||||||
cmdnames.INCREASE_SPEECH_VOLUME)
|
cmdnames.INCREASE_SPEECH_VOLUME)
|
||||||
|
|
||||||
|
handlers["selectPreviousSpeechSettingHandler"] = \
|
||||||
|
input_event.InputEventHandler(
|
||||||
|
self.select_previous_speech_setting,
|
||||||
|
cmdnames.SPEECH_SETTING_PREVIOUS)
|
||||||
|
|
||||||
|
handlers["selectNextSpeechSettingHandler"] = \
|
||||||
|
input_event.InputEventHandler(
|
||||||
|
self.select_next_speech_setting,
|
||||||
|
cmdnames.SPEECH_SETTING_NEXT)
|
||||||
|
|
||||||
|
handlers["decreaseCurrentSpeechSettingHandler"] = \
|
||||||
|
input_event.InputEventHandler(
|
||||||
|
self.decrease_current_speech_setting,
|
||||||
|
cmdnames.SPEECH_SETTING_DECREASE)
|
||||||
|
|
||||||
|
handlers["increaseCurrentSpeechSettingHandler"] = \
|
||||||
|
input_event.InputEventHandler(
|
||||||
|
self.increase_current_speech_setting,
|
||||||
|
cmdnames.SPEECH_SETTING_INCREASE)
|
||||||
|
|
||||||
|
handlers["saveSpeechSettingsHandler"] = \
|
||||||
|
input_event.InputEventHandler(
|
||||||
|
self.save_speech_settings,
|
||||||
|
cmdnames.SPEECH_SETTINGS_SAVE)
|
||||||
|
|
||||||
return handlers
|
return handlers
|
||||||
|
|
||||||
def _setup_bindings(self):
|
def _setup_bindings(self):
|
||||||
@@ -233,6 +271,41 @@ class SpeechAndVerbosityManager:
|
|||||||
keybindings.NO_MODIFIER_MASK,
|
keybindings.NO_MODIFIER_MASK,
|
||||||
self._handlers.get("increaseSpeechVolumeHandler")))
|
self._handlers.get("increaseSpeechVolumeHandler")))
|
||||||
|
|
||||||
|
bindings.add(
|
||||||
|
keybindings.KeyBinding(
|
||||||
|
"Left",
|
||||||
|
keybindings.defaultModifierMask,
|
||||||
|
keybindings.CTHULHU_MODIFIER_MASK,
|
||||||
|
self._handlers.get("selectPreviousSpeechSettingHandler")))
|
||||||
|
|
||||||
|
bindings.add(
|
||||||
|
keybindings.KeyBinding(
|
||||||
|
"Right",
|
||||||
|
keybindings.defaultModifierMask,
|
||||||
|
keybindings.CTHULHU_MODIFIER_MASK,
|
||||||
|
self._handlers.get("selectNextSpeechSettingHandler")))
|
||||||
|
|
||||||
|
bindings.add(
|
||||||
|
keybindings.KeyBinding(
|
||||||
|
"Down",
|
||||||
|
keybindings.defaultModifierMask,
|
||||||
|
keybindings.CTHULHU_MODIFIER_MASK,
|
||||||
|
self._handlers.get("decreaseCurrentSpeechSettingHandler")))
|
||||||
|
|
||||||
|
bindings.add(
|
||||||
|
keybindings.KeyBinding(
|
||||||
|
"Up",
|
||||||
|
keybindings.defaultModifierMask,
|
||||||
|
keybindings.CTHULHU_MODIFIER_MASK,
|
||||||
|
self._handlers.get("increaseCurrentSpeechSettingHandler")))
|
||||||
|
|
||||||
|
bindings.add(
|
||||||
|
keybindings.KeyBinding(
|
||||||
|
"s",
|
||||||
|
keybindings.defaultModifierMask,
|
||||||
|
keybindings.CTHULHU_CTRL_MODIFIER_MASK | keybindings.SHIFT_MODIFIER_MASK,
|
||||||
|
self._handlers.get("saveSpeechSettingsHandler")))
|
||||||
|
|
||||||
bindings.add(
|
bindings.add(
|
||||||
keybindings.KeyBinding(
|
keybindings.KeyBinding(
|
||||||
"",
|
"",
|
||||||
@@ -266,6 +339,380 @@ class SpeechAndVerbosityManager:
|
|||||||
def _get_server(self):
|
def _get_server(self):
|
||||||
return speech.getSpeechServer()
|
return speech.getSpeechServer()
|
||||||
|
|
||||||
|
def _format_number(self, value):
|
||||||
|
if isinstance(value, float):
|
||||||
|
if value.is_integer():
|
||||||
|
return str(int(value))
|
||||||
|
return f"{value:.1f}".rstrip("0").rstrip(".")
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
def _present_message(self, script, message):
|
||||||
|
if script:
|
||||||
|
script.presentMessage(message)
|
||||||
|
else:
|
||||||
|
speech.speak(message)
|
||||||
|
|
||||||
|
def _get_default_voice(self):
|
||||||
|
from . import acss
|
||||||
|
default_voice = settings.voices.get(settings.DEFAULT_VOICE)
|
||||||
|
if default_voice is None:
|
||||||
|
default_voice = acss.ACSS({})
|
||||||
|
settings.voices[settings.DEFAULT_VOICE] = default_voice
|
||||||
|
return default_voice
|
||||||
|
|
||||||
|
def _set_default_voice_family(self, family):
|
||||||
|
from . import acss
|
||||||
|
default_voice = self._get_default_voice()
|
||||||
|
if family is None:
|
||||||
|
default_voice.pop(acss.ACSS.FAMILY, None)
|
||||||
|
else:
|
||||||
|
default_voice[acss.ACSS.FAMILY] = dict(family)
|
||||||
|
default_voice['established'] = True
|
||||||
|
|
||||||
|
def _get_current_speech_setting(self):
|
||||||
|
return self._speech_settings_order[self._current_speech_setting_index]
|
||||||
|
|
||||||
|
def _get_rate_value(self):
|
||||||
|
from . import acss
|
||||||
|
default_voice = self._get_default_voice()
|
||||||
|
return int(default_voice.get(acss.ACSS.RATE, 50))
|
||||||
|
|
||||||
|
def _set_rate_value(self, value):
|
||||||
|
from . import acss
|
||||||
|
default_voice = self._get_default_voice()
|
||||||
|
default_voice[acss.ACSS.RATE] = int(value)
|
||||||
|
default_voice['established'] = True
|
||||||
|
|
||||||
|
def _get_pitch_value(self):
|
||||||
|
from . import acss
|
||||||
|
default_voice = self._get_default_voice()
|
||||||
|
return float(default_voice.get(acss.ACSS.AVERAGE_PITCH, 5.0))
|
||||||
|
|
||||||
|
def _set_pitch_value(self, value):
|
||||||
|
from . import acss
|
||||||
|
default_voice = self._get_default_voice()
|
||||||
|
default_voice[acss.ACSS.AVERAGE_PITCH] = float(value)
|
||||||
|
default_voice['established'] = True
|
||||||
|
|
||||||
|
def _get_volume_value(self):
|
||||||
|
from . import acss
|
||||||
|
default_voice = self._get_default_voice()
|
||||||
|
return float(default_voice.get(acss.ACSS.GAIN, 10.0))
|
||||||
|
|
||||||
|
def _set_volume_value(self, value):
|
||||||
|
from . import acss
|
||||||
|
default_voice = self._get_default_voice()
|
||||||
|
default_voice[acss.ACSS.GAIN] = float(value)
|
||||||
|
default_voice['established'] = True
|
||||||
|
|
||||||
|
def _get_current_voice_name(self, server=None):
|
||||||
|
from . import acss
|
||||||
|
default_voice = self._get_default_voice()
|
||||||
|
family = default_voice.get(acss.ACSS.FAMILY, {}) or {}
|
||||||
|
name = family.get(speechserver.VoiceFamily.NAME)
|
||||||
|
if name:
|
||||||
|
return name
|
||||||
|
if server:
|
||||||
|
voices = self._get_available_voices(server)
|
||||||
|
if voices:
|
||||||
|
return voices[0].get(speechserver.VoiceFamily.NAME)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def _get_available_modules(self, server):
|
||||||
|
if server is None or not hasattr(server, 'list_output_modules'):
|
||||||
|
return []
|
||||||
|
try:
|
||||||
|
modules = list(server.list_output_modules() or [])
|
||||||
|
except Exception as e:
|
||||||
|
debug.printMessage(debug.LEVEL_WARNING, f"Error getting output modules: {e}", True)
|
||||||
|
return []
|
||||||
|
return modules
|
||||||
|
|
||||||
|
def _get_available_voices(self, server):
|
||||||
|
if server is None or not hasattr(server, 'getVoiceFamilies'):
|
||||||
|
return []
|
||||||
|
try:
|
||||||
|
voices = server.getVoiceFamilies() or []
|
||||||
|
except Exception as e:
|
||||||
|
debug.printMessage(debug.LEVEL_WARNING, f"Error getting voices: {e}", True)
|
||||||
|
return []
|
||||||
|
filtered = []
|
||||||
|
for voice in voices:
|
||||||
|
if voice.get(speechserver.VoiceFamily.NAME):
|
||||||
|
filtered.append(voice)
|
||||||
|
if not filtered:
|
||||||
|
return []
|
||||||
|
|
||||||
|
if not self._should_filter_voices_by_locale(server):
|
||||||
|
return filtered
|
||||||
|
|
||||||
|
language, dialect = self._get_system_language_and_dialect()
|
||||||
|
if not language:
|
||||||
|
return filtered
|
||||||
|
|
||||||
|
language_filtered = []
|
||||||
|
for voice in filtered:
|
||||||
|
voice_lang = (voice.get(speechserver.VoiceFamily.LANG) or "").lower()
|
||||||
|
voice_dialect = (voice.get(speechserver.VoiceFamily.DIALECT) or "").lower()
|
||||||
|
if voice_lang != language:
|
||||||
|
continue
|
||||||
|
if dialect and voice_dialect and voice_dialect != dialect:
|
||||||
|
continue
|
||||||
|
language_filtered.append(voice)
|
||||||
|
|
||||||
|
if language_filtered:
|
||||||
|
msg = (
|
||||||
|
"SPEECH AND VERBOSITY MANAGER: "
|
||||||
|
f"Filtered voices to locale {language}"
|
||||||
|
f"{('-' + dialect) if dialect else ''}: "
|
||||||
|
f"{len(language_filtered)} of {len(filtered)}"
|
||||||
|
)
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
return language_filtered
|
||||||
|
|
||||||
|
msg = (
|
||||||
|
"SPEECH AND VERBOSITY MANAGER: "
|
||||||
|
f"No voices for locale {language}"
|
||||||
|
f"{('-' + dialect) if dialect else ''}; using all voices."
|
||||||
|
)
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
return filtered
|
||||||
|
|
||||||
|
def _should_filter_voices_by_locale(self, server):
|
||||||
|
if server is None or not hasattr(server, "getOutputModule"):
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
module = (server.getOutputModule() or "").lower()
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
return "espeak-ng" in module
|
||||||
|
|
||||||
|
def _get_system_language_and_dialect(self):
|
||||||
|
import locale
|
||||||
|
locale_value = None
|
||||||
|
try:
|
||||||
|
locale_value = locale.getlocale(locale.LC_MESSAGES)[0]
|
||||||
|
except Exception:
|
||||||
|
locale_value = None
|
||||||
|
if not locale_value:
|
||||||
|
try:
|
||||||
|
locale_value = locale.getdefaultlocale()[0]
|
||||||
|
except Exception:
|
||||||
|
locale_value = None
|
||||||
|
|
||||||
|
if not locale_value:
|
||||||
|
return "", ""
|
||||||
|
|
||||||
|
if "_" in locale_value:
|
||||||
|
language, dialect = locale_value.split("_", 1)
|
||||||
|
elif "-" in locale_value:
|
||||||
|
language, dialect = locale_value.split("-", 1)
|
||||||
|
else:
|
||||||
|
language, dialect = locale_value, ""
|
||||||
|
|
||||||
|
return language.lower(), dialect.lower()
|
||||||
|
|
||||||
|
def _announce_current_speech_setting(self, script=None):
|
||||||
|
setting = self._get_current_speech_setting()
|
||||||
|
debug.printMessage(debug.LEVEL_INFO,
|
||||||
|
f"SPEECH AND VERBOSITY MANAGER: Current setting {setting}",
|
||||||
|
True)
|
||||||
|
if setting == "rate":
|
||||||
|
value = self._get_rate_value()
|
||||||
|
message = messages.SPEECH_RATE_VALUE % value
|
||||||
|
elif setting == "pitch":
|
||||||
|
value = self._format_number(self._get_pitch_value())
|
||||||
|
message = messages.SPEECH_PITCH_VALUE % value
|
||||||
|
elif setting == "volume":
|
||||||
|
value = self._format_number(self._get_volume_value())
|
||||||
|
message = messages.SPEECH_VOLUME_VALUE % value
|
||||||
|
elif setting == "module":
|
||||||
|
server = self._get_server()
|
||||||
|
if server is None or not hasattr(server, 'getOutputModule'):
|
||||||
|
message = messages.SPEECH_MODULES_UNAVAILABLE
|
||||||
|
else:
|
||||||
|
module = server.getOutputModule() or ""
|
||||||
|
if module:
|
||||||
|
message = messages.SPEECH_MODULE_VALUE % module
|
||||||
|
else:
|
||||||
|
message = messages.SPEECH_MODULES_UNAVAILABLE
|
||||||
|
elif setting == "voice":
|
||||||
|
server = self._get_server()
|
||||||
|
voices = self._get_available_voices(server)
|
||||||
|
if not voices:
|
||||||
|
message = messages.SPEECH_VOICES_UNAVAILABLE
|
||||||
|
else:
|
||||||
|
name = self._get_current_voice_name(server)
|
||||||
|
message = messages.SPEECH_VOICE_VALUE % name
|
||||||
|
else:
|
||||||
|
message = ""
|
||||||
|
|
||||||
|
if message:
|
||||||
|
self._present_message(script, message)
|
||||||
|
|
||||||
|
@dbus_service.command
|
||||||
|
def select_previous_speech_setting(self, script=None, event=None):
|
||||||
|
if self._current_speech_setting_index > 0:
|
||||||
|
self._current_speech_setting_index -= 1
|
||||||
|
self._announce_current_speech_setting(script)
|
||||||
|
return True
|
||||||
|
|
||||||
|
@dbus_service.command
|
||||||
|
def select_next_speech_setting(self, script=None, event=None):
|
||||||
|
if self._current_speech_setting_index < len(self._speech_settings_order) - 1:
|
||||||
|
self._current_speech_setting_index += 1
|
||||||
|
self._announce_current_speech_setting(script)
|
||||||
|
return True
|
||||||
|
|
||||||
|
@dbus_service.command
|
||||||
|
def decrease_current_speech_setting(self, script=None, event=None):
|
||||||
|
return self._adjust_current_speech_setting(script, decrease=True)
|
||||||
|
|
||||||
|
@dbus_service.command
|
||||||
|
def increase_current_speech_setting(self, script=None, event=None):
|
||||||
|
return self._adjust_current_speech_setting(script, decrease=False)
|
||||||
|
|
||||||
|
def _adjust_current_speech_setting(self, script, decrease=False):
|
||||||
|
setting = self._get_current_speech_setting()
|
||||||
|
if setting == "rate":
|
||||||
|
return self._adjust_rate(script, decrease)
|
||||||
|
if setting == "pitch":
|
||||||
|
return self._adjust_pitch(script, decrease)
|
||||||
|
if setting == "volume":
|
||||||
|
return self._adjust_volume(script, decrease)
|
||||||
|
if setting == "module":
|
||||||
|
return self._adjust_module(script, decrease)
|
||||||
|
if setting == "voice":
|
||||||
|
return self._adjust_voice(script, decrease)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _adjust_rate(self, script, decrease):
|
||||||
|
delta = -self._rate_step if decrease else self._rate_step
|
||||||
|
value = self._get_rate_value() + delta
|
||||||
|
value = max(0, min(100, value))
|
||||||
|
self._set_rate_value(value)
|
||||||
|
msg = f"SPEECH AND VERBOSITY MANAGER: Rate set to {value}"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
self._announce_current_speech_setting(script)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _adjust_pitch(self, script, decrease):
|
||||||
|
delta = -self._pitch_step if decrease else self._pitch_step
|
||||||
|
value = round(self._get_pitch_value() + delta, 1)
|
||||||
|
value = max(0.0, min(10.0, value))
|
||||||
|
self._set_pitch_value(value)
|
||||||
|
msg = f"SPEECH AND VERBOSITY MANAGER: Pitch set to {value}"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
self._announce_current_speech_setting(script)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _adjust_volume(self, script, decrease):
|
||||||
|
delta = -self._volume_step if decrease else self._volume_step
|
||||||
|
value = round(self._get_volume_value() + delta, 1)
|
||||||
|
value = max(0.0, min(10.0, value))
|
||||||
|
self._set_volume_value(value)
|
||||||
|
msg = f"SPEECH AND VERBOSITY MANAGER: Volume set to {value}"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
self._announce_current_speech_setting(script)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _adjust_module(self, script, decrease):
|
||||||
|
server = self._get_server()
|
||||||
|
if server is None:
|
||||||
|
msg = "SPEECH AND VERBOSITY MANAGER: Cannot get speech server."
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
return True
|
||||||
|
|
||||||
|
modules = self._get_available_modules(server)
|
||||||
|
if not modules:
|
||||||
|
self._present_message(script, messages.SPEECH_MODULES_UNAVAILABLE)
|
||||||
|
return True
|
||||||
|
|
||||||
|
current = server.getOutputModule() if hasattr(server, 'getOutputModule') else ""
|
||||||
|
try:
|
||||||
|
index = modules.index(current)
|
||||||
|
except ValueError:
|
||||||
|
index = 0
|
||||||
|
|
||||||
|
delta = -1 if decrease else 1
|
||||||
|
new_index = max(0, min(len(modules) - 1, index + delta))
|
||||||
|
new_module = modules[new_index]
|
||||||
|
|
||||||
|
if new_module != current:
|
||||||
|
try:
|
||||||
|
server.setOutputModule(new_module)
|
||||||
|
msg = f"SPEECH AND VERBOSITY MANAGER: Output module set to {new_module}"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
except Exception as e:
|
||||||
|
debug.printMessage(debug.LEVEL_WARNING, f"Error setting output module: {e}", True)
|
||||||
|
return True
|
||||||
|
settings.speechServerInfo = [new_module, new_module]
|
||||||
|
msg = f"SPEECH AND VERBOSITY MANAGER: speechServerInfo set to {settings.speechServerInfo}"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
|
voices = self._get_available_voices(server)
|
||||||
|
if voices:
|
||||||
|
self._set_default_voice_family(voices[0])
|
||||||
|
else:
|
||||||
|
self._set_default_voice_family({})
|
||||||
|
|
||||||
|
self._present_message(script, messages.SPEECH_MODULE_VALUE % new_module)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _adjust_voice(self, script, decrease):
|
||||||
|
server = self._get_server()
|
||||||
|
voices = self._get_available_voices(server)
|
||||||
|
if not voices:
|
||||||
|
self._present_message(script, messages.SPEECH_VOICES_UNAVAILABLE)
|
||||||
|
return True
|
||||||
|
|
||||||
|
current_name = self._get_current_voice_name(server)
|
||||||
|
index = 0
|
||||||
|
for idx, voice in enumerate(voices):
|
||||||
|
if voice.get(speechserver.VoiceFamily.NAME) == current_name:
|
||||||
|
index = idx
|
||||||
|
break
|
||||||
|
|
||||||
|
delta = -1 if decrease else 1
|
||||||
|
new_index = max(0, min(len(voices) - 1, index + delta))
|
||||||
|
new_voice = voices[new_index]
|
||||||
|
self._set_default_voice_family(new_voice)
|
||||||
|
name = new_voice.get(speechserver.VoiceFamily.NAME, "")
|
||||||
|
msg = f"SPEECH AND VERBOSITY MANAGER: Voice set to {name}"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
self._present_message(script, messages.SPEECH_VOICE_VALUE % name)
|
||||||
|
return True
|
||||||
|
|
||||||
|
@dbus_service.command
|
||||||
|
def save_speech_settings(self, script=None, event=None):
|
||||||
|
try:
|
||||||
|
server = self._get_server()
|
||||||
|
if server and hasattr(server, "getOutputModule"):
|
||||||
|
module = server.getOutputModule() or ""
|
||||||
|
if module:
|
||||||
|
settings.speechServerInfo = [module, module]
|
||||||
|
msg = f"SPEECH AND VERBOSITY MANAGER: Saving speechServerInfo {settings.speechServerInfo}"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
|
general = {}
|
||||||
|
for key in settings.userCustomizableSettings:
|
||||||
|
general[key] = getattr(settings, key)
|
||||||
|
|
||||||
|
current_profile = _settings_manager.profile
|
||||||
|
pronunciations = _settings_manager.getPronunciations(current_profile)
|
||||||
|
keybindings = _settings_manager.getKeybindings(current_profile)
|
||||||
|
|
||||||
|
default_script = script_manager.get_manager().get_default_script()
|
||||||
|
_settings_manager.saveSettings(default_script,
|
||||||
|
general,
|
||||||
|
pronunciations,
|
||||||
|
keybindings)
|
||||||
|
self._present_message(script, messages.SPEECH_SETTINGS_SAVED)
|
||||||
|
except Exception as e:
|
||||||
|
debug.printMessage(debug.LEVEL_WARNING, f"Error saving speech settings: {e}", True)
|
||||||
|
self._present_message(script, messages.SPEECH_SETTINGS_SAVE_FAILED)
|
||||||
|
return True
|
||||||
|
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
# D-Bus Speech Server Controls
|
# D-Bus Speech Server Controls
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
|
|||||||
@@ -589,7 +589,13 @@ class SpeechServer(speechserver.SpeechServer):
|
|||||||
if not default_lang:
|
if not default_lang:
|
||||||
default_lang = locale_language
|
default_lang = locale_language
|
||||||
|
|
||||||
voices = ((self._default_voice_name, default_lang, None),) + voices
|
current_module = ""
|
||||||
|
try:
|
||||||
|
current_module = self.getOutputModule() or ""
|
||||||
|
except Exception:
|
||||||
|
current_module = ""
|
||||||
|
default_name = guilabels.SPEECH_DEFAULT_VOICE % (current_module or self._id)
|
||||||
|
voices = ((default_name, default_lang, None),) + voices
|
||||||
|
|
||||||
families = []
|
families = []
|
||||||
for name, lang, variant in voices:
|
for name, lang, variant in voices:
|
||||||
@@ -798,4 +804,3 @@ class SpeechServer(speechserver.SpeechServer):
|
|||||||
return ()
|
return ()
|
||||||
except speechd.SSIPCommandError:
|
except speechd.SSIPCommandError:
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user