Skip to content

Commit f9f04fb

Browse files
authored
Merge 4ebabcb into 9a6b70e
2 parents 9a6b70e + 4ebabcb commit f9f04fb

11 files changed

Lines changed: 769 additions & 227 deletions

File tree

source/appModules/kindle.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import api
1313
from scriptHandler import willSayAllResume, isScriptWaiting
1414
import controlTypes
15+
from controlTypes import OutputReason
1516
import treeInterceptorHandler
1617
from cursorManager import ReviewCursorManager
1718
import browseMode
@@ -277,7 +278,7 @@ def getFormatFieldSpeech(
277278
attrs: textInfos.Field,
278279
attrsCache: Optional[textInfos.Field] = None,
279280
formatConfig: Optional[Dict[str, bool]] = None,
280-
reason: Optional[str] = None,
281+
reason: Optional[OutputReason] = None,
281282
unit: Optional[str] = None,
282283
extraDetail: bool = False,
283284
initialFormat: bool = False

source/browseMode.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from scriptHandler import isScriptWaiting, willSayAllResume
2626
import aria
2727
import controlTypes
28+
from controlTypes import OutputReason
2829
import config
2930
import textInfos
3031
import braille
@@ -39,7 +40,7 @@
3940
from abc import ABCMeta, abstractmethod
4041
from typing import Optional
4142

42-
REASON_QUICKNAV = "quickNav"
43+
REASON_QUICKNAV = OutputReason.QUICKNAV
4344

4445
def reportPassThrough(treeInterceptor,onlyIfChanged=True):
4546
"""Reports the pass through mode if it has changed.
@@ -304,7 +305,7 @@ def event_treeInterceptor_gainFocus(self):
304305
controlTypes.ROLE_CHECKMENUITEM,
305306
})
306307

307-
def shouldPassThrough(self, obj, reason=None):
308+
def shouldPassThrough(self, obj, reason: Optional[OutputReason] = None):
308309
"""Determine whether pass through mode should be enabled (focus mode) or disabled (browse mode) for a given object.
309310
@param obj: The object in question.
310311
@type obj: L{NVDAObjects.NVDAObject}

source/controlTypes.py

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#See the file COPYING for more details.
55
#Copyright (C) 2007-2016 NV Access Limited, Babbage B.V.
66
from typing import Dict, Union, Set, Any, Optional, List
7+
from enum import Enum, auto
78

89
ROLE_UNKNOWN=0
910
ROLE_WINDOW=1
@@ -622,27 +623,44 @@
622623
ROLE_APPLICATION,
623624
}
624625

625-
#{ Output reasons
626-
# These constants are used to specify the reason that a given piece of output was generated.
627-
#: An object to be reported due to a focus change or similar.
628-
REASON_FOCUS="focus"
629-
#: An ancestor of the focus object to be reported due to a focus change or similar.
630-
REASON_FOCUSENTERED="focusEntered"
631-
#: An item under the mouse.
632-
REASON_MOUSE="mouse"
633-
#: A response to a user query.
634-
REASON_QUERY="query"
635-
#: Reporting a change to an object.
636-
REASON_CHANGE="change"
637-
#: A generic, screen reader specific message.
638-
REASON_MESSAGE="message"
639-
#: Text reported as part of a say all.
640-
REASON_SAYALL="sayAll"
641-
#: Content reported due to caret movement or similar.
642-
REASON_CARET="caret"
643-
#: No output, but any state should be cached as if output had occurred.
644-
REASON_ONLYCACHE="onlyCache"
645-
#}
626+
627+
class OutputReason(Enum):
628+
"""Specify the reason that a given piece of output was generated.
629+
"""
630+
#: An object to be reported due to a focus change or similar.
631+
FOCUS = auto()
632+
#: An ancestor of the focus object to be reported due to a focus change or similar.
633+
FOCUSENTERED = auto()
634+
#: An item under the mouse.
635+
MOUSE = auto()
636+
#: A response to a user query.
637+
QUERY = auto()
638+
#: Reporting a change to an object.
639+
CHANGE = auto()
640+
#: A generic, screen reader specific message.
641+
MESSAGE = auto()
642+
#: Text reported as part of a say all.
643+
SAYALL = auto()
644+
#: Content reported due to caret movement or similar.
645+
CARET = auto()
646+
#: No output, but any state should be cached as if output had occurred.
647+
ONLYCACHE = auto()
648+
649+
QUICKNAV = auto()
650+
651+
# The following constants are kept for backwards compatibility.
652+
# In future, OutputReason should be used directly
653+
654+
655+
REASON_FOCUS = OutputReason.FOCUS
656+
REASON_FOCUSENTERED = OutputReason.FOCUSENTERED
657+
REASON_MOUSE = OutputReason.MOUSE
658+
REASON_QUERY = OutputReason.QUERY
659+
REASON_CHANGE = OutputReason.CHANGE
660+
REASON_MESSAGE = OutputReason.MESSAGE
661+
REASON_SAYALL = OutputReason.SAYALL
662+
REASON_CARET = OutputReason.CARET
663+
REASON_ONLYCACHE = OutputReason.ONLYCACHE
646664

647665
#: Text to use for 'current' values. These describe if an item is the current item
648666
#: within a particular kind of selection.
@@ -661,15 +679,14 @@
661679
"time":_("current time"),
662680
}
663681

