Skip to content

Commit 8e0d3c7

Browse files
authored
Merge b35ebde into 564e401
2 parents 564e401 + b35ebde commit 8e0d3c7

8 files changed

Lines changed: 203 additions & 37 deletions

File tree

source/config/configSpec.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
symbolLevel = integer(default=100)
3737
trustVoiceLanguage = boolean(default=true)
3838
unicodeNormalization = featureFlag(optionsEnum="BoolFlag", behaviorOfDefault="disabled")
39+
reportNormalizedForCharacterNavigation = boolean(default=true)
3940
includeCLDR = boolean(default=True)
4041
beepSpeechModePitch = integer(default=10000,min=50,max=11025)
4142
outputDevice = string(default=default)

source/globalCommands.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3567,6 +3567,34 @@ def script_braille_cycleShowSelection(self, gesture: inputCore.InputGesture) ->
35673567
braille.handler.initialDisplay()
35683568
ui.message(msg)
35693569

3570+
@script(
3571+
# Translators: Input help mode message for Braille Unicode normalization command.
3572+
description=_("Cycle through the braille Unicode normalization states"),
3573+
category=SCRCAT_BRAILLE
3574+
)
3575+
def script_braille_cycleUnicodeNormalization(self, gesture: inputCore.InputGesture) -> None:
3576+
featureFlag: FeatureFlag = config.conf["braille"]["unicodeNormalization"]
3577+
boolFlag: BoolFlag = featureFlag.enumClassType
3578+
values = [x.value for x in boolFlag]
3579+
currentValue = featureFlag.value.value
3580+
nextValueIndex = (currentValue % len(values)) + 1
3581+
nextName: str = boolFlag(nextValueIndex).name
3582+
config.conf["braille"]["unicodeNormalization"] = nextName
3583+
featureFlag = config.conf["braille"]["unicodeNormalization"]
3584+
if featureFlag.isDefault():
3585+
# Translators: Used when reporting braille Unicode normalization state
3586+
# (default behavior).
3587+
msg = _("Braille Unicode normalization default ({default})").format(
3588+
default=featureFlag.behaviorOfDefault.displayString
3589+
)
3590+
else:
3591+
# Translators: Used when reporting braille Unicode normalization state
3592+
# (disabled or enabled).
3593+
msg = _("Braille Unicode normalization {state}").format(
3594+
state=BoolFlag[nextName].displayString
3595+
)
3596+
ui.message(msg)
3597+
35703598
@script(
35713599
description=_(
35723600
# Translators: Input help mode message for report clipboard text command.
@@ -4343,6 +4371,34 @@ def script_toggleReportCLDR(self, gesture):
43434371
characterProcessing.clearSpeechSymbols()
43444372
ui.message(state)
43454373

4374+
@script(
4375+
# Translators: Input help mode message for speech Unicode normalization command.
4376+
description=_("Cycle through the speech Unicode normalization states"),
4377+
category=SCRCAT_SPEECH
4378+
)
4379+
def script_speech_cycleUnicodeNormalization(self, gesture: inputCore.InputGesture) -> None:
4380+
featureFlag: FeatureFlag = config.conf["speech"]["unicodeNormalization"]
4381+
boolFlag: BoolFlag = featureFlag.enumClassType
4382+
values = [x.value for x in boolFlag]
4383+
currentValue = featureFlag.value.value
4384+
nextValueIndex = (currentValue % len(values)) + 1
4385+
nextName: str = boolFlag(nextValueIndex).name
4386+
config.conf["speech"]["unicodeNormalization"] = nextName
4387+
featureFlag = config.conf["speech"]["unicodeNormalization"]
4388+
if featureFlag.isDefault():
4389+
# Translators: Used when reporting speech Unicode normalization state
4390+
# (default behavior).
4391+
msg = _("Speech Unicode normalization default ({default})").format(
4392+
default=featureFlag.behaviorOfDefault.displayString
4393+
)
4394+
else:
4395+
# Translators: Used when reporting speech Unicode normalization state
4396+
# (disabled or enabled).
4397+
msg = _("Speech Unicode normalization {state}").format(
4398+
state=BoolFlag[nextName].displayString
4399+
)
4400+
ui.message(msg)
4401+
43464402
_tempEnableScreenCurtain = True
43474403
_waitingOnScreenCurtainWarningDialog: Optional[wx.Dialog] = None
43484404
_toggleScreenCurtainMessage: Optional[str] = None

source/gui/nvdaControls.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
# -*- coding: UTF-8 -*-
21
# A part of NonVisual Desktop Access (NVDA)
3-
# Copyright (C) 2016-2024 NV Access Limited, Derek Riemer, Cyrille Bougot, Luke Davis
2+
# Copyright (C) 2016-2024 NV Access Limited, Derek Riemer, Cyrille Bougot, Luke Davis, Leonard de Ruijter
43
# This file is covered by the GNU General Public License.
54
# See the file COPYING for more details.
65
import collections
@@ -426,16 +425,18 @@ def __init__(
426425
style=0,
427426
validator=wx.DefaultValidator,
428427
name=wx.ChoiceNameStr,
428+
onChoiceEventHandler: typing.Callable[[wx.CommandEvent], None] | None = None,
429429
):
430430
"""
431-
@param parent: The parent window.
432-
@param keyPath: The list of keys required to get to the config value.
433-
@param conf: The config.conf object.
434-
@param pos: The position of the control. Forwarded to wx.Choice
435-
@param size: The size of the control. Forwarded to wx.Choice
436-
@param style: The style of the control. Forwarded to wx.Choice
437-
@param validator: The validator for the control. Forwarded to wx.Choice
438-
@param name: The name of the control. Forwarded to wx.Choice
431+
:param parent: The parent window.
432+
:param keyPath: The list of keys required to get to the config value.
433+
:param conf: The config.conf object.
434+
:param pos: The position of the control. Forwarded to wx.Choice
435+
:param size: The size of the control. Forwarded to wx.Choice
436+
:param style: The style of the control. Forwarded to wx.Choice
437+
:param validator: The validator for the control. Forwarded to wx.Choice
438+
:param name: The name of the control. Forwarded to wx.Choice
439+
:param onChoiceEventHandler: Event handler bound for EVT_CHOICE
439440
"""
440441
self._confPath = keyPath
441442
self._conf = conf
@@ -462,7 +463,11 @@ def __init__(
462463
validator=validator,
463464
name=name,
464465
)
465-
466+
if onChoiceEventHandler is not None:
467+
self.Bind(
468+
wx.EVT_CHOICE,
469+
onChoiceEventHandler
470+
)
466471
self.SetSelection(self._getChoiceIndex(configValue.value))
467472
self.defaultValue = self._getConfSpecDefaultValue()
468473
"""The default value of the config spec. Not the "behavior of default".

source/gui/settingsDialogs.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,9 +1597,24 @@ def makeSettings(self, settingsSizer):
15971597
wxCtrlClass=nvdaControls.FeatureFlagCombo,
15981598
keyPath=["speech", "unicodeNormalization"],
15991599
conf=config.conf,
1600+
onChoiceEventHandler=self._onUnicodeNormalizationChange,
16001601
)
16011602
self.bindHelpEvent("SpeechUnicodeNormalization", self.unicodeNormalizationCombo)
16021603

1604+
# Translators: This is the label for a checkbox in the
1605+
# speech settings panel.
1606+
reportNormalizedForCharacterNavigationText = _("Report &Normalized when navigating by character")
1607+
self.reportNormalizedForCharacterNavigationCheckBox = settingsSizerHelper.addItem(
1608+
wx.CheckBox(self, label=reportNormalizedForCharacterNavigationText)
1609+
)
1610+
self.bindHelpEvent(
1611+
"SpeechReportNormalizedForCharacterNavigation",
1612+
self.reportNormalizedForCharacterNavigationCheckBox
1613+
)
1614+
self.reportNormalizedForCharacterNavigationCheckBox.SetValue(
1615+
config.conf["speech"]["reportNormalizedForCharacterNavigation"]
1616+
)
1617+
16031618
includeCLDRText = _(
16041619
# Translators: This is the label for a checkbox in the
16051620
# voice settings panel (if checked, data from the unicode CLDR will be used
@@ -1713,6 +1728,9 @@ def onSave(self):
17131728
].value
17141729
config.conf["speech"]["trustVoiceLanguage"] = self.trustVoiceLanguageCheckbox.IsChecked()
17151730
self.unicodeNormalizationCombo.saveCurrentValueToConf()
1731+
config.conf["speech"]["reportNormalizedForCharacterNavigation"] = (
1732+
self.reportNormalizedForCharacterNavigationCheckBox.IsChecked()
1733+
)
17161734
currentIncludeCLDR = config.conf["speech"]["includeCLDR"]
17171735
config.conf["speech"]["includeCLDR"] = newIncludeCldr = self.includeCLDRCheckbox.IsChecked()
17181736
if currentIncludeCLDR is not newIncludeCldr:
@@ -1753,6 +1771,12 @@ def _onSpeechModesListChange(self, evt: wx.CommandEvent):
17531771
+ [self._allSpeechModes.index(speech.SpeechMode.talk)]
17541772
)
17551773

1774+
def _onUnicodeNormalizationChange(self, evt: wx.CommandEvent):
1775+
evt.Skip()
1776+
self.reportNormalizedForCharacterNavigationCheckBox.Enable(
1777+
bool(self.unicodeNormalizationCombo._getControlCurrentFlag())
1778+
)
1779+
17561780
def isValid(self) -> bool:
17571781
enabledSpeechModes = self.speechModesList.CheckedItems
17581782
if len(enabledSpeechModes) < 2:

source/speech/commands.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,24 @@ class EndUtteranceCommand(SpeechCommand):
202202
def __repr__(self):
203203
return "EndUtteranceCommand()"
204204

205+
206+
class SuppressUnicodeNormalizationCommand(SpeechCommand):
207+
"""Suppresses Unicode normalization at a point in a speech sequence.
208+
For any text after this, Unicode normalization will be suppressed.
209+
To restore normalization, provide an EndUtteranceCommand.
210+
"""
211+
state: bool
212+
213+
def __init__(self, state: bool = True):
214+
"""
215+
@param state: SUppress normalization if True, don't suppress when False
216+
"""
217+
self.state = state
218+
219+
def __repr__(self):
220+
return f"SuppressUnicodeNormalizationCommand({self.state!r})"
221+
222+
205223
class BaseProsodyCommand(SynthParamCommand):
206224
"""Base class for commands which change voice prosody; i.e. pitch, rate, etc.
207225
The change to the setting is specified using either an offset or a multiplier, but not both.

source/speech/manager.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# Commands that are used in this file.
1515
EndUtteranceCommand,
1616
LangChangeCommand,
17+
SuppressUnicodeNormalizationCommand,
1718
SynthParamCommand,
1819
BaseCallbackCommand,
1920
ConfigProfileTriggerCommand,
@@ -363,6 +364,8 @@ def _processSpeechSequence(self, inSeq: SpeechSequence):
363364
continue
364365
if isinstance(command, SynthParamCommand):
365366
paramTracker.update(command)
367+
if isinstance(command, SuppressUnicodeNormalizationCommand):
368+
continue # Not handled by speech manager
366369
outSeq.append(command)
367370
# Add the last sequence and make sure the sequence ends the utterance.
368371
self._ensureEndUtterance(outSeq, outSeqs, paramsToReplay, paramTracker)

0 commit comments

Comments
 (0)