Beispiel #1
0
 def finish(self):
     # There is no more text.
     # Call stop to clean up, but only after speech completely finishes.
     # Otherwise, if a different synth is being used for say all,
     # we might switch synths too early and truncate the final speech.
     # We do this by putting a CallbackCommand at the start of a new utterance.
     cb = CallbackCommand(self.stop, name="say-all:stop")
     speech.speakWithoutPauses(
         [EndUtteranceCommand(), cb,
          EndUtteranceCommand()])
Beispiel #2
0
    def create_EndUtteranceCommand(self, expectedToBecomeIndex=None):
        """EndUtteranceCommand get converted into IndexCommands by speechManager. The expectedToBecomeIndex argument
		allow tracking that.
		@note: the expectedToBecomeIndex is tested to be ordered, contiguous, and unique with respect to other
		indexed commands to help to prevent errors in the tests.
		"""
        self._testCase.assertIsNotNone(
            expectedToBecomeIndex,
            "Did you forget to provide the 'expectedToBecomeIndex' argument?")
        self._assertStrictIndexOrder(expectedToBecomeIndex)
        e = EndUtteranceCommand()
        e.expectedIndexCommandIndex = expectedToBecomeIndex
        return e
Beispiel #3
0
    def test_redundantSequenceAfterEndUtterance(self):
        """
		Tests that redundant param change and index commands are not emitted as an extra utterance
		when the preceeding utterance contained param change commands and an EndUtterance command.
		See PR #11651
		E.g. speaking a character.
		"""
        smi = SpeechManagerInteractions(self)
        seq = [
            CharacterModeCommand(True),
            "a",
            smi.create_ExpectedIndex(1),
            EndUtteranceCommand(),
        ]
        with smi.expectation():
            smi.speak(seq)
            # synth should receive the characterMode, the letter 'a' and an index command.
            smi.expect_synthSpeak(sequence=seq[:-1])
        with smi.expectation():
            # Previously, this would result in synth.speak receiving
            # a call with sequence:
            # [CharacterModeCommand(True), IndexCommand(2)]
            # This is a problem because it includes an index command but no speech.
            # This is inefficient, and also some SAPI5 synths such as Ivona will not
            # notify of this bookmark.
            smi.indexReached(1)
            smi.doneSpeaking()
            smi.pumpAll()
Beispiel #4
0
 def test_onlySpaces(self):
     expected = repr([
         'space',
         EndUtteranceCommand(),
         'tab',
         EndUtteranceCommand(),
     ])
     output = _getSpellingSpeechWithoutCharMode(
         text=' \t',
         locale=None,
         useCharacterDescriptions=False,
         sayCapForCapitals=False,
         capPitchChange=0,
         beepForCapitals=False,
     )
     self.assertEqual(repr(list(output)), expected)
Beispiel #5
0
 def test_manySymbolNamesInARow(self):
     # Spelling a...b
     seq = (c for c in [
         'a',
         EndUtteranceCommand(), 'dot',
         EndUtteranceCommand(), 'dot',
         EndUtteranceCommand(), 'dot',
         EndUtteranceCommand(), 'b',
         EndUtteranceCommand()
     ])
     expected = repr([
         CharacterModeCommand(True), 'a',
         EndUtteranceCommand(),
         CharacterModeCommand(False), 'dot',
         EndUtteranceCommand(), 'dot',
         EndUtteranceCommand(), 'dot',
         EndUtteranceCommand(),
         CharacterModeCommand(True), 'b',
         EndUtteranceCommand()
     ])
     output = _getSpellingSpeechAddCharMode(seq)
     self.assertEqual(repr(list(output)), expected)
Beispiel #6
0
 def test_characterMode(self):
     expected = repr([
         'Alfa',
         EndUtteranceCommand(),
     ])
     output = _getSpellingSpeechWithoutCharMode(
         text='a',
         locale='en',
         useCharacterDescriptions=True,
         sayCapForCapitals=False,
         capPitchChange=0,
         beepForCapitals=False,
     )
     self.assertEqual(repr(list(output)), expected)
Beispiel #7
0
 def test_languageDetection(self):
     config.conf['speech']['autoLanguageSwitching'] = True
     expected = repr([
         LangChangeCommand('fr_FR'),
         'a',
         EndUtteranceCommand(),
     ])
     output = _getSpellingSpeechWithoutCharMode(
         text='a',
         locale='fr_FR',
         useCharacterDescriptions=False,
         sayCapForCapitals=False,
         capPitchChange=0,
         beepForCapitals=False,
     )
     self.assertEqual(repr(list(output)), expected)
