Make synth fallback check all other synths, not just later ones#19603
Merged
Conversation
added 8 commits
February 12, 2026 13:35
…ubic in most cases!)
seanbudd
approved these changes
Feb 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Link to issue number:
None
Summary of the issue:
If the default speech synthesizer is set to a synth that can't be loaded for some reason, and the only working synth(s) are before that synth in
synthDriverHandler.defaultSynthPriorityList, NVDA will fall back tosilence.That is, as reported in #19582, if the default synth is eSpeak and it can't be loaded, NVDA doesn't produce speech at all.
Description of user facing changes:
If eSpeak is set as the default synth and it can't be loaded, NVDA will first try to use OneCore before falling back to no speech.
Description of developer facing changes:
synthDriverHandler.setSynthandfindAndSetNextSynthnow optionally take an internal-only keyword-only_leftToTrylist of synth names (in reverse order of priority). The behaviour offindAndSetNextSynthhas changed to find the first working synth indefaultSynthPriorityList, rather than only considering synths aftercurrentSynthName. As a result,setSynthmay fall back to a synth anywhere indefaultSynthPriorityList, and will preference synths earlier therein.Description of development approach:
Update
synthDriverHandler.setSynthandfindNextSynthto take an optional list of synth names. IfNone, it is calculated infindAndSetNextSynthfromcurrentSynthNameanddefaultSynthPriorityList.In
findAndSetNextSynth, rather than finding the index ofcurrentSynthNameindefaultSynthPriorityListand attempting to use the next synth, pop a synth name fromleftToTryand attempt to use that synth. asfindAndSetNextSynthcallssetSynthwith the popped name and the remainder ofleftToTry, andsetSynthcallsfindAndSetNextSynthwith what it received asleftToTry, this will consumeleftToTrytail-first until either a working synth is found orleftToTryis exhausted.If
findAndSetNextSynthreceivesNoneas the value ofleftToTry, it usesdefaultSynthPriorityListin reverse order, excludingcurrentSynthName. Otherwise,currentSynthNameis ignored.Since, if unspecified,
leftToTrydefaults todefaultSynthPriorityList, andfindAndSetNextSynthconsumesleftToTryin reverse, we try synths fromdefaultSynthPriorityListin order (axiomatically,reverss(reverse(sequence)) = sequence).Testing strategy:
Raised
RuntimeErrorfromsynthDrivers.espeak.SynthDriver.__init__and/orsynthDriverHandler.OneCore.OneCoreSynthDriver.__init__. Observed the following behaviour:Known issues with pull request:
None known
Code Review Checklist: