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.
 
 
 
 
 
 

492 lines
12 KiB

//
// sptask.cpp
//
// implements a notification callback ISpTask
//
// created: 12/1/99
//
//
#include "private.h"
#include "globals.h"
#include "sptask.h"
#include "candui.h"
#include "ids.h"
#include "computil.h"
//
// ctor
//
//
CSpTask::CSpTask(CCandidateUI *pcui)
{
// CSpTask is initialized with an TFX instance
// so store the pointer to the TFX
// init data members here
m_pcui = pcui;
m_fSapiInitialized = FALSE;
m_fActive = FALSE;
m_fInCallback = FALSE;
}
CSpTask::~CSpTask()
{
_ReleaseGrammars();
}
//
// CSpTask::_InitializeSAPIObjects
//
// initialize SAPI objects for SR
// later we'll get other objects initialized here
// (TTS, audio etc)
//
HRESULT CSpTask::InitializeSAPIObjects(void)
{
#ifdef _WIN64
return E_NOTIMPL;
#else
if (m_fSapiInitialized == TRUE)
return m_cpRecoCtxt ? S_OK : E_FAIL;
// do not try again even in failure
m_fSapiInitialized = TRUE;
// m_xxx are CComPtrs from ATL
//
HRESULT hr = _GetSapilayrEngineInstance(&m_cpRecoEngine);
// create the recognition context
if( S_OK == hr )
{
hr = m_cpRecoEngine->CreateRecoContext( &m_cpRecoCtxt );
}
if ( hr == S_OK )
{
SPRECOGNIZERSTATUS stat;
if (S_OK == m_cpRecoEngine->GetStatus(&stat))
{
m_langid = stat.aLangID[0];
}
}
return hr;
#endif // _WIN64
}
//
// CSpTask::NotifyCallback
//
// INotifyControl object calls back here
// returns S_OK when it handles notifications
//
//
HRESULT CSpTask::NotifyCallback( WPARAM wParam, LPARAM lParam )
{
USES_CONVERSION;
// we can't delete reco context while we're in this callback
//
m_fInCallback = TRUE;
// also we can't terminate candidate UI object while in the callback
m_pcui->AddRef();
{
CSpEvent event;
while ( m_cpRecoCtxt && event.GetFrom(m_cpRecoCtxt) == S_OK )
{
switch (event.eEventId)
{
case SPEI_RECOGNITION:
_OnSpEventRecognition(event);
break;
default:
break;
}
}
}
m_fInCallback = FALSE;
m_pcui->Release();
return S_OK;
}
HRESULT CSpTask::_OnSpEventRecognition(CSpEvent &event)
{
HRESULT hr = S_OK;
ISpRecoResult *pResult = event.RecoResult();
if (pResult)
{
static const WCHAR szUnrecognized[] = L"<Unrecognized>";
SPPHRASE *pPhrase;
hr = pResult->GetPhrase(&pPhrase);
if (S_OK == hr)
{
if (pPhrase->ullGrammarID == GRAM_ID_CANDCC)
{
if (SUCCEEDED(hr) && pPhrase)
{
// retrieve LANGID from phrase
LANGID langid = pPhrase->LangID;
hr = _DoCommand(pPhrase, langid);
}
}
else if(pPhrase->ullGrammarID == GRAM_ID_DICT)
{
if (m_pcui->_ptim != NULL) {
// Windows bug#508709
// Ignore dictation event during SPTip is in commanding mode
DWORD dwSpeechGlobalState;
GetCompartmentDWORD(m_pcui->_ptim, GUID_COMPARTMENT_SPEECH_GLOBALSTATE, &dwSpeechGlobalState, TRUE);
if (dwSpeechGlobalState & TF_DICTATION_ON) {
hr = _DoDictation(pResult);
}
}
}
::CoTaskMemFree( pPhrase );
}
}
return hr;
}
const WCHAR c_szRuleName[] = L"ID_Candidate";
//
// CSpTask::_DoCommand
//
// review: the rulename may need to be localizable?
//
HRESULT CSpTask::_DoCommand(SPPHRASE *pPhrase, LANGID langid)
{
HRESULT hr = S_OK;
if ( wcscmp(pPhrase->Rule.pszName, c_szRuleName) == 0)
{
if (m_pcui)
{
hr = m_pcui->NotifySpeechCmd(pPhrase,
pPhrase->pProperties[0].pszValue,
pPhrase->pProperties[0].ulId);
}
}
return hr;
}
//
// CSpTask::_DoDictation
//
// support spelling
//
HRESULT CSpTask::_DoDictation(ISpRecoResult *pResult)
{
HRESULT hr = E_FAIL;
BYTE bAttr; // no need?
Assert(pResult);
// this cotaskmemfree's text we get
CSpDynamicString dstr;
hr = pResult->GetText(SP_GETWHOLEPHRASE, SP_GETWHOLEPHRASE, TRUE, &dstr, &bAttr);
if (S_OK == hr)
{
WCHAR sz[2]={0};
StringCchCopyW(sz, ARRAYSIZE(sz), dstr);
Assert(m_pcui);
hr = m_pcui->FHandleSpellingChar(sz[0]);
}
return hr;
}
//
// CSpTask::InitializeCallback
//
//
HRESULT CSpTask::InitializeCallback()
{
#ifdef _WIN64
return E_NOTIMPL;
#else
// set recognition notification
CComPtr<ISpNotifyTranslator> cpNotify;
HRESULT hr = cpNotify.CoCreateInstance(CLSID_SpNotifyTranslator);
// set this class instance to notify control object
if (SUCCEEDED(hr))
{
hr = cpNotify->InitSpNotifyCallback( (ISpNotifyCallback *)this, 0, 0 );
}
if (SUCCEEDED(hr))
{
hr = m_cpRecoCtxt->SetNotifySink(cpNotify);
}
// set the events we're interested in
if( SUCCEEDED( hr ) )
{
const ULONGLONG ulInterest = SPFEI(SPEI_RECOGNITION);
hr = m_cpRecoCtxt->SetInterest(ulInterest, ulInterest);
}
else
{
m_cpRecoCtxt.Release();
}
if( SUCCEEDED( hr ) )
{
hr = _LoadGrammars();
}
return hr;
#endif // _WIN64
}
//
// _LoadGrammars
//
// synopsis - load CFG for dictation and commands available during dictation
//
HRESULT CSpTask::_LoadGrammars()
{
// do not initialize grammars more than once
//
if (m_cpDictGrammar || m_cpCmdGrammar)
return S_OK;
HRESULT hr = E_FAIL;
if (m_cpRecoCtxt)
{
//
// create grammar object
//
if ( m_langid != 0x0804 ) // Chinese Engine doesn't support spelling grammar.
{
hr = m_cpRecoCtxt->CreateGrammar(GRAM_ID_DICT, &m_cpDictGrammar);
if (S_OK == hr)
{
// specify spelling mode
hr = m_cpDictGrammar->LoadDictation(L"Spelling", SPLO_STATIC);
}
if (SUCCEEDED(hr))
{
hr = m_cpRecoCtxt->CreateGrammar(GRAM_ID_CANDCC, &m_cpCmdGrammar);
}
}
else
hr = m_cpRecoCtxt->CreateGrammar(GRAM_ID_CANDCC, &m_cpCmdGrammar);
// load the command grammar
//
if (SUCCEEDED(hr) )
{
// Load it from the resource first to speed up the initialization.
if (m_langid == 0x409 || // English
m_langid == 0x411 || // Japanese
m_langid == 0x804 ) // Simplified Chinese
{
hr = m_cpCmdGrammar->LoadCmdFromResource(
g_hInst,
(const WCHAR*)MAKEINTRESOURCE(ID_DICTATION_COMMAND_CFG),
L"SRGRAMMAR",
m_langid,
SPLO_DYNAMIC);
}
// in case LoadCmdFromResource returns wrong.
if (!SUCCEEDED(hr))
{
if(!_GetCmdFileName(m_langid))
{
hr = E_FAIL;
}
if (m_szCmdFile[0])
{
hr = m_cpCmdGrammar->LoadCmdFromFile(_GetCmdFileName(m_langid), SPLO_DYNAMIC);
}
if (!SUCCEEDED(hr))
{
m_cpCmdGrammar.Release();
}
}
hr = S_OK;
}
}
return hr;
}
void CSpTask::_ReleaseGrammars(void)
{
if (!m_fInCallback)
{
m_cpDictGrammar.Release();
m_cpCmdGrammar.Release();
if (m_cpRecoCtxt)
{
m_cpRecoCtxt->SetNotifySink(NULL);
m_cpRecoCtxt.Release();
}
}
}
WCHAR * CSpTask::_GetCmdFileName(LANGID langid)
{
if (!m_szCmdFile[0])
{
// now we only have a command file for English/Japanese
// when cfgs are available, we'll get the name of cmd file
// and the rule names from resources using findresourceex
//
if (PRIMARYLANGID(langid) == LANG_ENGLISH
|| PRIMARYLANGID(langid) == LANG_JAPANESE
|| PRIMARYLANGID(langid) == LANG_CHINESE)
{
char szFilePath[MAX_PATH];
char *pszExt;
char szCp[MAX_PATH];
int ilen;
if (!GetModuleFileName(g_hInst, szFilePath, ARRAYSIZE(szFilePath)))
return NULL;
// find extension
// is this dbcs safe?
pszExt = strrchr(szFilePath, (int)'.');
if (pszExt)
{
*pszExt = '\0';
}
ilen = lstrlen(szFilePath);
if (!pszExt)
{
pszExt = szFilePath+ilen;
}
LoadStringA(g_hInst, IDS_CMD_EXT, pszExt, ARRAYSIZE(szFilePath)-ilen);
if (GetLocaleInfo(langid, LOCALE_IDEFAULTANSICODEPAGE, szCp, ARRAYSIZE(szCp))>0)
{
int iACP = atoi(szCp);
if (MultiByteToWideChar(iACP, NULL, szFilePath, -1, m_szCmdFile, ARRAYSIZE(m_szCmdFile)) == 0) {
m_szCmdFile[0] = 0;
return NULL;
}
}
}
}
return m_szCmdFile;
}
HRESULT CSpTask::_Activate(BOOL fActive)
{
HRESULT hr = E_FAIL;
if (m_cpRecoCtxt)
{
// Need SAPI bug# for this workaround.
//
m_fActive = fActive;
//
// Is the NULL rulename fine?
//
if (m_cpCmdGrammar)
hr = m_cpCmdGrammar->SetRuleState(NULL, NULL, m_fActive ? SPRS_ACTIVE : SPRS_INACTIVE);
if (m_cpDictGrammar)
hr = m_cpDictGrammar->SetDictationState(m_fActive? SPRS_ACTIVE : SPRS_INACTIVE);
}
return hr;
}
HRESULT CSpTask::InitializeSpeech()
{
HRESULT hr = E_FAIL;
#ifdef _WIN64
hr = E_NOTIMPL;
#else
hr = InitializeSAPIObjects();
// set callback
if (hr == S_OK)
hr = InitializeCallback();
// activate grammars
if (hr == S_OK)
hr = _Activate(TRUE);
#endif // _WIN64
return hr;
}
//
// _GetSapilayrEngineInstance
//
//
//
HRESULT CSpTask::_GetSapilayrEngineInstance(ISpRecognizer **ppRecoEngine)
{
#ifdef _WIN64
return E_NOTIMPL;
#else
HRESULT hr = E_FAIL;
CComPtr<ITfFunctionProvider> cpFuncPrv;
CComPtr<ITfFnGetSAPIObject> cpGetSAPI;
// we shouldn't release this until we terminate ourselves
// so we don't use comptr here
if (m_pcui->_ptim != NULL) {
hr = m_pcui->_ptim->GetFunctionProvider(CLSID_SapiLayr, &cpFuncPrv);
if (S_OK == hr)
{
hr = cpFuncPrv->GetFunction(GUID_NULL, IID_ITfFnGetSAPIObject, (IUnknown **)&cpGetSAPI);
}
if (S_OK == hr)
{
hr = cpGetSAPI->Get(GETIF_RECOGNIZERNOINIT, (IUnknown **)ppRecoEngine);
}
}
return hr;
#endif
}