Ejemplo n.º 1
0
	def test_invalidated_newSpeech(self):
		"""New speech should cause a cancellation of speech that has become
			invalid after being sent to the synth.
			Ensure that new speech can be started as soon as possible to reduce
			the stammering of the synth.
		"""
		smi = SpeechManagerInteractions(self)
		isSpeechNumberValid = {}

		def _checkIfValid(speechNumber):
			return isSpeechNumberValid.get(speechNumber, False)

		with smi.expectation():
			initiallyValidSequence = [
				"text 1",
				smi.create_CallBackCommand(expectedToBecomeIndex=1),
				"text 2",
				smi.create_ExpectedIndex(expectedToBecomeIndex=2),
				_CancellableSpeechCommand(lambda: _checkIfValid(1)),
			]
			isSpeechNumberValid[1] = True  # initially valid
			smi.speak(initiallyValidSequence)
			smi.expect_synthSpeak(sequence=initiallyValidSequence[:4])

		isSpeechNumberValid[1] = False
		with smi.expectation():
			newSequence = [
				"text 3",
				smi.create_CallBackCommand(expectedToBecomeIndex=3),
				"text 4",
				smi.create_ExpectedIndex(expectedToBecomeIndex=4),
			]
			smi.speak(newSequence)
			smi.expect_synthCancel()
			smi.expect_synthSpeak(sequence=newSequence[:4])
Ejemplo n.º 2
0
	def test_invalidated_indexHit(self):
		"""Hitting an index should cause a cancellation of speech that has become
			invalid after being sent to the synth.
			For particularly long utterances with many indexes, the speech can be
			stopped sooner.
		"""
		smi = SpeechManagerInteractions(self)
		isSpeechNumberValid = {}

		def _checkIfValid(speechNumber):
			return isSpeechNumberValid.get(speechNumber, False)

		with smi.expectation():
			initiallyValidSequence = [
				"text 1",
				smi.create_CallBackCommand(expectedToBecomeIndex=1),
				"text 2",
				smi.create_ExpectedIndex(expectedToBecomeIndex=2),
				_CancellableSpeechCommand(lambda: _checkIfValid(1)),
			]
			isSpeechNumberValid[1] = True  # initially valid
			smi.speak(initiallyValidSequence)
			smi.expect_synthSpeak(sequence=initiallyValidSequence[:4])

		with smi.expectation():
			isSpeechNumberValid[1] = False  # becomes invalid
			smi.indexReached(1)
			smi.expect_indexReachedCallback(forIndex=1)
			smi.pumpAll()
			smi.expect_synthCancel()
Ejemplo n.º 3
0
	def test_invalidSpeechNotSpoken(self):
		"""Ensure that invalid speech is not sent to the synth"""
		smi = SpeechManagerInteractions(self)

		with smi.expectation():
			text = "This stays invalid"
			smi.speak([text, _CancellableSpeechCommand(lambda: False)])
Ejemplo n.º 4
0
def _getFocusLossCancellableSpeechCommand(
		obj,
		reason: controlTypes.OutputReason
) -> Optional[_CancellableSpeechCommand]:
	if reason != controlTypes.REASON_FOCUS or not speech.manager._shouldCancelExpiredFocusEvents():
		return None
	from NVDAObjects import NVDAObject
	if not isinstance(obj, NVDAObject):
		log.warning("Unhandled object type. Expected all objects to be descendant from NVDAObject")
		return None
	previouslyHadFocus: bool = getattr(
		obj,
		WAS_GAIN_FOCUS_OBJ_ATTR_NAME,
		False
	)

	def isSpeechStillValid():
		from eventHandler import lastQueuedFocusObject
		isLastFocusObj: bool = obj is lastQueuedFocusObject
		stillValid = isLastFocusObj or not previouslyHadFocus

		log._speechManagerDebug(
			"checked if valid (isLast: %s, previouslyHad: %s): %s",
			isLastFocusObj,
			previouslyHadFocus,
			obj.name
		)
		return stillValid

	return _CancellableSpeechCommand(isSpeechStillValid)