664-
def processPositiveStates(role, states, reason, positiveStates=None):
682+
def processPositiveStates(role, states, reason: OutputReason, positiveStates=None):
665683
"""Processes the states for an object and returns the positive states to output for a specified reason.
666684
For example, if C{STATE_CHECKED} is in the returned states, it means that the processed object is checked.
667685
@param role: The role of the object to process states for (e.g. C{ROLE_CHECKBOX}.
668686
@type role: int
669687
@param states: The raw states for an object to process.
670688
@type states: set
671689
@param reason: The reason to process the states (e.g. C{REASON_FOCUS}.
672-
@type reason: str
673690
@param positiveStates: Used for C{REASON_CHANGE}, specifies states changed from negative to positive;
674691
@type positiveStates: set
675692
@return: The processed positive states.
@@ -719,15 +736,14 @@ def processPositiveStates(role, states, reason, positiveStates=None):
719736
positiveStates.discard(STATE_EDITABLE)
720737
return positiveStates
721738

722-
def processNegativeStates(role, states, reason, negativeStates=None):
739+
def processNegativeStates(role, states, reason: OutputReason, negativeStates=None):
723740
"""Processes the states for an object and returns the negative states to output for a specified reason.
724741
For example, if C{STATE_CHECKED} is in the returned states, it means that the processed object is not checked.
725742
@param role: The role of the object to process states for (e.g. C{ROLE_CHECKBOX}.
726743
@type role: int
727744
@param states: The raw states for an object to process.
728745
@type states: set
729746
@param reason: The reason to process the states (e.g. C{REASON_FOCUS}.
730-
@type reason: str
731747
@param negativeStates: Used for C{REASON_CHANGE}, specifies states changed from positive to negative;
732748
@type negativeStates: set
733749
@return: The processed negative states.
@@ -787,7 +803,7 @@ def processNegativeStates(role, states, reason, negativeStates=None):
787803
def processAndLabelStates(
788804
role: int,
789805
states: Set[Any],
790-
reason: str,
806+
reason: OutputReason,
791807
positiveStates: Optional[Set[Any]] = None,
792808
negativeStates: Optional[Set[Any]] = None,
793809
positiveStateLabelDict: Dict[int, str] = {},

source/sayAllHandler.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def next(self):
6565
if not obj:
6666
return
6767
# Call this method again when we start speaking this object.
68-
callbackCommand = speech.CallbackCommand(self.next)
68+
callbackCommand = speech.CallbackCommand(self.next, name="say-all:next")
6969
speech.speakObject(obj, reason=controlTypes.REASON_SAYALL, _prefixSpeechCommand=callbackCommand)
7070

7171
def stop(self):
@@ -117,9 +117,11 @@ def __init__(self, cursor):
117117

118118
def nextLine(self):
119119
if not self.reader:
120+
log.debug("no self.reader")
120121
# We were stopped.
121122
return
122123
if not self.reader.obj:
124+
log.debug("no self.reader.obj")
123125
# The object died, so we should too.
124126
self.finish()
125127
return
@@ -135,17 +137,30 @@ def nextLine(self):
135137
# No more text.
136138
if isinstance(self.reader.obj, textInfos.DocumentWithPageTurns):
137139
# Once the last line finishes reading, try turning the page.
138-
cb = speech.CallbackCommand(self.turnPage)
140+
cb = speech.CallbackCommand(self.turnPage, name="say-all:turnPage")
139141
speech.speakWithoutPauses([cb, speech.EndUtteranceCommand()])
140142
else:
141143
self.finish()
142144
return
145+
143146
# Call lineReached when we start speaking this line.
144147
# lineReached will move the cursor and trigger reading of the next line.
145-
cb = speech.CallbackCommand(lambda obj=self.reader.obj, state=self.speakTextInfoState.copy(): self.lineReached(obj,bookmark, state))
146-
spoke = speech.speakTextInfo(self.reader, unit=textInfos.UNIT_READINGCHUNK,
147-
reason=controlTypes.REASON_SAYALL, _prefixSpeechCommand=cb,
148-
useCache=self.speakTextInfoState)
148+
def _onLineReached(obj=self.reader.obj, state=self.speakTextInfoState.copy()):
149+
self.lineReached(obj, bookmark, state)
150+
151+
cb = speech.CallbackCommand(
152+
_onLineReached,
153+
name="say-all:lineReached"
154+
)
155+
156+
spoke = speech.speakTextInfo(
157+
self.reader,
158+
unit=textInfos.UNIT_READINGCHUNK,
159+
reason=controlTypes.REASON_SAYALL,
160+
_prefixSpeechCommand=cb,
161+
useCache=self.speakTextInfoState
162+
)
163+
149164
# Collapse to the end of this line, ready to read the next.
150165
try:
151166
self.reader.collapse(end=True)
@@ -186,6 +201,7 @@ def turnPage(self):
186201
try:
187202
self.reader.obj.turnPage()
188203
except RuntimeError:
204+
log.debug("No more pages")
189205
# No more pages.
190206
self.stop()
191207
return
@@ -198,9 +214,12 @@ def finish(self):
198214
# Otherwise, if a different synth is being used for say all,
199215
# we might switch synths too early and truncate the final speech.
200216
# We do this by putting a CallbackCommand at the start of a new utterance.
201-
cb = speech.CallbackCommand(self.stop)
202-
speech.speakWithoutPauses([speech.EndUtteranceCommand(), cb,
203-
speech.EndUtteranceCommand()])
217+
cb = speech.CallbackCommand(self.stop, name="say-all:stop")
218+
speech.speakWithoutPauses([
219+
speech.EndUtteranceCommand(),
220+
cb,
221+
speech.EndUtteranceCommand()
222+
])
204223

205224
def stop(self):
206225
if not self.reader:

0 commit comments

Comments
 (0)