Fixed a bug that could leave you without speech if changing the active window.
This commit is contained in:
@@ -112,6 +112,7 @@ class SettingsManager(object):
|
||||
self._appPronunciations: Dict[str, Any] = {}
|
||||
self._appKeybindings: Dict[str, Any] = {}
|
||||
self._lastRoleSoundPresentation: Optional[Any] = None
|
||||
self._session_settings: Dict[str, Any] = {}
|
||||
|
||||
if not self._loadBackend():
|
||||
raise Exception('SettingsManager._loadBackend failed.')
|
||||
@@ -383,6 +384,12 @@ class SettingsManager(object):
|
||||
def setSetting(self, settingName: str, settingValue: Any) -> None:
|
||||
self._setSettingsRuntime({settingName:settingValue})
|
||||
|
||||
def set_session_setting(self, setting_name: str, setting_value: Any) -> None:
|
||||
"""Set a process-lifetime setting which survives application changes."""
|
||||
|
||||
self._session_settings[setting_name] = copy.deepcopy(setting_value)
|
||||
self._setSettingsRuntime({setting_name: setting_value})
|
||||
|
||||
def getSetting(self, settingName: str) -> Any:
|
||||
return getattr(settings, settingName, None)
|
||||
|
||||
@@ -582,6 +589,8 @@ class SettingsManager(object):
|
||||
self._getCustomizedSettings()
|
||||
for key, value in self.customizedSettings.items():
|
||||
setattr(settings, str(key), value)
|
||||
for key, value in self._session_settings.items():
|
||||
setattr(settings, str(key), copy.deepcopy(value))
|
||||
|
||||
msg = 'SETTINGS MANAGER: Runtime settings set.'
|
||||
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||
|
||||
@@ -375,6 +375,7 @@ class SpeechAndVerbosityManager:
|
||||
}
|
||||
default_voice[acss.ACSS.FAMILY] = family_dict
|
||||
default_voice['established'] = True
|
||||
self.app.getSettingsManager().set_session_setting("voices", settings.voices)
|
||||
|
||||
def _get_current_speech_setting(self):
|
||||
order = self._get_speech_settings_order()
|
||||
@@ -405,6 +406,7 @@ class SpeechAndVerbosityManager:
|
||||
default_voice = self._get_default_voice()
|
||||
default_voice[acss.ACSS.RATE] = int(value)
|
||||
default_voice['established'] = True
|
||||
self.app.getSettingsManager().set_session_setting("voices", settings.voices)
|
||||
|
||||
def _get_pitch_value(self):
|
||||
from . import acss
|
||||
@@ -416,6 +418,7 @@ class SpeechAndVerbosityManager:
|
||||
default_voice = self._get_default_voice()
|
||||
default_voice[acss.ACSS.AVERAGE_PITCH] = float(value)
|
||||
default_voice['established'] = True
|
||||
self.app.getSettingsManager().set_session_setting("voices", settings.voices)
|
||||
|
||||
def _get_volume_value(self):
|
||||
from . import acss
|
||||
@@ -427,6 +430,7 @@ class SpeechAndVerbosityManager:
|
||||
default_voice = self._get_default_voice()
|
||||
default_voice[acss.ACSS.GAIN] = float(value)
|
||||
default_voice['established'] = True
|
||||
self.app.getSettingsManager().set_session_setting("voices", settings.voices)
|
||||
|
||||
def _get_current_voice_name(self, server=None):
|
||||
from . import acss
|
||||
@@ -708,6 +712,10 @@ class SpeechAndVerbosityManager:
|
||||
debug.printMessage(debug.LEVEL_WARNING, f"Error setting output module: {e}", True)
|
||||
return True
|
||||
settings.speechServerInfo = [new_module, new_module]
|
||||
self.app.getSettingsManager().set_session_setting(
|
||||
"speechServerInfo",
|
||||
settings.speechServerInfo,
|
||||
)
|
||||
msg = f"SPEECH AND VERBOSITY MANAGER: speechServerInfo set to {settings.speechServerInfo}"
|
||||
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||
|
||||
|
||||
@@ -6,12 +6,121 @@ from unittest import mock
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from cthulhu import guilabels
|
||||
from cthulhu import settings
|
||||
from cthulhu import settings_manager
|
||||
from cthulhu import speech_and_verbosity_manager
|
||||
from cthulhu import speechdispatcherfactory
|
||||
from cthulhu import speechserver
|
||||
|
||||
|
||||
class SpeechDispatcherVoiceSelectionRegressionTests(unittest.TestCase):
|
||||
def test_session_speech_settings_override_profile_reload(self):
|
||||
manager = settings_manager.SettingsManager.__new__(
|
||||
settings_manager.SettingsManager
|
||||
)
|
||||
manager._session_settings = {
|
||||
"speechServerInfo": ["doubletalk", "doubletalk"],
|
||||
"voices": {
|
||||
settings.DEFAULT_VOICE: {
|
||||
"family": {
|
||||
speechserver.VoiceFamily.NAME: "Perfect Paul",
|
||||
speechserver.VoiceFamily.LANG: "en",
|
||||
speechserver.VoiceFamily.DIALECT: "US",
|
||||
speechserver.VoiceFamily.VARIANT: "none",
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
manager.customizedSettings = {}
|
||||
manager._getCustomizedSettings = mock.Mock(return_value={})
|
||||
manager._logRoleSoundPresentationChange = mock.Mock()
|
||||
saved_settings = {
|
||||
"speechServerInfo": ["rhvoice", "rhvoice"],
|
||||
"voices": {
|
||||
settings.DEFAULT_VOICE: {
|
||||
"family": {
|
||||
speechserver.VoiceFamily.NAME: "Previous Voice",
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
with mock.patch.object(
|
||||
settings,
|
||||
"speechServerInfo",
|
||||
saved_settings["speechServerInfo"],
|
||||
), mock.patch.object(settings, "voices", saved_settings["voices"]):
|
||||
manager._setSettingsRuntime(saved_settings)
|
||||
|
||||
self.assertEqual(
|
||||
["doubletalk", "doubletalk"],
|
||||
settings.speechServerInfo,
|
||||
)
|
||||
self.assertEqual(
|
||||
"Perfect Paul",
|
||||
settings.voices[settings.DEFAULT_VOICE]["family"][
|
||||
speechserver.VoiceFamily.NAME
|
||||
],
|
||||
)
|
||||
|
||||
def test_quick_module_switch_preserves_module_and_voice_for_session(self):
|
||||
current_module = {"name": "rhvoice"}
|
||||
perfect_paul = speechserver.VoiceFamily(
|
||||
{
|
||||
speechserver.VoiceFamily.NAME: "Perfect Paul",
|
||||
speechserver.VoiceFamily.LANG: "en",
|
||||
speechserver.VoiceFamily.DIALECT: "US",
|
||||
speechserver.VoiceFamily.VARIANT: "none",
|
||||
}
|
||||
)
|
||||
server = mock.Mock()
|
||||
server.list_output_modules.return_value = ["rhvoice", "doubletalk"]
|
||||
server.getOutputModule.side_effect = lambda: current_module["name"]
|
||||
server.setOutputModule.side_effect = (
|
||||
lambda module: current_module.update(name=module)
|
||||
)
|
||||
server.getVoiceFamilies.return_value = [perfect_paul]
|
||||
|
||||
session_settings = mock.Mock()
|
||||
app = mock.Mock()
|
||||
app.getSettingsManager.return_value = session_settings
|
||||
manager = speech_and_verbosity_manager.SpeechAndVerbosityManager.__new__(
|
||||
speech_and_verbosity_manager.SpeechAndVerbosityManager
|
||||
)
|
||||
manager.app = app
|
||||
manager._get_server = mock.Mock(return_value=server)
|
||||
manager._present_message = mock.Mock()
|
||||
|
||||
runtime_voices = {
|
||||
settings.DEFAULT_VOICE: {
|
||||
"family": {
|
||||
speechserver.VoiceFamily.NAME: "Previous Voice",
|
||||
}
|
||||
}
|
||||
}
|
||||
with mock.patch.object(settings, "voices", runtime_voices), \
|
||||
mock.patch.object(
|
||||
settings,
|
||||
"speechServerInfo",
|
||||
["rhvoice", "rhvoice"],
|
||||
):
|
||||
manager._adjust_module(script=None, decrease=False)
|
||||
|
||||
session_values = {
|
||||
call.args[0]: call.args[1]
|
||||
for call in session_settings.set_session_setting.call_args_list
|
||||
}
|
||||
self.assertEqual(
|
||||
["doubletalk", "doubletalk"],
|
||||
session_values["speechServerInfo"],
|
||||
)
|
||||
self.assertEqual(
|
||||
"Perfect Paul",
|
||||
session_values["voices"][settings.DEFAULT_VOICE]["family"][
|
||||
speechserver.VoiceFamily.NAME
|
||||
],
|
||||
)
|
||||
|
||||
def test_output_module_updates_the_synthetic_default_voice_name(self):
|
||||
server = speechdispatcherfactory.SpeechServer.__new__(
|
||||
speechdispatcherfactory.SpeechServer
|
||||
|
||||
Reference in New Issue
Block a user