Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

520 lines
14 KiB

  1. //
  2. //
  3. // Sapilayr TIP CTextToSpeech implementation.
  4. //
  5. //
  6. #include "private.h"
  7. #include "sapilayr.h"
  8. #include "nui.h"
  9. #include "tts.h"
  10. // -------------------------------------------------------
  11. //
  12. // Implementation for CTextToSpeech
  13. //
  14. // -------------------------------------------------------
  15. CTextToSpeech::CTextToSpeech(CSapiIMX *psi)
  16. {
  17. m_psi = psi;
  18. m_fPlaybackInitialized = FALSE;
  19. m_fIsInPlay = FALSE;
  20. m_fIsInPause = FALSE;
  21. }
  22. CTextToSpeech::~CTextToSpeech( )
  23. {
  24. };
  25. /* --------------------------------------------------------
  26. // Function Name: _SetDictation
  27. //
  28. // Description: Temporally change the dictation status
  29. // while TTS is playing.
  30. //
  31. //
  32. // ----------------------------------------------------------*/
  33. void CTextToSpeech::_SetDictation( BOOL fEnable )
  34. {
  35. BOOL fDictOn;
  36. fDictOn = m_psi->GetDICTATIONSTAT_DictOnOff() && m_psi->GetOnOff() &&
  37. !m_psi->Get_SPEECH_DISABLED_Disabled() && !m_psi->Get_SPEECH_DISABLED_DictationDisabled();
  38. // Only when the dictation status now is On, we change the
  39. // status based on required value.
  40. if ( fDictOn )
  41. {
  42. // Temporally Enable/disable dictation.
  43. CSpTask *psp;
  44. m_psi->GetSpeechTask(&psp);
  45. if (psp)
  46. {
  47. if (psp->m_cpDictGrammar)
  48. {
  49. (psp->m_cpDictGrammar)->SetDictationState(fEnable ? SPRS_ACTIVE: SPRS_INACTIVE);
  50. }
  51. psp->Release();
  52. }
  53. }
  54. }
  55. /* --------------------------------------------------------
  56. // Function Name: TtsPlay
  57. //
  58. // Description: Play sound for currect selection or text
  59. // in visible area.
  60. //
  61. //
  62. // ----------------------------------------------------------*/
  63. HRESULT CTextToSpeech::TtsPlay( )
  64. {
  65. HRESULT hr = E_FAIL;
  66. if ( !m_psi )
  67. return E_FAIL;
  68. if ( !m_fPlaybackInitialized )
  69. {
  70. hr = m_psi->GetFunction(GUID_NULL, IID_ITfFnPlayBack, (IUnknown **)&m_cpPlayBack);
  71. if ( hr == S_OK )
  72. m_fPlaybackInitialized = TRUE;
  73. }
  74. if ( m_fPlaybackInitialized )
  75. {
  76. // Stop the possible previous speaking
  77. TtsStop( );
  78. hr = m_psi->_RequestEditSession(ESCB_TTS_PLAY, TF_ES_READWRITE);
  79. }
  80. return hr;
  81. }
  82. /* --------------------------------------------------------
  83. // Function Name: _TtsPlay
  84. //
  85. // Description: Edit session callback function for
  86. // TtsPlay (ESCB_TTS_PLAY)
  87. // It will call ITfFnPlayBack->Play( ).
  88. //
  89. // ----------------------------------------------------------*/
  90. HRESULT CTextToSpeech::_TtsPlay(TfEditCookie ec,ITfContext *pic)
  91. {
  92. HRESULT hr = S_OK;
  93. CComPtr<ITfRange> cpSelRange = NULL;
  94. BOOL fEmpty = TRUE;
  95. BOOL fPlayed = FALSE;
  96. hr = GetSelectionSimple(ec, pic, &cpSelRange);
  97. if ( hr == S_OK )
  98. cpSelRange->IsEmpty(ec, &fEmpty);
  99. if ( hr == S_OK && !fEmpty && m_cpPlayBack)
  100. {
  101. hr = m_cpPlayBack->Play(cpSelRange);
  102. fPlayed = TRUE;
  103. }
  104. else
  105. {
  106. CComPtr<ITfRange> cpRangeView;
  107. // Get the Active View Range
  108. hr = m_psi->_GetActiveViewRange(ec, pic, &cpRangeView);
  109. if( hr == S_OK )
  110. {
  111. if ( cpSelRange )
  112. {
  113. LONG l;
  114. hr = cpRangeView->CompareStart(ec, cpSelRange, TF_ANCHOR_START, &l);
  115. if ( hr == S_OK && l > 0 )
  116. {
  117. // Current selection is not in current active view.
  118. // Use Start Anchor in active view as start point.
  119. cpSelRange.Release( );
  120. hr = cpRangeView->Clone(&cpSelRange);
  121. }
  122. }
  123. else
  124. {
  125. cpSelRange.Release( );
  126. hr = cpRangeView->Clone(&cpSelRange);
  127. }
  128. if ( hr == S_OK && cpSelRange )
  129. {
  130. hr = cpSelRange->ShiftEndToRange(ec, cpRangeView, TF_ANCHOR_END);
  131. if ( hr == S_OK )
  132. {
  133. cpSelRange->IsEmpty(ec, &fEmpty);
  134. if ( hr == S_OK && !fEmpty)
  135. {
  136. hr = m_cpPlayBack->Play(cpSelRange);
  137. fPlayed = TRUE;
  138. }
  139. }
  140. }
  141. }
  142. }
  143. if (!fPlayed )
  144. {
  145. CSpeechUIServer *pSpeechUIServer;
  146. pSpeechUIServer = m_psi->GetSpeechUIServer( );
  147. if ( pSpeechUIServer )
  148. pSpeechUIServer->SetTtsPlayOnOff( FALSE );
  149. }
  150. return hr;
  151. }
  152. /* --------------------------------------------------------
  153. // Function Name: TtsStop
  154. //
  155. // Description: Stop current TTS playing immediately
  156. //
  157. // update the TTS session status.
  158. //
  159. // ----------------------------------------------------------*/
  160. HRESULT CTextToSpeech::TtsStop( )
  161. {
  162. HRESULT hr=S_OK;
  163. if ( _IsInPlay( ) && m_psi )
  164. {
  165. CComPtr<ISpVoice> cpSpVoice;
  166. CSpTask *psp;
  167. hr = m_psi->GetSpeechTask(&psp);
  168. if (hr == S_OK)
  169. {
  170. cpSpVoice = psp->_GetSpVoice( );
  171. if ( cpSpVoice )
  172. hr = cpSpVoice->Speak( NULL, SPF_PURGEBEFORESPEAK, NULL );
  173. psp->Release();
  174. _SetPlayMode(FALSE);
  175. }
  176. }
  177. return hr;
  178. }
  179. /* --------------------------------------------------------
  180. // Function Name: TtsPause
  181. //
  182. // Description: Pause current TTS playing immediately
  183. //
  184. // update the TTS session status.
  185. //
  186. // ----------------------------------------------------------*/
  187. HRESULT CTextToSpeech::TtsPause( )
  188. {
  189. HRESULT hr=S_OK;
  190. if ( _IsInPlay( ) && m_psi )
  191. {
  192. CComPtr<ISpVoice> cpSpVoice;
  193. CSpTask *psp;
  194. hr = m_psi->GetSpeechTask(&psp);
  195. if (hr == S_OK)
  196. {
  197. cpSpVoice = psp->_GetSpVoice( );
  198. if ( cpSpVoice )
  199. hr = cpSpVoice->Pause( );
  200. psp->Release();
  201. _SetPauseMode(TRUE);
  202. }
  203. }
  204. return hr;
  205. }
  206. /* --------------------------------------------------------
  207. // Function Name: TtsResume
  208. //
  209. // Description: Resume previous paused playing
  210. // update the TTS session status.
  211. //
  212. // ----------------------------------------------------------*/
  213. HRESULT CTextToSpeech::TtsResume( )
  214. {
  215. HRESULT hr=S_OK;
  216. if ( _IsInPause( ) && m_psi )
  217. {
  218. CComPtr<ISpVoice> cpSpVoice;
  219. CSpTask *psp;
  220. hr = m_psi->GetSpeechTask(&psp);
  221. if (hr == S_OK)
  222. {
  223. cpSpVoice = psp->_GetSpVoice( );
  224. if ( cpSpVoice )
  225. hr = cpSpVoice->Resume( );
  226. psp->Release();
  227. _SetPauseMode(FALSE);
  228. }
  229. }
  230. return hr;
  231. }
  232. /* --------------------------------------------------------
  233. // Function Name: _IsPureCiceroIC
  234. //
  235. // Description: Check current IC attribute to
  236. // determine it is PureCicero aware
  237. // or AIMM aware.
  238. //
  239. // ----------------------------------------------------------*/
  240. BOOL CTextToSpeech::_IsPureCiceroIC(ITfContext *pic)
  241. {
  242. BOOL fCiceroNative = FALSE;
  243. HRESULT hr = S_OK;
  244. if ( pic )
  245. {
  246. TF_STATUS tss;
  247. hr = pic->GetStatus(&tss);
  248. if (S_OK == hr)
  249. {
  250. //
  251. // If TS_SS_TRANSITORY is not set, means it is Cicero Aware.
  252. //
  253. if (!(tss.dwStaticFlags & TS_SS_TRANSITORY) )
  254. fCiceroNative = TRUE;
  255. }
  256. }
  257. return fCiceroNative;
  258. }
  259. /* --------------------------------------------------------
  260. // Function Name: _SetTTSButtonStatus
  261. //
  262. // Description: Based on current IC attribute to
  263. // determine if to active or gray
  264. // TTS buttons on toolbar.
  265. //
  266. // This function will be called under
  267. // TIM_CODE_SETFOCUS and TIM_CODE_INITIC.
  268. // ----------------------------------------------------------*/
  269. HRESULT CTextToSpeech::_SetTTSButtonStatus(ITfContext *pic)
  270. {
  271. BOOL fCiceroNative;
  272. HRESULT hr = S_OK;
  273. CSpeechUIServer *pSpeechUIServer;
  274. TraceMsg(TF_GENERAL, "CTextToSpeech::_SetTTSButtonStatus is called");
  275. if ( !m_psi )
  276. return E_FAIL;
  277. fCiceroNative = _IsPureCiceroIC(pic);
  278. pSpeechUIServer = m_psi->GetSpeechUIServer( );
  279. if ( pSpeechUIServer )
  280. {
  281. pSpeechUIServer->SetTtsButtonStatus( fCiceroNative );
  282. }
  283. return hr;
  284. }
  285. /* --------------------------------------------------------
  286. // Function Name: _HandleEventOnPlayButton
  287. //
  288. // Description: Handle mouse click event on Play button
  289. // or Hotkey Windows+S.
  290. //
  291. // it would be called by button's OnButtonUp
  292. // callback function, and by Hotkey handler.
  293. //
  294. // ----------------------------------------------------------*/
  295. HRESULT CTextToSpeech::_HandleEventOnPlayButton( )
  296. {
  297. HRESULT hr = S_OK;
  298. BOOL fTTSPlayOn;
  299. CSpeechUIServer *pSpeechUIServer;
  300. if ( !m_psi ) return E_FAIL;
  301. pSpeechUIServer = m_psi->GetSpeechUIServer( );
  302. if ( pSpeechUIServer == NULL) return E_FAIL;
  303. fTTSPlayOn = pSpeechUIServer->GetTtsPlayOnOff( );
  304. if ( fTTSPlayOn )
  305. {
  306. // It is under Play mode.
  307. // Click this button to stop playing.
  308. // If it is under Pause mode, the Speaker needs to be resumed first.
  309. BOOL fTTSPauseOn;
  310. fTTSPauseOn = pSpeechUIServer->GetTtsPauseOnOff( );
  311. if ( fTTSPauseOn )
  312. {
  313. // Under pause mode
  314. pSpeechUIServer->SetTtsPauseOnOff(FALSE);
  315. hr = TtsResume( );
  316. }
  317. }
  318. if ( (hr == S_OK) && fTTSPlayOn )
  319. {
  320. // It has already been in Play mode.
  321. // click this to stop playing.
  322. hr = TtsStop( );
  323. }
  324. else
  325. {
  326. // It is not in Playing mode.
  327. hr = TtsPlay( );
  328. }
  329. pSpeechUIServer->SetTtsPlayOnOff( !fTTSPlayOn );
  330. return hr;
  331. }
  332. /* --------------------------------------------------------
  333. // Function Name: _HandleEventOnPauseButton
  334. //
  335. // Description: Handle mouse click event on Pause Button.
  336. // it would be called by Pause button's
  337. // OnLButtonUp callback function.
  338. //
  339. // ----------------------------------------------------------*/
  340. HRESULT CTextToSpeech::_HandleEventOnPauseButton( )
  341. {
  342. HRESULT hr = S_OK;
  343. BOOL fTTSPauseOn;
  344. BOOL fTTSPlayOn;
  345. CSpeechUIServer *pSpeechUIServer;
  346. if ( !m_psi ) return E_FAIL;
  347. pSpeechUIServer = m_psi->GetSpeechUIServer( );
  348. if ( pSpeechUIServer == NULL) return E_FAIL;
  349. fTTSPauseOn = pSpeechUIServer->GetTtsPauseOnOff( );
  350. fTTSPlayOn = pSpeechUIServer->GetTtsPlayOnOff( );
  351. if ( fTTSPauseOn )
  352. {
  353. // It has already been in Pause mode.
  354. // click this to resume playing.
  355. hr = TtsResume( );
  356. }
  357. else
  358. {
  359. // It is not in Pause mode.
  360. if ( fTTSPlayOn )
  361. {
  362. hr = TtsPause( );
  363. }
  364. }
  365. if ( fTTSPlayOn )
  366. pSpeechUIServer->SetTtsPauseOnOff( !fTTSPauseOn );
  367. else
  368. {
  369. // If it is not under Play mode, click Pause button should not change the status.
  370. pSpeechUIServer->SetTtsPauseOnOff( FALSE );
  371. }
  372. return hr;
  373. }
  374. /* --------------------------------------------------------
  375. // Function Name: SpeakNotifyCallback
  376. //
  377. // Description: This is callback for m_cpSpVoice in CSptask.
  378. // Only SPEI_START_INPUT_STREAM &
  379. // SPEI_END_INPUT_STREAM are insterested.
  380. //
  381. // When the input stream is over, we want
  382. // to update the TTS buttons' toggle status
  383. // ----------------------------------------------------------*/
  384. void CSpTask::SpeakNotifyCallback( WPARAM wParam, LPARAM lParam )
  385. {
  386. USES_CONVERSION;
  387. CSpEvent event;
  388. CSpTask *_this = (CSpTask *)lParam;
  389. CSapiIMX *psi = NULL;
  390. CSpeechUIServer *pSpeechUIServer = NULL;
  391. CComPtr<ISpVoice> cpVoice = NULL;
  392. if ( _this )
  393. cpVoice = _this->_GetSpVoice( );
  394. if (!_this || !cpVoice)
  395. {
  396. return;
  397. }
  398. psi = _this->GetTip( );
  399. if ( psi )
  400. pSpeechUIServer = psi->GetSpeechUIServer( );
  401. else
  402. return;
  403. while ( event.GetFrom(cpVoice) == S_OK )
  404. {
  405. switch (event.eEventId)
  406. {
  407. case SPEI_START_INPUT_STREAM :
  408. TraceMsg(TF_GENERAL,"SPEI_START_INPUT_STREAM is notified");
  409. psi->_SetPlayMode(TRUE);
  410. // Update the toggle status for Play button.
  411. if ( pSpeechUIServer )
  412. pSpeechUIServer->SetTtsPlayOnOff( TRUE );
  413. break;
  414. case SPEI_END_INPUT_STREAM :
  415. TraceMsg(TF_GENERAL,"SPEI_END_INPUT_STREAM is notified");
  416. psi->_SetPlayMode(FALSE);
  417. // Update the toggle status for Play button.
  418. if ( pSpeechUIServer )
  419. pSpeechUIServer->SetTtsPlayOnOff( FALSE );
  420. break;
  421. }
  422. }
  423. return;
  424. }