/*++ Copyright (c) 1985 - 1999, Microsoft Corporation Module Name: profile.cpp Abstract: This file implements the CActiveIMMProfiles Class. Author: Revision History: Notes: --*/ #include "private.h" #include "globals.h" #include "profile.h" #include "idebug.h" UINT WINAPI RawImmGetDescriptionA(HKL hkl, LPSTR lpstr, UINT uBufLen); // // Callbacks // HRESULT CAImeProfile::ActiveLanguageProfileNotifySinkCallback( REFGUID rguid, REFGUID rguidProfile, BOOL fActivated, void *pv ) { DebugMsg(TF_FUNC, "ActiveLanguageProfileNotifySinkCallback"); CAImeProfile* _this = (CAImeProfile*)pv; _this->ResetCache(); return S_OK; } // // Create instance // // entry point for msimtf.dll HRESULT CAImmProfile_CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObj) { return CAImeProfile::CreateInstance(pUnkOuter, riid, ppvObj); } /* static */ HRESULT CAImeProfile::CreateInstance( IUnknown *pUnkOuter, REFIID riid, void **ppvObj ) { IMTLS *ptls; DebugMsg(TF_FUNC, "CAImeProfile::CreateInstance called."); *ppvObj = NULL; if (pUnkOuter != NULL) { return CLASS_E_NOAGGREGATION; } ptls = IMTLS_GetOrAlloc(); if (ptls == NULL) return E_FAIL; if (ptls->pAImeProfile != NULL) { /* * CAImeProfile instance already have in a thread. */ return ptls->pAImeProfile->QueryInterface(riid, ppvObj); } else { /* * Create an new CAImeProfile instance. */ CAImeProfile* pImeProfile = new CAImeProfile; if (pImeProfile) { HRESULT hr = pImeProfile->QueryInterface(riid, ppvObj); if (SUCCEEDED(hr)) { hr = pImeProfile->InitProfileInstance(); if (hr != S_OK) { DebugMsg(TF_ERROR, "CAImeProfile::CreateInstance: Couldn't create tim!"); Assert(0); // couldn't create tim! } pImeProfile->Release(); } Assert(ptls->pAImeProfile == NULL); ptls->pAImeProfile = pImeProfile; // Set CAImeProfile instance in the TLS data. ptls->pAImeProfile->AddRef(); return hr; } } return E_OUTOFMEMORY; } // // Initialization, destruction and standard COM stuff // CAImeProfile::CAImeProfile( ) { DllAddRef(); m_ref = 1; m_profile = NULL; m_pActiveLanguageProfileNotifySink = NULL; m_SavedLangId = LANG_NEUTRAL; m_fActivateThread = FALSE; ResetCache(); m_cp = CP_ACP; m_LangID = LANG_NEUTRAL; m_hKL = 0; } CAImeProfile::~CAImeProfile() { if (m_profile) { if (m_SavedLangId != LANG_NEUTRAL) { HRESULT hr = m_profile->ChangeCurrentLanguage(m_SavedLangId); if (FAILED(hr)) { TraceMsg(TF_ERROR, "CAImeProfile::~CAImeProfile: failed for ChangeCurrentLanguage"); } } m_profile->Release(); m_profile = NULL; } if (m_pActiveLanguageProfileNotifySink) { m_pActiveLanguageProfileNotifySink->_Unadvise(); m_pActiveLanguageProfileNotifySink->Release(); m_pActiveLanguageProfileNotifySink = NULL; } DllRelease(); } HRESULT CAImeProfile::QueryInterface( REFIID riid, void **ppvObj ) { *ppvObj = NULL; if (IsEqualIID(riid, IID_IAImeProfile) || IsEqualIID(riid, IID_IUnknown)) { *ppvObj = static_cast(this); } if (*ppvObj) { AddRef(); return S_OK; } return E_NOINTERFACE; } ULONG CAImeProfile::AddRef( ) { return InterlockedIncrement(&m_ref); } ULONG CAImeProfile::Release( ) { ULONG cr = InterlockedDecrement(&m_ref); if (cr == 0) { delete this; } return cr; } HRESULT CAImeProfile::InitProfileInstance( ) { HRESULT hr; IMTLS *ptls; hr = TF_CreateInputProcessorProfiles(&m_profile); if (FAILED(hr)) { TraceMsg(TF_ERROR, "CAImeProfile::InitProfileInstance: failed for CoCreate"); } else if (m_pActiveLanguageProfileNotifySink == NULL) { m_pActiveLanguageProfileNotifySink = new CActiveLanguageProfileNotifySink(CAImeProfile::ActiveLanguageProfileNotifySinkCallback, this); if (m_pActiveLanguageProfileNotifySink == NULL) { DebugMsg(TF_ERROR, "Couldn't create ActiveLanguageProfileNotifySink!"); m_profile->Release(); m_profile = NULL; return E_FAIL; } if ((ptls = IMTLS_GetOrAlloc()) && ptls->tim != NULL) { m_pActiveLanguageProfileNotifySink->_Advise(ptls->tim); } } return hr; } HRESULT CAImeProfile::Activate( void ) { m_fActivateThread = TRUE; ResetCache(); return S_OK; } HRESULT CAImeProfile::Deactivate( void ) { m_fActivateThread = FALSE; return S_OK; } HRESULT CAImeProfile::ChangeCurrentKeyboardLayout( HKL hKL ) { HRESULT hr; LANGID CurrentLangId; hr = m_profile->GetCurrentLanguage(&CurrentLangId); if (FAILED(hr)) { TraceMsg(TF_ERROR, "CAImeProfile::ChangeCurrentKeyboardLayout: failed for GetCurrentLanguage"); } else if (hKL != NULL) { LANGID LangId = LangIdFromKL(hKL); if (LangId != CurrentLangId) { hr = m_profile->ChangeCurrentLanguage(LangId); if (FAILED(hr)) { m_SavedLangId = LANG_NEUTRAL; TraceMsg(TF_ERROR, "CAImeProfile::ChangeCurrentKeyboardLayout: failed for ChangeCurrentLanguage"); } m_SavedLangId = LangId; } } return hr; } HRESULT CAImeProfile::GetLangId( LANGID *plid ) { if (!m_profile) return E_FAIL; if (!plid) return E_INVALIDARG; HRESULT hr = S_OK; if (m_fInitLangID) { *plid = m_LangID; } else { *plid = LANG_NEUTRAL; hr = m_profile->GetCurrentLanguage(plid); if (FAILED(hr)) { TraceMsg(TF_ERROR, "CAImeProfile::GetLangId: failed for GetCurrentLanguage"); } else { m_LangID = *plid; m_fInitLangID = TRUE; } } return hr; } HRESULT CAImeProfile::GetCodePageA( UINT *puCodePage ) { if (!puCodePage) return E_INVALIDARG; if (m_fInitCP) { *puCodePage = m_cp; } else { *puCodePage = CP_ACP; LANGID langid; if (FAILED(GetLangId(&langid))) return E_FAIL; CHAR szCodePage[12]; int ret = GetLocaleInfo(MAKELCID(langid, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, szCodePage, sizeof(szCodePage)); if (ret) { szCodePage[ARRAYSIZE(szCodePage)-1] = '\0'; *puCodePage = strtoul(szCodePage, NULL, 10); m_cp = *puCodePage; m_fInitCP = TRUE; } } return S_OK; } #if 1 // // TEST CODE // #include "osver.h" extern HINSTANCE hIMM; // temporary: do not call IMM32 for now BOOL IsIMEHKL(HKL hkl) { return ((((DWORD)(UINT_PTR)hkl) & 0xf0000000) == 0xe0000000) ? TRUE : FALSE; } #endif HRESULT CAImeProfile::GetKeyboardLayout( HKL* phkl ) { if (! phkl) return E_INVALIDARG; *phkl = NULL; if (m_fInitHKL) { *phkl = m_hKL; } else if (! m_fActivateThread) { return E_FAIL; } else { LANGID langid; GUID guidProfile; HRESULT hr = m_profile->GetActiveLanguageProfile(GUID_TFCAT_TIP_KEYBOARD, &langid, &guidProfile); if (FAILED(hr)) return hr; // // Instead of (!IsEqualGUID(guidProfil, GUID_NULL)), we check // 2nd, 3r and 4th DWORD of guidProfile. Because // GetActivelanguageProfile(category guid) may return hKL in // guidProfile // if ((((unsigned long *) &guidProfile)[1] != 0) || (((unsigned long *) &guidProfile)[2] != 0) || (((unsigned long *) &guidProfile)[3] != 0)) { /* * Current keyboard layout is Cicero. */ m_hKL = (HKL)LongToHandle(langid); // Don't use ::GetKeyboardLayout(0); // Cicero awre doesn't case hKL. #if 1 // // check the dummy hkl // HKL fake_hKL = ::GetKeyboardLayout(0); if (IsIMEHKL(fake_hKL)) { // // fake hKL is IME hKL. // hIMM = GetSystemModuleHandle("imm32.dll"); if (hIMM != NULL) { char szDesc[256]; char szDumbDesc[256]; DWORD ret = RawImmGetDescriptionA(fake_hKL, szDesc, sizeof(szDesc)); if (ret != 0) { wsprintf(szDumbDesc, "hkl%04x", LOWORD((UINT_PTR)fake_hKL)); if (lstrcmp(szDumbDesc, szDesc) != 0) { // // fake hKL is regacy IME hKL. // if (IsOnNT()) { char szKLID[256]; wsprintf(szKLID, "%08x", LOWORD((UINT_PTR) m_hKL)); HKL win32_hKL = LoadKeyboardLayout(szKLID, KLF_NOTELLSHELL); } else { } } else { // // Dummy Cicero hKL for Win9x. // UINT n = GetKeyboardLayoutList(0, NULL); if (n) { HKL* phKL = new HKL [n]; if (phKL) { HKL* p = phKL; GetKeyboardLayoutList(n, phKL); while (n--) { if (IsIMEHKL(*p)) { ret = RawImmGetDescriptionA(*p, szDesc, sizeof(szDesc)); if (ret != 0) { wsprintf(szDumbDesc, "hkl%04x", LOWORD((UINT_PTR)*p)); if (lstrcmp(szDumbDesc, szDesc) == 0) { // // Dummy Cicero hKL for Win9x. // char szKLID[256]; wsprintf(szKLID, "%08x", LOWORD((UINT_PTR) *p)); HKL win32_hKL = LoadKeyboardLayout(szKLID, KLF_NOTELLSHELL); break; } } } p++; } delete [] phKL; } } } } FreeLibrary(hIMM); hIMM = NULL; } } #endif } else if (!IsEqualGUID(guidProfile, GUID_NULL)) { /* * Current keyboard layout is regacy IME. */ m_hKL = (HKL)LongToHandle(*(DWORD *)&guidProfile); } else { m_hKL = 0; } *phkl = m_hKL; m_fInitHKL = TRUE; } return S_OK; } HRESULT CAImeProfile::IsIME( HKL hKL ) { LANGID LangId = LangIdFromKL(hKL); Interface LanguageProfiles; HRESULT hr = m_profile->EnumLanguageProfiles(LangId, LanguageProfiles); if (FAILED(hr)) return S_FALSE; CEnumrateValue Enumrate(LanguageProfiles, LanguageProfilesCallback); ENUM_RET ret = Enumrate.DoEnumrate(); if (ret != ENUM_FIND) return S_FALSE; else return S_OK; } HRESULT CAImeProfile::GetActiveLanguageProfile( IN HKL hKL, IN GUID catid, OUT TF_LANGUAGEPROFILE* pLanguageProfile ) { LANGID LangId = LangIdFromKL(hKL); Interface LanguageProfiles; HRESULT hr = m_profile->EnumLanguageProfiles(LangId, LanguageProfiles); if (FAILED(hr)) return S_FALSE; LANG_PROF_ENUM_ARG LangProfEnumArg; LangProfEnumArg.catid = catid; CEnumrateValue Enumrate(LanguageProfiles, LanguageProfilesCallback, &LangProfEnumArg); ENUM_RET ret = Enumrate.DoEnumrate(); if (ret != ENUM_FIND || pLanguageProfile == NULL) return S_FALSE; else { *pLanguageProfile = LangProfEnumArg.LanguageProfile; return S_OK; } } ENUM_RET CAImeProfile::LanguageProfilesCallback( TF_LANGUAGEPROFILE LanguageProfile, LANG_PROF_ENUM_ARG* pLangProfEnumArg ) { if (LanguageProfile.fActive && ! IsEqualGUID(LanguageProfile.clsid, GUID_NULL)) { if (pLangProfEnumArg) { if (! IsEqualGUID(LanguageProfile.catid, pLangProfEnumArg->catid)) { return ENUM_CONTINUE; } pLangProfEnumArg->LanguageProfile = LanguageProfile; } return ENUM_FIND; } return ENUM_CONTINUE; }