Module sayAllHandler
[hide private]
[frames] | no frames]

Source Code for Module sayAllHandler

  1  #sayAllHandler.py 
  2  #A part of NonVisual Desktop Access (NVDA) 
  3  #Copyright (C) 2006-2007 NVDA Contributors <http://www.nvda-project.org/> 
  4  #This file is covered by the GNU General Public License. 
  5  #See the file COPYING for more details. 
  6   
  7  import itertools 
  8  import queueHandler 
  9  import config 
 10  import speech 
 11  import textInfos 
 12  import globalVars 
 13  import api 
 14  import tones 
 15  import time 
 16   
 17  CURSOR_CARET=0 
 18  CURSOR_REVIEW=1 
 19   
 20  _generatorID = None 
 21   
22 -def _startGenerator(generator):
23 global _generatorID 24 stop() 25 _generatorID = queueHandler.registerGeneratorObject(generator)
26
27 -def stop():
28 """Stop say all if a say all is in progress. 29 """ 30 global _generatorID 31 if _generatorID is None: 32 return 33 queueHandler.cancelGeneratorObject(_generatorID) 34 _generatorID = None
35
36 -def isRunning():
37 """Determine whether say all is currently running. 38 @return: C{True} if say all is currently running, C{False} if not. 39 @rtype: bool 40 @note: If say all completes and there is no call to L{stop} (which is called from L{speech.cancelSpeech}), this will incorrectly return C{True}. 41 This should not matter, but is worth noting nevertheless. 42 """ 43 global _generatorID 44 return _generatorID is not None
45
46 -def readObjects(obj):
47 _startGenerator(readObjectsHelper_generator(obj))
48
49 -def generateObjectSubtreeSpeech(obj,indexGen):
50 index=indexGen.next() 51 speech.speakObject(obj,reason=speech.REASON_SAYALL,index=index) 52 yield obj,index 53 child=obj.simpleFirstChild 54 while child: 55 childSpeech=generateObjectSubtreeSpeech(child,indexGen) 56 for r in childSpeech: 57 yield r 58 child=child.simpleNext
59
60 -def readObjectsHelper_generator(obj):
61 lastSentIndex=0 62 lastReceivedIndex=0 63 speechGen=generateObjectSubtreeSpeech(obj,itertools.count()) 64 objIndexMap={} 65 keepReading=True 66 keepUpdating=True 67 while keepUpdating: 68 # lastReceivedIndex might be None if other speech was interspersed with this say all. 69 # In this case, we want to send more text in case this was the last chunk spoken. 70 if lastReceivedIndex is None or (lastSentIndex-lastReceivedIndex)<=1: 71 if keepReading: 72 try: 73 o,lastSentIndex=speechGen.next() 74 except StopIteration: 75 keepReading=False 76 continue 77 objIndexMap[lastSentIndex]=o 78 receivedIndex=speech.getLastSpeechIndex() 79 if receivedIndex!=lastReceivedIndex and (lastReceivedIndex!=0 or receivedIndex!=None): 80 lastReceivedIndex=receivedIndex 81 lastReceivedObj=objIndexMap.get(lastReceivedIndex) 82 if lastReceivedObj is not None: 83 api.setNavigatorObject(lastReceivedObj) 84 #Clear old objects from the map 85 for i in objIndexMap.keys(): 86 if i<=lastReceivedIndex: 87 del objIndexMap[i] 88 while speech.isPaused: 89 yield 90 yield
91
92 -def readText(info,cursor):
93 _startGenerator(readTextHelper_generator(info,cursor))
94
95 -def readTextHelper_generator(info,cursor):
96 lastSentIndex=0 97 lastReceivedIndex=0 98 cursorIndexMap={} 99 if not info.obj: 100 # The object died, so we should too. 101 return 102 reader=info.copy() 103 if not reader.isCollapsed: 104 reader.collapse() 105 keepReading=True 106 keepUpdating=True 107 while keepUpdating: 108 if not reader.obj: 109 # The object died, so we should too. 110 return 111 # lastReceivedIndex might be None if other speech was interspersed with this say all. 112 # In this case, we want to send more text in case this was the last chunk spoken. 113 if lastReceivedIndex is None or (lastSentIndex-lastReceivedIndex)<=10: 114 if keepReading: 115 bookmark=reader.bookmark 116 index=lastSentIndex+1 117 delta=reader.move(textInfos.UNIT_READINGCHUNK,1,endPoint="end") 118 if delta<=0: 119 speech.speakWithoutPauses(None) 120 keepReading=False 121 continue 122 speech.speakTextInfo(reader,unit=textInfos.UNIT_READINGCHUNK,reason=speech.REASON_SAYALL,index=index) 123 lastSentIndex=index 124 cursorIndexMap[index]=bookmark 125 try: 126 reader.collapse(end=True) 127 except RuntimeError: #MS Word when range covers end of document 128 speech.speakWithoutPauses(None) 129 keepReading=False 130 else: 131 # We'll wait for speech to catch up a bit before sending more text. 132 if speech.speakWithoutPauses.lastSentIndex is None or (lastSentIndex-speech.speakWithoutPauses.lastSentIndex)>=10: # There is a 133 # There is a large chunk of pending speech 134 # Force speakWithoutPauses to send text to the synth so we can move on. 135 speech.speakWithoutPauses(None) 136 receivedIndex=speech.getLastSpeechIndex() 137 if receivedIndex!=lastReceivedIndex and (lastReceivedIndex!=0 or receivedIndex!=None): 138 lastReceivedIndex=receivedIndex 139 bookmark=cursorIndexMap.get(receivedIndex,None) 140 if bookmark is not None: 141 updater=reader.obj.makeTextInfo(bookmark) 142 if cursor==CURSOR_CARET: 143 updater.updateCaret() 144 if cursor!=CURSOR_CARET or config.conf["reviewCursor"]["followCaret"]: 145 api.setReviewPosition(updater) 146 while speech.isPaused: 147 yield 148 yield
149