// cutil.cpp // // file to put misc utility classes implementation // #include "private.h" #include "sapilayr.h" #include "sphelper.h" #include "xstring.h" #include "cregkey.h" #include "ctflbui.h" #include "nui.h" const GUID c_guidProfileBogus = { /* 09ea4e4b-46ce-4469-b450-0de76a435bbb */ 0x09ea4e4b, 0x46ce, 0x4469, {0xb4, 0x50, 0x0d, 0xe7, 0x6a, 0x43, 0x5b, 0xbb} }; /* a5239e24-2bcf-4915-9c5c-fd50c0f69db2 */ const CLSID CLSID_MSLBUI = { 0xa5239e24, 0x2bcf, 0x4915, {0x9c, 0x5c, 0xfd, 0x50, 0xc0, 0xf6, 0x9d, 0xb2} }; // const GUID c_guidProfile0 = { /* 55122b58-15bb-11d4-bd48-00105a2799b5 */ // 0x55122b58, // 0x15bb, // 0x11d4, // {0xbd, 0x48, 0x00, 0x10, 0x5a, 0x27, 0x99, 0xb5} // }; // const GUID c_guidProfile1 = { /* 55122b59-15bb-11d4-bd48-00105a2799b5 */ // 0x55122b59, // 0x15bb, // 0x11d4, // {0xbd, 0x48, 0x00, 0x10, 0x5a, 0x27, 0x99, 0xb5} // }; // const GUID c_guidProfile2 = { /* 55122b5a-15bb-11d4-bd48-00105a2799b5 */ // 0x55122b5a, // 0x15bb, // 0x11d4, // {0xbd, 0x48, 0x00, 0x10, 0x5a, 0x27, 0x99, 0xb5} // }; #ifndef USE_SAPI_FOR_LANGDETECTION static const char c_szSpeechRecognizersKey[] = "Software\\Microsoft\\Speech\\Recognizers"; static const char c_szSpeechRecognizersTokensKey[] = "Software\\Microsoft\\Speech\\Recognizers\\Tokens"; static const char c_szDefault[] = "DefaultTokenId"; static const char c_szAttribute[] = "Attributes"; static const char c_szLanguage[] = "Language"; static const char c_szUseSAPIForLang[] = "UseSAPIForLang"; #endif static const char c_szProfileRemoved[] = "ProfileRemoved"; static const char c_szProfileInitialized[] = "ProfileInitialized"; _inline BOOL _IsCompatibleLangid(LANGID langidReq, LANGID langidCmp) { if (PRIMARYLANGID(langidReq) == LANG_CHINESE) { return langidReq == langidCmp; } else { return PRIMARYLANGID(langidReq) == PRIMARYLANGID(langidCmp); } } void _RegisterOrUnRegisterMslbui(BOOL fRegister) { // we just assume the dll is copied to system32 TCHAR szMslbui[MAX_PATH]; int cch = GetSystemDirectory(szMslbui, ARRAYSIZE(szMslbui)); if (!cch) { return; } // GetSystemDirectory appends no '\' unless the system // directory is the root, such like "c:\" if (cch != 3) { StringCchCat(szMslbui, ARRAYSIZE(szMslbui), TEXT("\\")); } StringCchCat(szMslbui, ARRAYSIZE(szMslbui), TEXT("mslbui.dll")); if (fRegister) { // load mslbui.dll and register it TF_RegisterLangBarAddIn(CLSID_MSLBUI, AtoW(szMslbui), TF_RLBAI_CURRENTUSER | TF_RLBAI_ENABLE); } else { TF_UnregisterLangBarAddIn(CLSID_MSLBUI, TF_RLBAI_CURRENTUSER); } } //+--------------------------------------------------------------------------- // // dtor // // //---------------------------------------------------------------------------+ CLangProfileUtil::~CLangProfileUtil() { if (m_langidRecognizers.Count() > 0) m_langidRecognizers.Clear(); } //+--------------------------------------------------------------------------- // // _RegisterProfiles // // synopsis: a rough equivalent of RegisterTIP lib function, only different in // trying to cache the profile manager & the category manager // //---------------------------------------------------------------------------+ HRESULT CLangProfileUtil::_RegisterAProfile(HINSTANCE hInst, REFCLSID rclsid, const REGTIPLANGPROFILE *plp) { Assert(plp); HRESULT hr = S_OK; // ensure profile manager if (!m_cpProfileMgr) { hr = TF_CreateInputProcessorProfiles(&m_cpProfileMgr); } // register the clsid if (S_OK == hr) { hr = m_cpProfileMgr->Register(rclsid); } if (S_OK == hr) { WCHAR wszFilePath[MAX_PATH]; WCHAR *pv = &wszFilePath[0]; wszFilePath[0] = L'\0'; if (wcslen(plp->szIconFile)) { char szFilePath[MAX_PATH]; WCHAR *pvCur; ::GetModuleFileName(hInst, szFilePath, ARRAYSIZE(szFilePath)); StringCchCopyW(wszFilePath, ARRAYSIZE(wszFilePath), AtoW(szFilePath)); pv = pvCur = &wszFilePath[0]; while (*pvCur) { if (*pvCur == L'\\') pv = pvCur + 1; pvCur++; } *pv = L'\0'; } StringCchCatW(wszFilePath, ARRAYSIZE(wszFilePath), plp->szIconFile); hr = m_cpProfileMgr->AddLanguageProfile(rclsid, plp->langid, *plp->pguidProfile, plp->szProfile, wcslen(plp->szProfile), wszFilePath, wcslen(wszFilePath), plp->uIconIndex); } return hr; } //+--------------------------------------------------------------------------- // // RegisterActiveProfiles(void) // // synopsis // // // //---------------------------------------------------------------------------+ HRESULT CLangProfileUtil::RegisterActiveProfiles(void) { if (_fUserRemovedProfile()) { // remove mslbui when not one speech profile is enabled if (!_IsAnyProfileEnabled()) _RegisterOrUnRegisterMslbui(FALSE); return S_FALSE; } _SetUserInitializedProfile(); BOOL fEnabled; HRESULT hr = _EnsureProfiles(TRUE, &fEnabled); // if the speech TIP profile is correctly registered, // then we're OK to register the persist UI (mslbui.dll) // if (S_OK == hr && fEnabled) _RegisterOrUnRegisterMslbui(TRUE); return hr; } //+--------------------------------------------------------------------------- // // IsProfileAvailableForLang(LANGID langid, BOOL *pfAvailable) // // synopsis // // // //---------------------------------------------------------------------------+ HRESULT CLangProfileUtil::IsProfileAvailableForLang(LANGID langid, BOOL *pfAvailable) { if (pfAvailable) { *pfAvailable = _IsDictationEnabledForLang(langid); return S_OK; } else return E_INVALIDARG; } //+--------------------------------------------------------------------------- // // GetDisplayName(BSTR *pbstrName) // // synopsis // // //---------------------------------------------------------------------------+ HRESULT CLangProfileUtil::GetDisplayName(BSTR *pbstrName) { HRESULT hr = E_INVALIDARG; if (pbstrName) { *pbstrName = SysAllocString(L"Register Active profiles for SPTIP"); if (!*pbstrName) hr = E_OUTOFMEMORY; else hr = S_OK; } return hr; } HRESULT CLangProfileUtil::_EnsureProfiles(BOOL fRegister, BOOL *pfEnabled) { HRESULT hr = S_OK; if (pfEnabled) *pfEnabled = FALSE; if (fRegister) { m_langidRecognizers.Clear(); } if (!m_cpProfileMgr || fRegister) { if (!m_cpProfileMgr) { hr = TF_CreateInputProcessorProfiles(&m_cpProfileMgr); } if (fRegister) { // if this is a first time initialization, // obtain the list of all languages // if (S_OK == hr) { LANGID *pLangIds; ULONG ulCount; // plangid will be assigned cotaskmemalloc'd memory // hr = m_cpProfileMgr->GetLanguageList(&pLangIds, &ulCount); if (S_OK == hr) { for (UINT i = 0; i < ulCount; i++) { // here we register profiles // if SR engines are available // BOOL fEnable = FALSE; if (_IsDictationEnabledForLang(pLangIds[i])) { fEnable = TRUE; if (pfEnabled) *pfEnabled = TRUE; } hr = m_cpProfileMgr->EnableLanguageProfile( CLSID_SapiLayr, pLangIds[i], c_guidProfileBogus, fEnable); } // for CoTaskMemFree(pLangIds); } } } // fRegister } return hr; } BOOL CLangProfileUtil::_IsAnyProfileEnabled() { HRESULT hr = S_OK; if (!m_cpProfileMgr) { hr = TF_CreateInputProcessorProfiles(&m_cpProfileMgr); } LANGID *pLangIds; ULONG ulCount; BOOL fEnable = FALSE; if (S_OK == hr) { // // plangid will be assigned cotaskmemalloc'd memory // hr = m_cpProfileMgr->GetLanguageList(&pLangIds, &ulCount); } if (S_OK == hr) { for (UINT i = 0; i < ulCount; i++) { hr = m_cpProfileMgr->IsEnabledLanguageProfile(CLSID_SapiLayr, pLangIds[i], c_guidProfileBogus, &fEnable); if (S_OK == hr && fEnable) break; } CoTaskMemFree(pLangIds); } return fEnable; } //+--------------------------------------------------------------------------- // // _GetProfileLangID // // synopsis: handle language profiles // //---------------------------------------------------------------------------+ HRESULT CLangProfileUtil::_GetProfileLangID(LANGID *plangid) { HRESULT hr = S_OK; Assert(plangid); hr = _EnsureProfiles(FALSE); if (hr == S_OK) { hr = m_cpProfileMgr->GetCurrentLanguage(plangid); } return hr; } //+--------------------------------------------------------------------------- // // _DictationEnabled // // synopsis: // //---------------------------------------------------------------------------+ BOOL CLangProfileUtil::_DictationEnabled(LANGID *plangidRequested) { BOOL fret = FALSE; LANGID langidReq = (LANGID)-1; HRESULT hr = _GetProfileLangID(&langidReq); if (S_OK == hr) { if (plangidRequested) *plangidRequested = langidReq; fret = _IsDictationActiveForLang(langidReq); } return fret; } // // _IsDictationActiveForLang // // synopsis: see if the default SR engine is capable for // the specified language // BOOL CLangProfileUtil::_IsDictationActiveForLang(LANGID langidReq) { return _IsDictationEnabledForLang(langidReq, TRUE); } BOOL CLangProfileUtil::_IsDictationEnabledForLang(LANGID langidReq, BOOL fUseDefault) { // // try reg first and if it's not compatible try SAPI // BOOL fEnabled = FALSE; if (_fUseSAPIForLanguageDetection() == FALSE && ERROR_SUCCESS == _IsDictationEnabledForLangInReg(langidReq, fUseDefault, &fEnabled)) { return fEnabled; } return _IsDictationEnabledForLangSAPI(langidReq, fUseDefault); } BOOL CLangProfileUtil::_IsDictationEnabledForLangSAPI(LANGID langidReq, BOOL fUseDefault) { BOOL fEnabled = FALSE; WCHAR * pszDefaultTokenId = NULL; HRESULT hr = S_OK; if (fUseDefault) { if (langidReq == m_langidDefault) return TRUE; SpGetDefaultTokenIdFromCategoryId(SPCAT_RECOGNIZERS, &pszDefaultTokenId); } CComPtr cpEnum; if (S_OK == hr) { char szLang[MAX_PATH]; WCHAR wsz[MAX_PATH]; StringCchPrintfA(szLang, ARRAYSIZE(szLang), "Language=%x", langidReq); MultiByteToWideChar(CP_ACP, NULL, szLang, -1, wsz, ARRAYSIZE(wsz)); hr = SpEnumTokens(SPCAT_RECOGNIZERS, wsz, NULL, &cpEnum); } while (!fEnabled && S_OK == hr) { CComPtr cpToken; WCHAR * pszTokenId = NULL; hr = cpEnum->Next(1, &cpToken, NULL); if (S_OK == hr) { hr = cpToken->GetId(&pszTokenId); } if (S_OK == hr) { Assert(!fUseDefault || pszDefaultTokenId); if (!fUseDefault || wcscmp(pszDefaultTokenId, pszTokenId) == 0) fEnabled = TRUE; } if (pszTokenId) { CoTaskMemFree(pszTokenId); } } if (pszDefaultTokenId) { CoTaskMemFree(pszDefaultTokenId); } if (fUseDefault && fEnabled) { m_langidDefault = langidReq; } return fEnabled; } const TCHAR c_szDefaultDefaultToken[] = TEXT("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Recognizers\\Tokens\\MSASREnglish"); const TCHAR c_szDefaultDefaultTokenJpn[] = TEXT("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Recognizers\\Tokens\\MSASRJapanese"); const TCHAR c_szDefaultDefaultTokenChs[] = TEXT("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Recognizers\\Tokens\\MSASRChinese"); LONG CLangProfileUtil::_IsDictationEnabledForLangInReg(LANGID langidReq, BOOL fUseDefault, BOOL *pfEnabled) { LONG lret = ERROR_SUCCESS; // // fUseDefault == TRUE, just see if the current default recognizer // matches with the requested langid // if (fUseDefault) { if( m_langidDefault == 0xFFFF) { char szRegkeyDefaultToken[MAX_PATH]; CMyRegKey regkey; lret = regkey.Open(HKEY_CURRENT_USER, c_szSpeechRecognizersKey, KEY_READ); if (ERROR_SUCCESS == lret) { // first obtain the regkey to look at for default token lret = regkey.QueryValueCch(szRegkeyDefaultToken, c_szDefault, ARRAYSIZE(szRegkeyDefaultToken)); regkey.Close(); } else { if (PRIMARYLANGID(langidReq) == LANG_JAPANESE) { StringCchCopy(szRegkeyDefaultToken, ARRAYSIZE(szRegkeyDefaultToken), c_szDefaultDefaultTokenJpn); } else if (langidReq == 0x804) // CHS { StringCchCopy(szRegkeyDefaultToken, ARRAYSIZE(szRegkeyDefaultToken), c_szDefaultDefaultTokenChs); } else { StringCchCopy(szRegkeyDefaultToken, ARRAYSIZE(szRegkeyDefaultToken), c_szDefaultDefaultToken); } lret = ERROR_SUCCESS; } // then get the attribute / language if (ERROR_SUCCESS == lret) { char *psz = szRegkeyDefaultToken; // // eliminate "KKEY_LOCAL_MACHINE" // while(*psz && *psz != '\\') psz++; if (*psz == '\\') { psz++; // // open speech/recognizers/tokens key // lret = regkey.Open(HKEY_LOCAL_MACHINE, psz, KEY_READ); } else m_langidDefault = 0x0000; } if (ERROR_SUCCESS == lret) { m_langidDefault = _GetLangIdFromRecognizerToken(regkey.m_hKey); } } *pfEnabled = _IsCompatibleLangid(langidReq, m_langidDefault); return lret; } // // this is fUseDefault == FALSE case. We want to see // if any installed recognizer can satisfy the langid requested. // if (m_langidRecognizers.Count() == 0) { CMyRegKey regkey; char szRecognizerName[MAX_PATH]; lret = regkey.Open(HKEY_LOCAL_MACHINE, c_szSpeechRecognizersTokensKey, KEY_READ); if(ERROR_SUCCESS == lret) { CMyRegKey regkeyReco; DWORD dwIndex = 0; while (ERROR_SUCCESS == regkey.EnumKey(dwIndex, szRecognizerName, ARRAYSIZE(szRecognizerName))) { lret = regkeyReco.Open(regkey.m_hKey, szRecognizerName, KEY_READ); if (ERROR_SUCCESS == lret) { LANGID langid=_GetLangIdFromRecognizerToken(regkeyReco.m_hKey); if (langid) { LANGID *pl = m_langidRecognizers.Append(1); if (pl) *pl = langid; } regkeyReco.Close(); } dwIndex++; } } } BOOL fEnabled = FALSE; for (int i = 0 ; i < m_langidRecognizers.Count(); i++) { LANGID *p= m_langidRecognizers.GetPtr(i); if (p) { if (_IsCompatibleLangid(langidReq, *p)) { fEnabled = TRUE; break; } } } *pfEnabled = fEnabled; return lret; } LANGID CLangProfileUtil::_GetLangIdFromRecognizerToken(HKEY hkeyToken) { LANGID langid = 0; char szLang[MAX_PATH]; CMyRegKey regkeyAttr; LONG lret = regkeyAttr.Open(hkeyToken, c_szAttribute, KEY_READ); if (ERROR_SUCCESS == lret) { lret = regkeyAttr.QueryValueCch(szLang, c_szLanguage, ARRAYSIZE(szLang)); } if (ERROR_SUCCESS == lret) { char *psz = szLang; while(*psz && *psz != ';') { langid = langid << 4; if (*psz >= 'a' && *psz <= 'f') { *psz -= ('a' - 'A'); } if (*psz >= 'A' && *psz <= 'F') { langid += *psz - 'A' + 10; } else if (*psz >= '0' && *psz <= '9') { langid += *psz - '0'; } psz++; } } return langid; } BOOL CLangProfileUtil::_fUseSAPIForLanguageDetection(void) { if (m_uiUseSAPIForLangDetection == 0) { CMyRegKey regkey; if (ERROR_SUCCESS == regkey.Open(HKEY_LOCAL_MACHINE, c_szSapilayrKey, KEY_READ)) { DWORD dw; if (ERROR_SUCCESS==regkey.QueryValue(dw, c_szUseSAPIForLang)) { m_uiUseSAPIForLangDetection = dw; } } if (m_uiUseSAPIForLangDetection == 0) { m_uiUseSAPIForLangDetection = 1; } } return m_uiUseSAPIForLangDetection == 2 ? TRUE : FALSE; } BOOL CLangProfileUtil::_fUserRemovedProfile(void) { BOOL bret = FALSE; CMyRegKey regkey; if (ERROR_SUCCESS == regkey.Open(HKEY_CURRENT_USER, c_szSapilayrKey, KEY_READ)) { DWORD dw; if (ERROR_SUCCESS==regkey.QueryValue(dw, c_szProfileRemoved)) { bret = dw > 0 ? TRUE : FALSE; } } return bret; } BOOL CLangProfileUtil::_fUserInitializedProfile(void) { BOOL bret = FALSE; CMyRegKey regkey; if (ERROR_SUCCESS == regkey.Open(HKEY_CURRENT_USER, c_szSapilayrKey, KEY_READ)) { DWORD dw; if (ERROR_SUCCESS==regkey.QueryValue(dw, c_szProfileInitialized)) { bret = dw > 0 ? TRUE : FALSE; } } return bret; } BOOL CLangProfileUtil::_SetUserInitializedProfile(void) { CMyRegKey regkey; if (ERROR_SUCCESS == regkey.Create(HKEY_CURRENT_USER, c_szSapilayrKey)) { DWORD dw = 0x0001; if (ERROR_SUCCESS==regkey.SetValue(dw, c_szProfileInitialized)) { return TRUE; } } return FALSE; }