Ejemplo n.º 5
0
	def test_validSpeechSpoken(self):
		"""Tests the outcome when speech stays valid. It should not be cancelled."""
		smi = SpeechManagerInteractions(self)

		with smi.expectation():
			text = "This stays valid"
			smi.speak([text, _CancellableSpeechCommand(lambda: True)])
			smi.expect_synthSpeak(sequence=[text, smi.create_ExpectedIndex(expectedToBecomeIndex=1)])
Ejemplo n.º 6
0
	def test_validSpeechAfterInvalid(self):
		"""Tests that calling speak with invalid speech will not lock up the SpeechManager.
		Under certain circumstances this resulted in NVDA going silent when more speech was in the queue.
		"""
		smi = SpeechManagerInteractions(self)

		with smi.expectation():
			smi.speak([
				"Stays invalid",
				_CancellableSpeechCommand(lambda: False),
				smi.create_ExpectedIndex(expectedToBecomeIndex=1)
			])

		with smi.expectation():
			smi.speak(["Stays valid", _CancellableSpeechCommand(lambda: True)])
			smi.expect_synthSpeak(sequence=[
				"Stays valid", smi.create_ExpectedIndex(expectedToBecomeIndex=2)
			])
Ejemplo n.º 7
0
	def test_invalidated_newSpeechWithCancellable(self):
		"""New speech that contains a cancellableSpeechCommand should cause a
			cancellation of speech that has become invalid after being sent to the
			synth.
			Similar to test_invalidated_newSpeech, but ensure that the
			cancellableSpeechCommand does not affect the behaviour.
			"""
		smi = SpeechManagerInteractions(self)
		isSpeechNumberValid = {}

		def _checkIfValid(speechNumber):
			return isSpeechNumberValid.get(speechNumber, False)

		with smi.expectation():
			initiallyValidSequence = [
				"text 1",
				smi.create_CallBackCommand(expectedToBecomeIndex=1),
				"text 2",
				smi.create_ExpectedIndex(expectedToBecomeIndex=2),
				_CancellableSpeechCommand(lambda: _checkIfValid(1)),
			]
			isSpeechNumberValid[1] = True  # initially valid
			smi.speak(initiallyValidSequence)
			smi.expect_synthSpeak(sequence=initiallyValidSequence[:4])

		isSpeechNumberValid[1] = False
		isSpeechNumberValid[2] = True
		with smi.expectation():
			newValidSequence = [
				"text 3",
				smi.create_CallBackCommand(expectedToBecomeIndex=3),
				"text 4",
				smi.create_ExpectedIndex(expectedToBecomeIndex=4),
				_CancellableSpeechCommand(lambda: _checkIfValid(2)),
			]
			smi.speak(newValidSequence)
			smi.expect_synthCancel()
			smi.expect_synthSpeak(sequence=newValidSequence[:4])
Ejemplo n.º 8
0
def _getFocusLossCancellableSpeechCommand(
        obj, reason: controlTypes.OutputReason
) -> Optional[_CancellableSpeechCommand]:
    if reason != controlTypes.REASON_FOCUS or not speech.manager._shouldCancelExpiredFocusEvents(
    ):
        return None
    from NVDAObjects import NVDAObject
    if not isinstance(obj, NVDAObject):
        log.warning(
            "Unhandled object type. Expected all objects to be descendant from NVDAObject"
        )
        return None

    def previouslyHadFocus():
        return getattr(obj, WAS_GAIN_FOCUS_OBJ_ATTR_NAME, False)

    def isLastFocusObj():
        # Obj may have been created multiple times pointing to the same underlying object.
        return obj is lastQueuedFocusObject or obj == lastQueuedFocusObject

    def isAncestorOfCurrentFocus():
        return obj in api.getFocusAncestors()

    def isSpeechStillValid():
        stillValid = (isLastFocusObj() or not previouslyHadFocus()
                      or isAncestorOfCurrentFocus())
        return stillValid

    if not speech.manager._shouldDoSpeechManagerLogging():
        return _CancellableSpeechCommand(isSpeechStillValid)

    def getDevInfo():
        return (f"isLast: {isLastFocusObj()}"
                f", previouslyHad: {previouslyHadFocus()}"
                f", isAncestorOfCurrentFocus: {isAncestorOfCurrentFocus()}")

    return _CancellableSpeechCommand(isSpeechStillValid, getDevInfo)