Skip to content

Commit 259e6d5

Browse files
authored
Merge f7a48f0 into 8a82bd5
2 parents 8a82bd5 + f7a48f0 commit 259e6d5

9 files changed

Lines changed: 115 additions & 50 deletions

File tree

source/NVDAObjects/behaviors.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import globalVars
3232
from typing import List, Union
3333
import diffHandler
34+
from config.configFlags import TypingEcho
3435

3536

3637
class ProgressBar(NVDAObject):
@@ -571,7 +572,10 @@ def event_typedCharacter(self, ch):
571572
else:
572573
self._hasTab = False
573574
if (
574-
(config.conf["keyboard"]["speakTypedCharacters"] or config.conf["keyboard"]["speakTypedWords"])
575+
(
576+
config.conf["keyboard"]["speakTypedCharacters"] > TypingEcho.OFF.value
577+
or config.conf["keyboard"]["speakTypedWords"] > TypingEcho.OFF.value
578+
)
575579
and not config.conf["terminals"]["speakPasswords"]
576580
and self._supportsTextChange
577581
):

source/NVDAObjects/inputComposition.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import eventHandler
22
import queueHandler
33
import controlTypes
4+
from config.configFlags import TypingEcho
45
import characterProcessing
56
import speech
67
import config
@@ -73,7 +74,10 @@ def findOverlayClasses(self, clsList):
7374
return clsList
7475

7576
def reportNewText(self, oldString, newString):
76-
if config.conf["keyboard"]["speakTypedCharacters"] or config.conf["keyboard"]["speakTypedWords"]:
77+
if (
78+
config.conf["keyboard"]["speakTypedCharacters"] > TypingEcho.OFF.value
79+
or config.conf["keyboard"]["speakTypedWords"] > TypingEcho.OFF.value
80+
):
7781
newText = calculateInsertedChars(oldString.strip("\u3000"), newString.strip("\u3000"))
7882
if newText:
7983
queueHandler.queueFunction(

source/config/configFlags.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,30 @@ def _displayStringLabels(self):
4545
}
4646

4747

