Skip to content

Commit

Permalink
Merge f7a48f0 into 8a82bd5
Browse files Browse the repository at this point in the history
  • Loading branch information
cary-rowen authored Dec 12, 2024
2 parents 8a82bd5 + f7a48f0 commit 259e6d5
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 50 deletions.
6 changes: 5 additions & 1 deletion source/NVDAObjects/behaviors.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import globalVars
from typing import List, Union
import diffHandler
from config.configFlags import TypingEcho


class ProgressBar(NVDAObject):
Expand Down Expand Up @@ -571,7 +572,10 @@ def event_typedCharacter(self, ch):
else:
self._hasTab = False
if (
(config.conf["keyboard"]["speakTypedCharacters"] or config.conf["keyboard"]["speakTypedWords"])
(
config.conf["keyboard"]["speakTypedCharacters"] > TypingEcho.OFF.value
or config.conf["keyboard"]["speakTypedWords"] > TypingEcho.OFF.value
)
and not config.conf["terminals"]["speakPasswords"]
and self._supportsTextChange
):
Expand Down
6 changes: 5 additions & 1 deletion source/NVDAObjects/inputComposition.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import eventHandler
import queueHandler
import controlTypes
from config.configFlags import TypingEcho
import characterProcessing
import speech
import config
Expand Down Expand Up @@ -73,7 +74,10 @@ def findOverlayClasses(self, clsList):
return clsList

def reportNewText(self, oldString, newString):
if config.conf["keyboard"]["speakTypedCharacters"] or config.conf["keyboard"]["speakTypedWords"]:
if (
config.conf["keyboard"]["speakTypedCharacters"] > TypingEcho.OFF.value
or config.conf["keyboard"]["speakTypedWords"] > TypingEcho.OFF.value
):
newText = calculateInsertedChars(oldString.strip("\u3000"), newString.strip("\u3000"))
if newText:
queueHandler.queueFunction(
Expand Down
24 changes: 24 additions & 0 deletions source/config/configFlags.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,30 @@ def _displayStringLabels(self):
}


@unique
class TypingEcho(DisplayStringIntEnum):
"""Enumeration containing the possible config values for typing echo (characters and words).
Use TypingEcho.MEMBER.value to compare with the config;
use TypingEcho.MEMBER.displayString in the UI for a translatable description of this member.
"""

OFF = 0
ON = 1
EDIT_CONTROLS = 2

@property
def _displayStringLabels(self):
return {
# Translators: One of the choices for typing echo in keyboard settings
TypingEcho.OFF: _("Off"),
# Translators: One of the choices for typing echo in keyboard settings
TypingEcho.ON: _("On"),
# Translators: One of the choices for typing echo in keyboard settings
TypingEcho.EDIT_CONTROLS: _("Only in edit controls"),
}


