Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Only in edit controls" mode for typing echo #17505

Open
wants to merge 42 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
ec022e9
Add "Only in edit controls" mode for typing echo
cary-rowen Dec 11, 2024
4721d55
Pre-commit auto-fix
pre-commit-ci[bot] Dec 11, 2024
b46e1e4
Updated changes
cary-rowen Dec 12, 2024
146dd24
Merge branch 'TypedWords' of github.com:cary-rowen/nvda into TypedWords
cary-rowen Dec 12, 2024
f7a48f0
Merge branch 'master' into TypedWords
cary-rowen Dec 12, 2024
f0e5c0e
Add #noqa: E722 to suppress lint warnings
cary-rowen Dec 12, 2024
08336fd
Update configuration schema to version 14 and add upgrade step for bo…
cary-rowen Dec 12, 2024
3f2b7a7
Pre-commit auto-fix
pre-commit-ci[bot] Dec 12, 2024
830632f
Merged master branch
cary-rowen Dec 16, 2024
4f730a6
Merge branch 'master' into typedWords
cary-rowen Dec 18, 2024
d0f5330
Merge branch 'master' into typedWords
cary-rowen Dec 19, 2024
2b7adf2
Just update changes.
cary-rowen Dec 19, 2024
d648052
Change 'On' to 'Everywhere'
cary-rowen Dec 19, 2024
57cfcdb
Merge branch 'master' into typedWords
cary-rowen Jan 1, 2025
711e1a9
Apply code review changes.
cary-rowen Jan 7, 2025
11f3526
New option is now default
cary-rowen Jan 7, 2025
ec6ddf6
Apply code review changes
cary-rowen Jan 7, 2025
7785dfd
Fix name error
cary-rowen Jan 7, 2025
16f32aa
Fix lint
cary-rowen Jan 7, 2025
0496524
Merge branch 'master' into typedWords
cary-rowen Jan 8, 2025
6cd87a4
Pre-commit auto-fix
pre-commit-ci[bot] Jan 8, 2025
ef70a00
Uasof 'Everywhere, Update translator comments'e 'Always' insted
cary-rowen Jan 8, 2025
6349361
Use 'always' instead of 'everywhere, update translator comments'
cary-rowen Jan 8, 2025
0cb3ef8
Merge branch 'TypedWords' of github.com:cary-rowen/nvda into typedWords
cary-rowen Jan 8, 2025
0088d6a
New upgrade step method
cary-rowen Jan 8, 2025
9975afe
Pre-commit auto-fix
pre-commit-ci[bot] Jan 8, 2025
77ef2ff
Merge branch 'master' into typedWords
cary-rowen Jan 9, 2025
d326bdd
Improve upgrade steps
cary-rowen Jan 9, 2025
62e5403
Applied some review suggestions and improved the upgrade steps
cary-rowen Jan 9, 2025
dd86094
Update changes entries.
cary-rowen Jan 9, 2025
0892f12
Update copyright headers
cary-rowen Jan 9, 2025
1d5d615
Apply code review suggestions.
cary-rowen Jan 10, 2025
3a1ebf8
Make SAPI5 & MSSP voices use WavePlayer (WASAPI) (#17592)
gexgd0419 Jan 10, 2025
328d5b2
Adjusted the order of options in the doc.
cary-rowen Jan 10, 2025
13fd31c
Add toggleIntegerValue helper function and update toggle scripts
cary-rowen Jan 10, 2025
4040cd5
Pre-commit auto-fix
pre-commit-ci[bot] Jan 10, 2025
7c25e4c
Fix conflicts
cary-rowen Jan 11, 2025
b8ffc04
Apply code review suggestions, add type hints
cary-rowen Jan 11, 2025
efffdd9
Pre-commit auto-fix
pre-commit-ci[bot] Jan 11, 2025
5fff6c7
Merge branch 'master' into TypedWords
cary-rowen Jan 13, 2025
4c8eba2
Apply suggestions from code review
SaschaCowley Jan 13, 2025
7be75c6
Merge branch 'master' into TypedWords
cary-rowen Jan 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
)
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
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
):
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
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
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)
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
beepForLowercaseWithCapslock = boolean(default=true)
speakCommandKeys = boolean(default=false)
speechInterruptForCharacters = boolean(default=true)
Expand Down
31 changes: 13 additions & 18 deletions source/globalCommands.py
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
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.
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
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))
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
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))
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
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:")
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
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: # noqa: E722
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
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: # noqa: E722
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
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.
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
"""
Expand Down Expand Up @@ -1355,6 +1356,14 @@ def _suppressSpeakTypedCharacters(number: int):
FIRST_NONCONTROL_CHAR = " "


def is_editableControl() -> bool:
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
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:
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
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:
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
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
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved
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
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved

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
cary-rowen marked this conversation as resolved.
Show resolved Hide resolved

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