48+
@unique
49+
class TypingEcho(DisplayStringIntEnum):
50+
"""Enumeration containing the possible config values for typing echo (characters and words).
51+
52+
Use TypingEcho.MEMBER.value to compare with the config;
53+
use TypingEcho.MEMBER.displayString in the UI for a translatable description of this member.
54+
"""
55+
56+
OFF = 0
57+
ON = 1
58+
EDIT_CONTROLS = 2
59+
60+
@property
61+
def _displayStringLabels(self):
62+
return {
63+
# Translators: One of the choices for typing echo in keyboard settings
64+
TypingEcho.OFF: _("Off"),
65+
# Translators: One of the choices for typing echo in keyboard settings
66+
TypingEcho.ON: _("On"),
67+
# Translators: One of the choices for typing echo in keyboard settings
68+
TypingEcho.EDIT_CONTROLS: _("Only in edit controls"),
69+
}
70+
71+
4872
@unique
4973
class ShowMessages(DisplayStringIntEnum):
5074
"""Enumeration containing the possible config values for "Show messages" option in braille settings.

source/config/configSpec.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,10 @@
179179
# Default = 6: NumpadInsert + ExtendedInsert
180180
NVDAModifierKeys = integer(1, 7, default=6)
181181
keyboardLayout = string(default="desktop")
182-
speakTypedCharacters = boolean(default=true)
183-
speakTypedWords = boolean(default=false)
182+
# 0: Off, 1: on, 2: Only in edit controls
183+
speakTypedCharacters = integer(default=1,min=0,max=2)
184+
# 0: Off, 1: on, 2: Only in edit controls
185+
speakTypedWords = integer(default=1,min=0,max=2)
184186
beepForLowercaseWithCapslock = boolean(default=true)
185187
speakCommandKeys = boolean(default=false)
186188
speechInterruptForCharacters = boolean(default=true)

source/globalCommands.py

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
ShowMessages,
4545
BrailleMode,
4646
OutputMode,
47+
TypingEcho,
4748
)
4849
from config.featureFlag import FeatureFlag
4950
from config.featureFlagEnums import BoolFlag
@@ -542,15 +543,12 @@ def script_previousSynthSetting(self, gesture):
542543
gesture="kb:NVDA+2",
543544
)
544545
def script_toggleSpeakTypedCharacters(self, gesture):
545-
if config.conf["keyboard"]["speakTypedCharacters"]:
546-
# Translators: The message announced when toggling the speak typed characters keyboard setting.
547-
state = _("speak typed characters off")
548-
config.conf["keyboard"]["speakTypedCharacters"] = False
549-
else:
550-
# Translators: The message announced when toggling the speak typed characters keyboard setting.
551-
state = _("speak typed characters on")
552-
config.conf["keyboard"]["speakTypedCharacters"] = True
553-
ui.message(state)
546+
numVals = len(TypingEcho)
547+
state = TypingEcho((config.conf["keyboard"]["speakTypedCharacters"] + 1) % numVals)
548+
config.conf["keyboard"]["speakTypedCharacters"] = state.value
549+
# Translators: Reported when the user cycles through speak typed characters modes.
550+
# {mode} will be replaced with the mode; e.g. Off, On, Only in edit controls.
551+
ui.message(_("Speak typed characters {mode}").format(mode=state.displayString))
554552

555553
@script(
556554
# Translators: Input help mode message for toggle speak typed words command.
@@ -559,15 +557,12 @@ def script_toggleSpeakTypedCharacters(self, gesture):
559557
gesture="kb:NVDA+3",
560558
)
561559
def script_toggleSpeakTypedWords(self, gesture):
562-
if config.conf["keyboard"]["speakTypedWords"]:
563-
# Translators: The message announced when toggling the speak typed words keyboard setting.
564-
state = _("speak typed words off")
565-
config.conf["keyboard"]["speakTypedWords"] = False
566-
else:
567-
# Translators: The message announced when toggling the speak typed words keyboard setting.
568-
state = _("speak typed words on")
569-
config.conf["keyboard"]["speakTypedWords"] = True
570-
ui.message(state)
560+
numVals = len(TypingEcho)
561+
state = TypingEcho((config.conf["keyboard"]["speakTypedWords"] + 1) % numVals)
562+
config.conf["keyboard"]["speakTypedWords"] = state.value
563+
# Translators: Reported when the user cycles through speak typed words modes.
564+
# {mode} will be replaced with the mode; e.g. Off, On, Only in edit controls.
565+
ui.message(_("Speak typed words {mode}").format(mode=state.displayString))
571566

572567
@script(
573568
# Translators: Input help mode message for toggle speak command keys command.

source/gui/settingsDialogs.py

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
ReportTableHeaders,
3939
ReportCellBorders,
4040
OutputMode,
41+
TypingEcho,
4142
)
4243
import languageHandler
4344
import speech
@@ -1981,24 +1982,27 @@ def makeSettings(self, settingsSizer):
19811982
checkedItems.append(n)
19821983
self.modifierList.CheckedItems = checkedItems
19831984
self.modifierList.Select(0)
1984-
19851985
self.bindHelpEvent("KeyboardSettingsModifiers", self.modifierList)
1986-
# Translators: This is the label for a checkbox in the
1987-
# keyboard settings panel.
1988-
charsText = _("Speak typed &characters")
1989-
self.charsCheckBox = sHelper.addItem(wx.CheckBox(self, label=charsText))
1990-
self.bindHelpEvent(
1991-
"KeyboardSettingsSpeakTypedCharacters",
1992-
self.charsCheckBox,
1993-
)
1994-
self.charsCheckBox.SetValue(config.conf["keyboard"]["speakTypedCharacters"])
19951986

1996-
# Translators: This is the label for a checkbox in the
1997-
# keyboard settings panel.
1998-
speakTypedWordsText = _("Speak typed &words")
1999-
self.wordsCheckBox = sHelper.addItem(wx.CheckBox(self, label=speakTypedWordsText))
2000-
self.bindHelpEvent("KeyboardSettingsSpeakTypedWords", self.wordsCheckBox)
2001-
self.wordsCheckBox.SetValue(config.conf["keyboard"]["speakTypedWords"])
1987+
# Translators: This is the label for a combobox in the keyboard settings panel.
1988+
charsLabelText = _("Speak typed &characters:")
1989+
charsChoices = [mode.displayString for mode in TypingEcho]
1990+
self.charsList = sHelper.addLabeledControl(charsLabelText, wx.Choice, choices=charsChoices)
1991+
self.bindHelpEvent("KeyboardSettingsSpeakTypedCharacters", self.charsList)
1992+
try:
1993+
self.charsList.SetSelection(config.conf["keyboard"]["speakTypedCharacters"])
1994+
except:
1995+
log.debugWarning("Could not set characters echo list to current setting", exc_info=True)
1996+
1997+
# Translators: This is the label for a combobox in the keyboard settings panel.
1998+
wordsLabelText = _("Speak typed &words:")
1999+
wordsChoices = [mode.displayString for mode in TypingEcho]
2000+
self.wordsList = sHelper.addLabeledControl(wordsLabelText, wx.Choice, choices=wordsChoices)
2001+
self.bindHelpEvent("KeyboardSettingsSpeakTypedWords", self.wordsList)
2002+
try:
2003+
self.wordsList.SetSelection(config.conf["keyboard"]["speakTypedWords"])
2004+
except:
2005+
log.debugWarning("Could not set words echo list to current setting", exc_info=True)
20022006

20032007
# Translators: This is the label for a checkbox in the
20042008
# keyboard settings panel.
@@ -2098,8 +2102,8 @@ def onSave(self):
20982102
config.conf["keyboard"]["NVDAModifierKeys"] = sum(
20992103
key.value for (n, key) in enumerate(NVDAKey) if self.modifierList.IsChecked(n)
21002104
)
2101-
config.conf["keyboard"]["speakTypedCharacters"] = self.charsCheckBox.IsChecked()
2102-
config.conf["keyboard"]["speakTypedWords"] = self.wordsCheckBox.IsChecked()
2105+
config.conf["keyboard"]["speakTypedCharacters"] = self.charsList.GetSelection()
2106+
config.conf["keyboard"]["speakTypedWords"] = self.wordsList.GetSelection()
21032107
config.conf["keyboard"]["speechInterruptForCharacters"] = (
21042108
self.speechInterruptForCharsCheckBox.IsChecked()
21052109
)

source/speech/speech.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
ReportTableHeaders,
6969
ReportCellBorders,
7070
OutputMode,
71+
TypingEcho,
7172
)
7273
import aria
7374
from .priorities import Spri
@@ -780,8 +781,8 @@ def _getPlaceholderSpeechIfTextEmpty(
780781
reason: OutputReason,
781782
) -> Tuple[bool, SpeechSequence]:
782783
"""Attempt to get speech for placeholder attribute if text for 'obj' is empty. Don't report the placeholder
783-
value unless the text is empty, because it is confusing to hear the current value (presumably typed by the
784-
user) *and* the placeholder. The placeholder should "disappear" once the user types a value.
784+
value unless the text is empty, because it is confusing to hear the current value (presumably typed by the
785+
user) *and* the placeholder. The placeholder should "disappear" once the user types a value.
785786
@return: (True, SpeechSequence) if text for obj was considered empty and we attempted to get speech for the
786787
placeholder value. (False, []) if text for obj was not considered empty.
787788
"""
@@ -1355,6 +1356,14 @@ def _suppressSpeakTypedCharacters(number: int):
13551356
FIRST_NONCONTROL_CHAR = " "
13561357

13571358

1359+
def is_editableControl() -> bool:
1360+
obj = api.getFocusObject()
1361+
controls = {controlTypes.ROLE_EDITABLETEXT, controlTypes.ROLE_DOCUMENT, controlTypes.ROLE_TERMINAL}
1362+
return (
1363+
obj.role in controls or controlTypes.STATE_EDITABLE in obj.states
1364+
) and controlTypes.STATE_READONLY not in obj.states
1365+
1366+
13581367
def speakTypedCharacters(ch: str):
13591368
typingIsProtected = api.isTypingProtected()
13601369
if typingIsProtected:
@@ -1374,8 +1383,14 @@ def speakTypedCharacters(ch: str):
13741383
clearTypedWordBuffer()
13751384
if log.isEnabledFor(log.IO):
13761385
log.io("typed word: %s" % typedWord)
1377-
if config.conf["keyboard"]["speakTypedWords"] and not typingIsProtected:
1378-
speakText(typedWord)
1386+
typingEchoMode = config.conf["keyboard"]["speakTypedWords"]
1387+
if typingEchoMode > TypingEcho.OFF.value and not typingIsProtected:
1388+
if (
1389+
typingEchoMode == TypingEcho.EDIT_CONTROLS.value
1390+
and is_editableControl()
1391+
or typingEchoMode == TypingEcho.ON.value
1392+
):
1393+
speakText(typedWord)
13791394
if _speechState._suppressSpeakTypedCharactersNumber > 0:
13801395
# We primarily suppress based on character count and still have characters to suppress.
13811396
# However, we time out after a short while just in case.
@@ -1387,8 +1402,15 @@ def speakTypedCharacters(ch: str):
13871402
_speechState._suppressSpeakTypedCharactersTime = None
13881403
else:
13891404
suppress = False
1390-
if not suppress and config.conf["keyboard"]["speakTypedCharacters"] and ch >= FIRST_NONCONTROL_CHAR:
1391-
speakSpelling(realChar)
1405+
1406+
typingEchoMode = config.conf["keyboard"]["speakTypedCharacters"]
1407+
if not suppress and typingEchoMode > TypingEcho.OFF.value and ch >= FIRST_NONCONTROL_CHAR:
1408+
if (
1409+
typingEchoMode == TypingEcho.EDIT_CONTROLS.value
1410+
and is_editableControl()
1411+
or typingEchoMode == TypingEcho.ON.value
1412+
):
1413+
speakSpelling(realChar)
13921414

13931415

13941416
class SpeakTextInfoState(object):

user_docs/en/changes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ To use this feature, "allow NVDA to control the volume of other applications" mu
4646
* Component updates:
4747
* Updated LibLouis Braille translator to [3.32.0](https://github.com/liblouis/liblouis/releases/tag/v3.32.0). (#17469, @LeonarddeR)
4848
* Updated CLDR to version 46.0. (#17484, @OzancanKaratas)
49+
* The keyboard settings for "Speak typed characters" and "Speak typed words" now have three options: Off, On, and Only in edit controls, replacing the previous On/Off toggles. (#17505, @Cary-rowen)
4950

5051
### Bug Fixes
5152

@@ -138,6 +139,9 @@ As the NVDA update check URL is now configurable directly within NVDA, no replac
138139
* The `space` keyword argument for `brailleDisplayDrivers.seikantk.InputGesture` now expects an `int` rather than a `bool`. (#17047, @school510587)
139140
* The `[upgrade]` configuration section including `[upgrade][newLaptopKeyboardLayout]` has been removed. (#17191)
140141
* In `NVDAObjects.window.scintilla.ScintillaTextInfo`, if no text is selected, the `collapse` method is overriden to expand to line if the `end` parameter is set to `True` (#17431, @nvdaes)
142+
* Changed keyboard typing echo configuration from boolean to integer values:
143+
* `config.conf["keyboard"]["speakTypedCharacters"]` and `config.conf["keyboard"]["speakTypedWords"]` now use integer values (0=Off, 1=On, 2=Only in edit controls).
144+
* Added `TypingEcho` enum in `config.configFlags` to represent these modes.
141145

142146
#### Deprecations
143147

user_docs/en/userGuide.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,8 @@ The actual commands will not execute while in input help mode.
247247

248248
| Name |Desktop key |Laptop key |Description|
249249
|---|---|---|---|
250-
|Speak typed characters |`NVDA+2` |`NVDA+2` |When enabled, NVDA will announce all characters you type on the keyboard.|
251-
|Speak typed words |`NVDA+3` |`NVDA+3` |When enabled, NVDA will announce word you type on the keyboard.|
250+
|Speak typed characters |`NVDA+2` |`NVDA+2` |Controls how NVDA announces characters you type. Options: Off, On, Only in edit controls.|keyboard.|
251+
|Speak typed words |`NVDA+3` |`NVDA+3` |Controls how NVDA announces words you type. Options: Off, On, Only in edit controls.|
252252
|Speak command keys |`NVDA+4` |`NVDA+4` |When enabled, NVDA will announce all non-character keys you type on the keyboard. This includes key combinations such as control plus another letter.|
253253
|Enable mouse tracking |`NVDA+m` |`NVDA+m` |When enabled, NVDA will announce the text currently under the mouse pointer, as you move it around the screen. This allows you to find things on the screen, by physically moving the mouse, rather than trying to find them through object navigation.|
254254

@@ -2600,15 +2600,21 @@ If no key is chosen as the NVDA key it may be impossible to access many NVDA com
26002600

26012601
Key: NVDA+2
26022602

2603-
When enabled, NVDA will announce all characters you type on the keyboard.
2603+
This combo box controls how NVDA announces characters you type on the keyboard. Options are:
2604+
* Off: NVDA will not announce any characters you type.
2605+
* On: NVDA will announce all characters you type.
2606+
* Only in edit controls: NVDA will only announce characters typed in edit controls and other areas where text can be typed.
26042607

26052608
<!-- KC:setting -->
26062609

26072610
##### Speak Typed Words {#KeyboardSettingsSpeakTypedWords}
26082611

26092612
Key: NVDA+3
26102613

2611-
When enabled, NVDA will announce all words you type on the keyboard.
2614+
This combo box controls how NVDA announces words you type. Options are:
2615+
* Off: NVDA will not announce any words you type.
2616+
* On: NVDA will announce all words you type.
2617+
* Only in edit controls: NVDA will only announce words typed in edit controls and other areas where text can be typed.
26122618

26132619
##### Speech interrupt for typed characters {#KeyboardSettingsSpeechInteruptForCharacters}
26142620

0 commit comments

Comments
 (0)