@unique
class ShowMessages(DisplayStringIntEnum):
"""Enumeration containing the possible config values for "Show messages" option in braille settings.
Expand Down
6 changes: 4 additions & 2 deletions source/config/configSpec.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,10 @@
# Default = 6: NumpadInsert + ExtendedInsert
NVDAModifierKeys = integer(1, 7, default=6)
keyboardLayout = string(default="desktop")
speakTypedCharacters = boolean(default=true)
speakTypedWords = boolean(default=false)
# 0: Off, 1: on, 2: Only in edit controls
speakTypedCharacters = integer(default=1,min=0,max=2)
# 0: Off, 1: on, 2: Only in edit controls
speakTypedWords = integer(default=1,min=0,max=2)
beepForLowercaseWithCapslock = boolean(default=true)
speakCommandKeys = boolean(default=false)
speechInterruptForCharacters = boolean(default=true)
Expand Down
31 changes: 13 additions & 18 deletions source/globalCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
ShowMessages,
BrailleMode,
OutputMode,
TypingEcho,
)
from config.featureFlag import FeatureFlag
from config.featureFlagEnums import BoolFlag
Expand Down Expand Up @@ -542,15 +543,12 @@ def script_previousSynthSetting(self, gesture):
gesture="kb:NVDA+2",
)
def script_toggleSpeakTypedCharacters(self, gesture):
if config.conf["keyboard"]["speakTypedCharacters"]:
# Translators: The message announced when toggling the speak typed characters keyboard setting.
state = _("speak typed characters off")
config.conf["keyboard"]["speakTypedCharacters"] = False
else:
# Translators: The message announced when toggling the speak typed characters keyboard setting.
state = _("speak typed characters on")
config.conf["keyboard"]["speakTypedCharacters"] = True
ui.message(state)
numVals = len(TypingEcho)
state = TypingEcho((config.conf["keyboard"]["speakTypedCharacters"] + 1) % numVals)
config.conf["keyboard"]["speakTypedCharacters"] = state.value
# Translators: Reported when the user cycles through speak typed characters modes.
# {mode} will be replaced with the mode; e.g. Off, On, Only in edit controls.
ui.message(_("Speak typed characters {mode}").format(mode=state.displayString))

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

@script(
# Translators: Input help mode message for toggle speak command keys command.
Expand Down
40 changes: 22 additions & 18 deletions source/gui/settingsDialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
ReportTableHeaders,
ReportCellBorders,
OutputMode,
TypingEcho,
)
import languageHandler
import speech
Expand Down Expand Up @@ -1981,24 +1982,27 @@ def makeSettings(self, settingsSizer):
checkedItems.append(n)
self.modifierList.CheckedItems = checkedItems
self.modifierList.Select(0)

self.bindHelpEvent("KeyboardSettingsModifiers", self.modifierList)
# Translators: This is the label for a checkbox in the
# keyboard settings panel.
charsText = _("Speak typed &characters")
self.charsCheckBox = sHelper.addItem(wx.CheckBox(self, label=charsText))
self.bindHelpEvent(
"KeyboardSettingsSpeakTypedCharacters",
self.charsCheckBox,
)
self.charsCheckBox.SetValue(config.conf["keyboard"]["speakTypedCharacters"])

# Translators: This is the label for a checkbox in the
# keyboard settings panel.
speakTypedWordsText = _("Speak typed &words")
self.wordsCheckBox = sHelper.addItem(wx.CheckBox(self, label=speakTypedWordsText))
self.bindHelpEvent("KeyboardSettingsSpeakTypedWords", self.wordsCheckBox)
self.wordsCheckBox.SetValue(config.conf["keyboard"]["speakTypedWords"])
# Translators: This is the label for a combobox in the keyboard settings panel.
charsLabelText = _("Speak typed &characters:")
charsChoices = [mode.displayString for mode in TypingEcho]
self.charsList = sHelper.addLabeledControl(charsLabelText, wx.Choice, choices=charsChoices)
self.bindHelpEvent("KeyboardSettingsSpeakTypedCharacters", self.charsList)
try:
self.charsList.SetSelection(config.conf["keyboard"]["speakTypedCharacters"])
except:
log.debugWarning("Could not set characters echo list to current setting", exc_info=True)

# Translators: This is the label for a combobox in the keyboard settings panel.
wordsLabelText = _("Speak typed &words:")
wordsChoices = [mode.displayString for mode in TypingEcho]
self.wordsList = sHelper.addLabeledControl(wordsLabelText, wx.Choice, choices=wordsChoices)
self.bindHelpEvent("KeyboardSettingsSpeakTypedWords", self.wordsList)
try:
self.wordsList.SetSelection(config.conf["keyboard"]["speakTypedWords"])
except:
log.debugWarning("Could not set words echo list to current setting", exc_info=True)

# Translators: This is the label for a checkbox in the
# keyboard settings panel.
Expand Down Expand Up @@ -2098,8 +2102,8 @@ def onSave(self):
config.conf["keyboard"]["NVDAModifierKeys"] = sum(
key.value for (n, key) in enumerate(NVDAKey) if self.modifierList.IsChecked(n)
)
config.conf["keyboard"]["speakTypedCharacters"] = self.charsCheckBox.IsChecked()
config.conf["keyboard"]["speakTypedWords"] = self.wordsCheckBox.IsChecked()
config.conf["keyboard"]["speakTypedCharacters"] = self.charsList.GetSelection()
config.conf["keyboard"]["speakTypedWords"] = self.wordsList.GetSelection()
config.conf["keyboard"]["speechInterruptForCharacters"] = (
self.speechInterruptForCharsCheckBox.IsChecked()
)
Expand Down
34 changes: 28 additions & 6 deletions source/speech/speech.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
ReportTableHeaders,
ReportCellBorders,
OutputMode,
TypingEcho,
)
import aria
from .priorities import Spri
Expand Down Expand Up @@ -780,8 +781,8 @@ def _getPlaceholderSpeechIfTextEmpty(
reason: OutputReason,
) -> Tuple[bool, SpeechSequence]:
"""Attempt to get speech for placeholder attribute if text for 'obj' is empty. Don't report the placeholder
value unless the text is empty, because it is confusing to hear the current value (presumably typed by the
user) *and* the placeholder. The placeholder should "disappear" once the user types a value.
value unless the text is empty, because it is confusing to hear the current value (presumably typed by the
user) *and* the placeholder. The placeholder should "disappear" once the user types a value.
@return: (True, SpeechSequence) if text for obj was considered empty and we attempted to get speech for the
placeholder value. (False, []) if text for obj was not considered empty.
"""
Expand Down Expand Up @@ -1355,6 +1356,14 @@ def _suppressSpeakTypedCharacters(number: int):
FIRST_NONCONTROL_CHAR = " "


def is_editableControl() -> bool:
obj = api.getFocusObject()
controls = {controlTypes.ROLE_EDITABLETEXT, controlTypes.ROLE_DOCUMENT, controlTypes.ROLE_TERMINAL}
return (
obj.role in controls or controlTypes.STATE_EDITABLE in obj.states
) and controlTypes.STATE_READONLY not in obj.states


def speakTypedCharacters(ch: str):
typingIsProtected = api.isTypingProtected()
if typingIsProtected:
Expand All @@ -1374,8 +1383,14 @@ def speakTypedCharacters(ch: str):
clearTypedWordBuffer()
if log.isEnabledFor(log.IO):
log.io("typed word: %s" % typedWord)
if config.conf["keyboard"]["speakTypedWords"] and not typingIsProtected:
speakText(typedWord)
typingEchoMode = config.conf["keyboard"]["speakTypedWords"]
if typingEchoMode > TypingEcho.OFF.value and not typingIsProtected:
if (
typingEchoMode == TypingEcho.EDIT_CONTROLS.value
and is_editableControl()
or typingEchoMode == TypingEcho.ON.value
):
speakText(typedWord)
if _speechState._suppressSpeakTypedCharactersNumber > 0:
# We primarily suppress based on character count and still have characters to suppress.
# However, we time out after a short while just in case.
Expand All @@ -1387,8 +1402,15 @@ def speakTypedCharacters(ch: str):
_speechState._suppressSpeakTypedCharactersTime = None
else:
suppress = False
if not suppress and config.conf["keyboard"]["speakTypedCharacters"] and ch >= FIRST_NONCONTROL_CHAR:
speakSpelling(realChar)

typingEchoMode = config.conf["keyboard"]["speakTypedCharacters"]
if not suppress and typingEchoMode > TypingEcho.OFF.value and ch >= FIRST_NONCONTROL_CHAR:
if (
typingEchoMode == TypingEcho.EDIT_CONTROLS.value
and is_editableControl()
or typingEchoMode == TypingEcho.ON.value
):
speakSpelling(realChar)


class SpeakTextInfoState(object):
Expand Down
4 changes: 4 additions & 0 deletions user_docs/en/changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ To use this feature, "allow NVDA to control the volume of other applications" mu
* Component updates:
* Updated LibLouis Braille translator to [3.32.0](https://github.com/liblouis/liblouis/releases/tag/v3.32.0). (#17469, @LeonarddeR)
* Updated CLDR to version 46.0. (#17484, @OzancanKaratas)
* 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)

### Bug Fixes

Expand Down Expand Up @@ -138,6 +139,9 @@ As the NVDA update check URL is now configurable directly within NVDA, no replac
* The `space` keyword argument for `brailleDisplayDrivers.seikantk.InputGesture` now expects an `int` rather than a `bool`. (#17047, @school510587)
* The `[upgrade]` configuration section including `[upgrade][newLaptopKeyboardLayout]` has been removed. (#17191)
* 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)
* Changed keyboard typing echo configuration from boolean to integer values:
* `config.conf["keyboard"]["speakTypedCharacters"]` and `config.conf["keyboard"]["speakTypedWords"]` now use integer values (0=Off, 1=On, 2=Only in edit controls).
* Added `TypingEcho` enum in `config.configFlags` to represent these modes.

#### Deprecations

Expand Down
14 changes: 10 additions & 4 deletions user_docs/en/userGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ The actual commands will not execute while in input help mode.

| Name |Desktop key |Laptop key |Description|
|---|---|---|---|
|Speak typed characters |`NVDA+2` |`NVDA+2` |When enabled, NVDA will announce all characters you type on the keyboard.|
|Speak typed words |`NVDA+3` |`NVDA+3` |When enabled, NVDA will announce word you type on the keyboard.|
|Speak typed characters |`NVDA+2` |`NVDA+2` |Controls how NVDA announces characters you type. Options: Off, On, Only in edit controls.|keyboard.|
|Speak typed words |`NVDA+3` |`NVDA+3` |Controls how NVDA announces words you type. Options: Off, On, Only in edit controls.|
|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.|
|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.|

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

Key: NVDA+2

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

<!-- KC:setting -->

##### Speak Typed Words {#KeyboardSettingsSpeakTypedWords}

Key: NVDA+3

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

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

Expand Down

0 comments on commit 259e6d5

Please sign in to comment.