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.
565 lines
14 KiB
565 lines
14 KiB
/*++
|
|
|
|
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<IAImeProfile*>(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<IEnumTfLanguageProfiles> LanguageProfiles;
|
|
HRESULT hr = m_profile->EnumLanguageProfiles(LangId,
|
|
LanguageProfiles);
|
|
if (FAILED(hr))
|
|
return S_FALSE;
|
|
|
|
CEnumrateValue<IEnumTfLanguageProfiles,
|
|
TF_LANGUAGEPROFILE,
|
|
LANG_PROF_ENUM_ARG> 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<IEnumTfLanguageProfiles> LanguageProfiles;
|
|
HRESULT hr = m_profile->EnumLanguageProfiles(LangId,
|
|
LanguageProfiles);
|
|
if (FAILED(hr))
|
|
return S_FALSE;
|
|
|
|
LANG_PROF_ENUM_ARG LangProfEnumArg;
|
|
LangProfEnumArg.catid = catid;
|
|
|
|
CEnumrateValue<IEnumTfLanguageProfiles,
|
|
TF_LANGUAGEPROFILE,
|
|
LANG_PROF_ENUM_ARG> 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;
|
|
}
|