// // // Sapilayr TIP CTextToSpeech implementation. // // #include "private.h" #include "sapilayr.h" #include "nui.h" #include "tts.h" // ------------------------------------------------------- // // Implementation for CTextToSpeech // // ------------------------------------------------------- CTextToSpeech::CTextToSpeech(CSapiIMX *psi) { m_psi = psi; m_fPlaybackInitialized = FALSE; m_fIsInPlay = FALSE; m_fIsInPause = FALSE; } CTextToSpeech::~CTextToSpeech( ) { }; /* -------------------------------------------------------- // Function Name: _SetDictation // // Description: Temporally change the dictation status // while TTS is playing. // // // ----------------------------------------------------------*/ void CTextToSpeech::_SetDictation( BOOL fEnable ) { BOOL fDictOn; fDictOn = m_psi->GetDICTATIONSTAT_DictOnOff() && m_psi->GetOnOff() && !m_psi->Get_SPEECH_DISABLED_Disabled() && !m_psi->Get_SPEECH_DISABLED_DictationDisabled(); // Only when the dictation status now is On, we change the // status based on required value. if ( fDictOn ) { // Temporally Enable/disable dictation. CSpTask *psp; m_psi->GetSpeechTask(&psp); if (psp) { if (psp->m_cpDictGrammar) { (psp->m_cpDictGrammar)->SetDictationState(fEnable ? SPRS_ACTIVE: SPRS_INACTIVE); } psp->Release(); } } } /* -------------------------------------------------------- // Function Name: TtsPlay // // Description: Play sound for currect selection or text // in visible area. // // // ----------------------------------------------------------*/ HRESULT CTextToSpeech::TtsPlay( ) { HRESULT hr = E_FAIL; if ( !m_psi ) return E_FAIL; if ( !m_fPlaybackInitialized ) { hr = m_psi->GetFunction(GUID_NULL, IID_ITfFnPlayBack, (IUnknown **)&m_cpPlayBack); if ( hr == S_OK ) m_fPlaybackInitialized = TRUE; } if ( m_fPlaybackInitialized ) { // Stop the possible previous speaking TtsStop( ); hr = m_psi->_RequestEditSession(ESCB_TTS_PLAY, TF_ES_READWRITE); } return hr; } /* -------------------------------------------------------- // Function Name: _TtsPlay // // Description: Edit session callback function for // TtsPlay (ESCB_TTS_PLAY) // It will call ITfFnPlayBack->Play( ). // // ----------------------------------------------------------*/ HRESULT CTextToSpeech::_TtsPlay(TfEditCookie ec,ITfContext *pic) { HRESULT hr = S_OK; CComPtr cpSelRange = NULL; BOOL fEmpty = TRUE; BOOL fPlayed = FALSE; hr = GetSelectionSimple(ec, pic, &cpSelRange); if ( hr == S_OK ) cpSelRange->IsEmpty(ec, &fEmpty); if ( hr == S_OK && !fEmpty && m_cpPlayBack) { hr = m_cpPlayBack->Play(cpSelRange); fPlayed = TRUE; } else { CComPtr cpRangeView; // Get the Active View Range hr = m_psi->_GetActiveViewRange(ec, pic, &cpRangeView); if( hr == S_OK ) { if ( cpSelRange ) { LONG l; hr = cpRangeView->CompareStart(ec, cpSelRange, TF_ANCHOR_START, &l); if ( hr == S_OK && l > 0 ) { // Current selection is not in current active view. // Use Start Anchor in active view as start point. cpSelRange.Release( ); hr = cpRangeView->Clone(&cpSelRange); } } else { cpSelRange.Release( ); hr = cpRangeView->Clone(&cpSelRange); } if ( hr == S_OK && cpSelRange ) { hr = cpSelRange->ShiftEndToRange(ec, cpRangeView, TF_ANCHOR_END); if ( hr == S_OK ) { cpSelRange->IsEmpty(ec, &fEmpty); if ( hr == S_OK && !fEmpty) { hr = m_cpPlayBack->Play(cpSelRange); fPlayed = TRUE; } } } } } if (!fPlayed ) { CSpeechUIServer *pSpeechUIServer; pSpeechUIServer = m_psi->GetSpeechUIServer( ); if ( pSpeechUIServer ) pSpeechUIServer->SetTtsPlayOnOff( FALSE ); } return hr; } /* -------------------------------------------------------- // Function Name: TtsStop // // Description: Stop current TTS playing immediately // // update the TTS session status. // // ----------------------------------------------------------*/ HRESULT CTextToSpeech::TtsStop( ) { HRESULT hr=S_OK; if ( _IsInPlay( ) && m_psi ) { CComPtr cpSpVoice; CSpTask *psp; hr = m_psi->GetSpeechTask(&psp); if (hr == S_OK) { cpSpVoice = psp->_GetSpVoice( ); if ( cpSpVoice ) hr = cpSpVoice->Speak( NULL, SPF_PURGEBEFORESPEAK, NULL ); psp->Release(); _SetPlayMode(FALSE); } } return hr; } /* -------------------------------------------------------- // Function Name: TtsPause // // Description: Pause current TTS playing immediately // // update the TTS session status. // // ----------------------------------------------------------*/ HRESULT CTextToSpeech::TtsPause( ) { HRESULT hr=S_OK; if ( _IsInPlay( ) && m_psi ) { CComPtr cpSpVoice; CSpTask *psp; hr = m_psi->GetSpeechTask(&psp); if (hr == S_OK) { cpSpVoice = psp->_GetSpVoice( ); if ( cpSpVoice ) hr = cpSpVoice->Pause( ); psp->Release(); _SetPauseMode(TRUE); } } return hr; } /* -------------------------------------------------------- // Function Name: TtsResume // // Description: Resume previous paused playing // update the TTS session status. // // ----------------------------------------------------------*/ HRESULT CTextToSpeech::TtsResume( ) { HRESULT hr=S_OK; if ( _IsInPause( ) && m_psi ) { CComPtr cpSpVoice; CSpTask *psp; hr = m_psi->GetSpeechTask(&psp); if (hr == S_OK) { cpSpVoice = psp->_GetSpVoice( ); if ( cpSpVoice ) hr = cpSpVoice->Resume( ); psp->Release(); _SetPauseMode(FALSE); } } return hr; } /* -------------------------------------------------------- // Function Name: _IsPureCiceroIC // // Description: Check current IC attribute to // determine it is PureCicero aware // or AIMM aware. // // ----------------------------------------------------------*/ BOOL CTextToSpeech::_IsPureCiceroIC(ITfContext *pic) { BOOL fCiceroNative = FALSE; HRESULT hr = S_OK; if ( pic ) { TF_STATUS tss; hr = pic->GetStatus(&tss); if (S_OK == hr) { // // If TS_SS_TRANSITORY is not set, means it is Cicero Aware. // if (!(tss.dwStaticFlags & TS_SS_TRANSITORY) ) fCiceroNative = TRUE; } } return fCiceroNative; } /* -------------------------------------------------------- // Function Name: _SetTTSButtonStatus // // Description: Based on current IC attribute to // determine if to active or gray // TTS buttons on toolbar. // // This function will be called under // TIM_CODE_SETFOCUS and TIM_CODE_INITIC. // ----------------------------------------------------------*/ HRESULT CTextToSpeech::_SetTTSButtonStatus(ITfContext *pic) { BOOL fCiceroNative; HRESULT hr = S_OK; CSpeechUIServer *pSpeechUIServer; TraceMsg(TF_GENERAL, "CTextToSpeech::_SetTTSButtonStatus is called"); if ( !m_psi ) return E_FAIL; fCiceroNative = _IsPureCiceroIC(pic); pSpeechUIServer = m_psi->GetSpeechUIServer( ); if ( pSpeechUIServer ) { pSpeechUIServer->SetTtsButtonStatus( fCiceroNative ); } return hr; } /* -------------------------------------------------------- // Function Name: _HandleEventOnPlayButton // // Description: Handle mouse click event on Play button // or Hotkey Windows+S. // // it would be called by button's OnButtonUp // callback function, and by Hotkey handler. // // ----------------------------------------------------------*/ HRESULT CTextToSpeech::_HandleEventOnPlayButton( ) { HRESULT hr = S_OK; BOOL fTTSPlayOn; CSpeechUIServer *pSpeechUIServer; if ( !m_psi ) return E_FAIL; pSpeechUIServer = m_psi->GetSpeechUIServer( ); if ( pSpeechUIServer == NULL) return E_FAIL; fTTSPlayOn = pSpeechUIServer->GetTtsPlayOnOff( ); if ( fTTSPlayOn ) { // It is under Play mode. // Click this button to stop playing. // If it is under Pause mode, the Speaker needs to be resumed first. BOOL fTTSPauseOn; fTTSPauseOn = pSpeechUIServer->GetTtsPauseOnOff( ); if ( fTTSPauseOn ) { // Under pause mode pSpeechUIServer->SetTtsPauseOnOff(FALSE); hr = TtsResume( ); } } if ( (hr == S_OK) && fTTSPlayOn ) { // It has already been in Play mode. // click this to stop playing. hr = TtsStop( ); } else { // It is not in Playing mode. hr = TtsPlay( ); } pSpeechUIServer->SetTtsPlayOnOff( !fTTSPlayOn ); return hr; } /* -------------------------------------------------------- // Function Name: _HandleEventOnPauseButton // // Description: Handle mouse click event on Pause Button. // it would be called by Pause button's // OnLButtonUp callback function. // // ----------------------------------------------------------*/ HRESULT CTextToSpeech::_HandleEventOnPauseButton( ) { HRESULT hr = S_OK; BOOL fTTSPauseOn; BOOL fTTSPlayOn; CSpeechUIServer *pSpeechUIServer; if ( !m_psi ) return E_FAIL; pSpeechUIServer = m_psi->GetSpeechUIServer( ); if ( pSpeechUIServer == NULL) return E_FAIL; fTTSPauseOn = pSpeechUIServer->GetTtsPauseOnOff( ); fTTSPlayOn = pSpeechUIServer->GetTtsPlayOnOff( ); if ( fTTSPauseOn ) { // It has already been in Pause mode. // click this to resume playing. hr = TtsResume( ); } else { // It is not in Pause mode. if ( fTTSPlayOn ) { hr = TtsPause( ); } } if ( fTTSPlayOn ) pSpeechUIServer->SetTtsPauseOnOff( !fTTSPauseOn ); else { // If it is not under Play mode, click Pause button should not change the status. pSpeechUIServer->SetTtsPauseOnOff( FALSE ); } return hr; } /* -------------------------------------------------------- // Function Name: SpeakNotifyCallback // // Description: This is callback for m_cpSpVoice in CSptask. // Only SPEI_START_INPUT_STREAM & // SPEI_END_INPUT_STREAM are insterested. // // When the input stream is over, we want // to update the TTS buttons' toggle status // ----------------------------------------------------------*/ void CSpTask::SpeakNotifyCallback( WPARAM wParam, LPARAM lParam ) { USES_CONVERSION; CSpEvent event; CSpTask *_this = (CSpTask *)lParam; CSapiIMX *psi = NULL; CSpeechUIServer *pSpeechUIServer = NULL; CComPtr cpVoice = NULL; if ( _this ) cpVoice = _this->_GetSpVoice( ); if (!_this || !cpVoice) { return; } psi = _this->GetTip( ); if ( psi ) pSpeechUIServer = psi->GetSpeechUIServer( ); else return; while ( event.GetFrom(cpVoice) == S_OK ) { switch (event.eEventId) { case SPEI_START_INPUT_STREAM : TraceMsg(TF_GENERAL,"SPEI_START_INPUT_STREAM is notified"); psi->_SetPlayMode(TRUE); // Update the toggle status for Play button. if ( pSpeechUIServer ) pSpeechUIServer->SetTtsPlayOnOff( TRUE ); break; case SPEI_END_INPUT_STREAM : TraceMsg(TF_GENERAL,"SPEI_END_INPUT_STREAM is notified"); psi->_SetPlayMode(FALSE); // Update the toggle status for Play button. if ( pSpeechUIServer ) pSpeechUIServer->SetTtsPlayOnOff( FALSE ); break; } } return; }