Beispiel #8
0
 def test_cap(self):
     expected = repr([
         PitchCommand(offset=30),
         BeepCommand(2000, 50, left=50, right=50),
         'cap ',
         'A',
         PitchCommand(),
         EndUtteranceCommand(),
     ])
     output = _getSpellingSpeechWithoutCharMode(
         text='A',
         locale=None,
         useCharacterDescriptions=False,
         sayCapForCapitals=True,
         capPitchChange=30,
         beepForCapitals=True,
     )
     self.assertEqual(repr(list(output)), expected)
        def createInputSequences():
            """Speech sequences that are input to 'speechWithoutPauses' when triggering the 'read-all' command
			on the wxPython wiki page.
			"""
            return [[
                callbackCommand, lang_en,
                'The purpose of the wxPyWiki is to provide documentation, examples, how-tos, etc. for helping people ',
                lang_default
            ],
                    [
                        callbackCommand, lang_en, 'learn, understand and use ',
                        lang_default
                    ],
                    [
                        callbackCommand, 'visited', 'link', '', lang_en,
                        'wxPython', lang_default, lang_en,
                        '. Anything that falls within those guidelines is fair game. ',
                        lang_default
                    ],
                    [
                        EndUtteranceCommand(), callbackCommand, lang_en,
                        'Note: To get to the main wxPython site click ',
                        lang_default
                    ]]
Beispiel #10
0
 def test_symbolNamesAtStartAndEnd(self):
     # Spelling ¡hola!
     seq = (c for c in [
         'inverted exclamation point',
         EndUtteranceCommand(), 'h',
         EndUtteranceCommand(), 'o',
         EndUtteranceCommand(), 'l',
         EndUtteranceCommand(), 'a',
         EndUtteranceCommand(), 'bang',
         EndUtteranceCommand()
     ])
     expected = repr([
         'inverted exclamation point',
         EndUtteranceCommand(),
         CharacterModeCommand(True), 'h',
         EndUtteranceCommand(), 'o',
         EndUtteranceCommand(), 'l',
         EndUtteranceCommand(), 'a',
         EndUtteranceCommand(),
         CharacterModeCommand(False), 'bang',
         EndUtteranceCommand()
     ])
     output = _getSpellingSpeechAddCharMode(seq)
     self.assertEqual(repr(list(output)), expected)
Beispiel #11
0
    def nextLine(self):
        if not self.reader:
            log.debug("no self.reader")
            # We were stopped.
            return
        if not self.reader.obj:
            log.debug("no self.reader.obj")
            # The object died, so we should too.
            self.finish()
            return
        bookmark = self.reader.bookmark
        # Expand to the current line.
        # We use move end rather than expand
        # because the user might start in the middle of a line
        # and we don't want to read from the start of the line in that case.
        # For lines after the first, it's also more efficient because
        # we're already at the start of the line, so there's no need to search backwards.
        delta = self.reader.move(textInfos.UNIT_READINGCHUNK,
                                 1,
                                 endPoint="end")
        if delta <= 0:
            # No more text.
            if isinstance(self.reader.obj, textInfos.DocumentWithPageTurns):
                # Once the last line finishes reading, try turning the page.
                cb = CallbackCommand(self.turnPage, name="say-all:turnPage")
                speech.speakWithoutPauses([cb, EndUtteranceCommand()])
            else:
                self.finish()
            return

        # Copy the speakTextInfoState so that speak callbackCommand
        # and its associated callback are using a copy isolated to this specific line.
        state = self.speakTextInfoState.copy()

        # Call lineReached when we start speaking this line.
        # lineReached will move the cursor and trigger reading of the next line.

        def _onLineReached(obj=self.reader.obj, state=state):
            self.lineReached(obj, bookmark, state)

        cb = CallbackCommand(_onLineReached, name="say-all:lineReached")

        # Generate the speech sequence for the reader textInfo
        # and insert the lineReached callback at the very beginning of the sequence.
        # _linePrefix on speakTextInfo cannot be used here
        # As it would be inserted in the sequence after all initial control starts which is too late.
        speechGen = speech.getTextInfoSpeech(
            self.reader,
            unit=textInfos.UNIT_READINGCHUNK,
            reason=controlTypes.OutputReason.SAYALL,
            useCache=state)
        seq = list(speech._flattenNestedSequences(speechGen))
        seq.insert(0, cb)
        # Speak the speech sequence.
        spoke = speech.speakWithoutPauses(seq)
        # Update the textInfo state ready for when speaking the next line.
        self.speakTextInfoState = state.copy()

        # Collapse to the end of this line, ready to read the next.
        try:
            self.reader.collapse(end=True)
        except RuntimeError:
            # This occurs in Microsoft Word when the range covers the end of the document.
            # without this exception to indicate that further collapsing is not possible, say all could enter an infinite loop.
            self.finish()
            return
        if not spoke:
            # This line didn't include a natural pause, so nothing was spoken.
            self.numBufferedLines += 1
            if self.numBufferedLines < self.MAX_BUFFERED_LINES:
                # Move on to the next line.
                # We queue this to allow the user a chance to stop say all.
                queueHandler.queueFunction(queueHandler.eventQueue,
                                           self.nextLine)
            else:
                # We don't want to buffer too much.
                # Force speech. lineReached will resume things when speech catches up.
                speech.speakWithoutPauses(None)
                # The first buffered line has now started speaking.
                self.numBufferedLines -= 1