Skip to content

Commit a0d096a

Browse files
authored
Merge b8019cf into bcc7f25
2 parents bcc7f25 + b8019cf commit a0d096a

4 files changed

Lines changed: 36 additions & 18 deletions

File tree

source/speech/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# Copyright (C) 2006-2021 NV Access Limited, Peter Vágner, Aleksey Sadovoy, Babbage B.V., Bill Dengler,
55
# Julien Cochuyt
66

7+
import functools
78
from .speech import (
89
_extendSpeechSequence_addMathForTextInfo,
910
_getSpellingSpeechAddCharMode,
@@ -155,7 +156,9 @@ def initialize():
155156
synthDriverHandler.setSynth(config.conf["speech"]["synth"])
156157
speechInitialize()
157158
sayAllInitialize(
158-
speak,
159+
# override speak func to always have suppressBlanks=True,
160+
# since blanks should never be spoken in say all
161+
functools.partial(speak, suppressBlanks=True),
159162
speakObject,
160163
getTextInfoSpeech,
161164
SpeakTextInfoState,

source/speech/speech.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ def speakSpelling(
238238
locale=locale,
239239
useCharacterDescriptions=useCharacterDescriptions
240240
))
241-
speak(seq, priority=priority)
241+
speak(seq, priority=priority, suppressBlanks=True)
242242

243243

244244
def _getSpellingSpeechAddCharMode(
@@ -878,12 +878,14 @@ def getIndentationSpeech(indentation: str, formatConfig: Dict[str, bool]) -> Spe
878878
def speak( # noqa: C901
879879
speechSequence: SpeechSequence,
880880
symbolLevel: Optional[int] = None,
881-
priority: Spri = Spri.NORMAL
881+
priority: Spri = Spri.NORMAL,
882+
suppressBlanks: bool = False
882883
):
883884
"""Speaks a sequence of text and speech commands
884885
@param speechSequence: the sequence of text and L{SpeechCommand} objects to speak
885886
@param symbolLevel: The symbol verbosity level; C{None} (default) to use the user's configuration.
886887
@param priority: The speech priority.
888+
@param suppressBlanks: Whether to not append "blank" to the speech even if considered blank
887889
"""
888890
logBadSequenceTypes(speechSequence)
889891
# in case priority was explicitly passed in as None, set to default.
@@ -943,9 +945,22 @@ def speak( # noqa: C901
943945
if autoLanguageSwitching and isinstance(item,LangChangeCommand):
944946
curLanguage=item.lang
945947
if isinstance(item,str):
946-
speechSequence[index]=processText(curLanguage,item,symbolLevel)
947-
if not inCharacterMode:
948-
speechSequence[index]+=CHUNK_SEPARATOR
948+
text = processText(curLanguage, item, symbolLevel)
949+
if not inCharacterMode and text:
950+
text += CHUNK_SEPARATOR
951+
speechSequence[index] = text
952+
# speech sequence should be considered blank if:
953+
# 1. it contains strings
954+
# 2. all strings are blank after processing
955+
if (
956+
not suppressBlanks
957+
and any(isinstance(i, str) for i in speechSequence)
958+
# for checking if blank, just check if empty instead of isBlank(),
959+
# since whitespace has been stripped during processing
960+
and all(not s for s in speechSequence if isinstance(s, str))
961+
):
962+
# Translators: This is spoken when the speech sequence is considered blank.
963+
speechSequence.append(_("blank"))
949964
_manager.speak(speechSequence, priority)
950965

951966

@@ -964,7 +979,7 @@ def speakPreselectedText(
964979
"""
965980
seq = getPreselectedTextSpeech(text)
966981
if seq:
967-
speak(seq, symbolLevel=None, priority=priority)
982+
speak(seq, symbolLevel=None, priority=priority, suppressBlanks=True)
968983

969984

970985
def getPreselectedTextSpeech(
@@ -1013,7 +1028,7 @@ def speakSelectionMessage(
10131028
):
10141029
seq = _getSelectionMessageSpeech(message, text)
10151030
if seq:
1016-
speak(seq, symbolLevel=None, priority=priority)
1031+
speak(seq, symbolLevel=None, priority=priority, suppressBlanks=True)
10171032

10181033

10191034
def _getSelectionMessageSpeech(
@@ -1230,7 +1245,7 @@ def speakTextInfo(
12301245

12311246
speechGen = GeneratorWithReturn(speechGen)
12321247
for seq in speechGen:
1233-
speak(seq, priority=priority)
1248+
speak(seq, priority=priority, suppressBlanks=suppressBlanks)
12341249
return speechGen.returnValue
12351250

12361251

tests/system/robot/chromeTests.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,7 @@ def test_pr11606():
862862
actualSpeech = _chrome.getSpeechAfterKey("tab")
863863
_asserts.strings_match(
864864
actualSpeech,
865-
"section multi line editable list bullet link A link B"
865+
"section multi line editable list bullet link A link B"
866866
)
867867
# move past the end of the first link.
868868
# This should not be affected due to pr #11606.
@@ -886,7 +886,7 @@ def test_pr11606():
886886
actualSpeech = _chrome.getSpeechAfterKey("NVDA+upArrow")
887887
_asserts.strings_match(
888888
actualSpeech,
889-
"bullet link A link B"
889+
"bullet link A link B"
890890
)
891891

892892

@@ -1214,14 +1214,14 @@ def test_ariaRoleDescription_inline_contentEditable():
12141214
actualSpeech = _chrome.getSpeechAfterKey("downArrow")
12151215
_asserts.strings_match(
12161216
actualSpeech,
1217-
"Start drawing Our logo End"
1217+
"Start drawing Our logo End"
12181218
)
12191219
# When reading the line by word,
12201220
# Both entering and exiting the custom role should be reported.
12211221
actualSpeech = _chrome.getSpeechAfterKey("control+rightArrow")
12221222
_asserts.strings_match(
12231223
actualSpeech,
1224-
"drawing Our logo out of drawing"
1224+
"drawing Our logo out of drawing"
12251225
)
12261226
actualSpeech = _chrome.getSpeechAfterKey("control+rightArrow")
12271227
_asserts.strings_match(

tests/system/robot/symbolPronunciationTests.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,10 @@ def test_moveByWord():
147147
"don't", # Expected: mid-word symbol
148148
'right-pointing arrow', 't-shirt',
149149
# todo: There should not be any "empty" words. Expect 'bar bar', and 'at caret star line'
150-
'1', 'bar', '2', '', '3', '', '4',
150+
'1', 'bar', '2', 'blank', '3', 'blank', '4',
151151
# end of first line
152152
'blank', # single space and newline
153-
'', # tab and newline todo: There should not be any "empty" words.
153+
'blank', # tab and newline todo: There should not be any "empty" words.
154154
'blank', # 4 spaces and newline
155155
'right-pointing arrow',
156156
't-shirt',
@@ -195,14 +195,14 @@ def test_moveByLine():
195195
symbolLevel=SymLevel.NONE,
196196
expectedSpeech=[
197197
'Say', '(quietly)', 'Hello,', 'Jim .', "don't", # Expect:
198-
'', # todo: Expect 'right-pointing arrow'
198+
'blank', # todo: Expect 'right-pointing arrow'
199199
't-shirt',
200-
'', # todo: Expect 'right-pointing arrow'
200+
'blank', # todo: Expect 'right-pointing arrow'
201201
't-shirt',
202202
't-shirt', # todo: Expect 'right-pointing arrow t-shirt'
203203
'1 2 3 4', # todo: Should symbols be passed to synth, i.e. "1 | 2 || 3 etc"?
204204
'blank', # single space
205-
'', # tab # todo: There should not be any "empty" lines.
205+
'blank', # tab # todo: There should not be any "empty" lines.
206206
'blank', # four spaces
207207
'blank', # end of doc
208208
]

0 commit comments

Comments
 (0)