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.
2406 lines
69 KiB
2406 lines
69 KiB
/*++
|
|
|
|
Copyright (c) 2001, Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cic.cpp
|
|
|
|
Abstract:
|
|
|
|
This file implements the CicBridge Class.
|
|
|
|
Author:
|
|
|
|
Revision History:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include "private.h"
|
|
#include "globals.h"
|
|
#include "template.h"
|
|
#include "cic.h"
|
|
#include "context.h"
|
|
#include "profile.h"
|
|
#include "funcprv.h"
|
|
#include "korimx.h"
|
|
#include "delay.h"
|
|
#include "tls.h"
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::IUnknown::QueryInterface
|
|
// CicBridge::IUnknown::AddRef
|
|
// CicBridge::IUnknown::Release
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::QueryInterface(
|
|
REFIID riid,
|
|
void** ppvObj)
|
|
{
|
|
*ppvObj = NULL;
|
|
|
|
if (IsEqualIID(riid, IID_ITfSysHookSink))
|
|
{
|
|
*ppvObj = static_cast<ITfSysHookSink*>(this);
|
|
}
|
|
if (*ppvObj) {
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG
|
|
CicBridge::AddRef(
|
|
)
|
|
{
|
|
return InterlockedIncrement(&m_ref);
|
|
}
|
|
|
|
ULONG
|
|
CicBridge::Release(
|
|
)
|
|
{
|
|
ULONG cr = InterlockedDecrement(&m_ref);
|
|
|
|
if (cr == 0) {
|
|
delete this;
|
|
}
|
|
|
|
return cr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::ITfSysHookSink::OnPreFocusDIM
|
|
// CicBridge::ITfSysHookSink::OnSysShellProc
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::OnPreFocusDIM(
|
|
HWND hWnd)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CicBridge::OnSysShellProc(
|
|
int nCode,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::ITfSysHookSink::OnSysKeyboardProc
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
const DWORD TRANSMSGCOUNT = 256;
|
|
|
|
HRESULT
|
|
CicBridge::OnSysKeyboardProc(
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
TLS* ptls = TLS::GetTLS();
|
|
if (ptls == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::OnSysKeyboardProc. ptls==NULL."));
|
|
return S_FALSE;
|
|
}
|
|
|
|
ITfThreadMgr_P* ptim_P = ptls->GetTIM();
|
|
if (ptim_P == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::OnSysKeyboardProc. ptim_P==NULL"));
|
|
return S_FALSE;
|
|
}
|
|
|
|
BOOL fKeystrokeFeed;
|
|
if (FAILED(ptim_P->IsKeystrokeFeedEnabled(&fKeystrokeFeed)))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::OnSysKeyboardProc. IsKeystrokeFeedEnabled return error."));
|
|
return S_FALSE;
|
|
}
|
|
|
|
if (!fKeystrokeFeed)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
HWND hWnd = GetFocus();
|
|
if (hWnd != NULL)
|
|
{
|
|
Interface<ITfDocumentMgr> pdimAssoc;
|
|
|
|
ptim_P->GetFocus(pdimAssoc);
|
|
if ((ITfDocumentMgr*)pdimAssoc) {
|
|
//
|
|
// Check if it is our dim or app dim.
|
|
//
|
|
if (IsOwnDim((ITfDocumentMgr*)pdimAssoc))
|
|
{
|
|
//
|
|
// Call ImmGetAppCompatFlags with NULL to get the global app compat flag.
|
|
//
|
|
DWORD dwImeCompatFlags = ImmGetAppCompatFlags(NULL);
|
|
if (dwImeCompatFlags & (IMECOMPAT_AIMM12 | IMECOMPAT_AIMM_LEGACY_CLSID | IMECOMPAT_AIMM12_TRIDENT))
|
|
{
|
|
//
|
|
// AIMM aware apps.
|
|
//
|
|
HIMC hIMC = ImmGetContext(hWnd);
|
|
if (hIMC == NULL)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
#if 0
|
|
IMCLock imc(hIMC);
|
|
if (FAILED(imc.GetResult()))
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(imc_ctfime.GetResult()))
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
if (DefaultKeyHandling(ptls, imc, imc_ctfime->m_pCicContext, (UINT)wParam), lParam)
|
|
{
|
|
return S_OK;
|
|
}
|
|
#else
|
|
BYTE abKbdState[256];
|
|
|
|
if (!GetKeyboardState(abKbdState))
|
|
return S_FALSE;
|
|
|
|
DWORD fdwProperty = ImmGetProperty(GetKeyboardLayout(0), IGP_PROPERTY);
|
|
|
|
if ((HIWORD(lParam) & KF_MENUMODE) ||
|
|
((HIWORD(lParam) & KF_UP) && (fdwProperty & IME_PROP_IGNORE_UPKEYS)) ||
|
|
((HIWORD(lParam) & KF_ALTDOWN) && !(fdwProperty & IME_PROP_NEED_ALTKEY)))
|
|
return S_FALSE;
|
|
|
|
HRESULT hr;
|
|
|
|
hr = ProcessKey(ptls, ptim_P, hIMC, (UINT)wParam, lParam, abKbdState) ? S_OK : S_FALSE;
|
|
if (hr == S_OK)
|
|
{
|
|
UINT uVirKey = (UINT)wParam & 0xffff;
|
|
INT iNum;
|
|
|
|
if (fdwProperty & IME_PROP_KBD_CHAR_FIRST)
|
|
{
|
|
if (fdwProperty & IME_PROP_UNICODE)
|
|
{
|
|
WCHAR wc;
|
|
|
|
iNum = ToUnicode(uVirKey, // virtual-key code
|
|
HIWORD(lParam), // scan code
|
|
abKbdState, // key-state array
|
|
&wc, // translated key buffer
|
|
1, // size
|
|
0); // function option
|
|
if (iNum == 1)
|
|
{
|
|
//
|
|
// hi word : unicode character code
|
|
// hi byte of lo word : zero
|
|
// lo byte of lo word : virtual key
|
|
//
|
|
uVirKey = (uVirKey & 0x00ff) | ((UINT)wc << 16);
|
|
}
|
|
}
|
|
else
|
|
Assert(0); // should have IME_PROP_UNICODE
|
|
}
|
|
|
|
DWORD dwSize = FIELD_OFFSET(TRANSMSGLIST, TransMsg)
|
|
+ TRANSMSGCOUNT * sizeof(TRANSMSG);
|
|
|
|
LPTRANSMSGLIST lpTransMsgList = (LPTRANSMSGLIST) new BYTE[dwSize];
|
|
if (lpTransMsgList == NULL)
|
|
return S_FALSE;
|
|
|
|
lpTransMsgList->uMsgCount = TRANSMSGCOUNT;
|
|
|
|
hr = ToAsciiEx(ptls, ptim_P, uVirKey, HIWORD(lParam), abKbdState, lpTransMsgList, 0, hIMC, (UINT *) &iNum);
|
|
if (iNum > TRANSMSGCOUNT)
|
|
{
|
|
//
|
|
// The message buffer is not big enough. IME put messages
|
|
// into hMsgBuf in the input context.
|
|
//
|
|
IMCLock imc(hIMC);
|
|
if (FAILED(imc.GetResult()))
|
|
{
|
|
delete [] lpTransMsgList;
|
|
return S_FALSE;
|
|
}
|
|
|
|
IMCCLock<TRANSMSG> pdw(imc->hMsgBuf);
|
|
if (FAILED(pdw.GetResult()))
|
|
{
|
|
delete [] lpTransMsgList;
|
|
return S_FALSE;
|
|
}
|
|
|
|
PostTransMsg(GetFocus(), iNum, pdw);
|
|
}
|
|
else if (iNum > 0)
|
|
{
|
|
IMCLock imc(hIMC);
|
|
if (FAILED(imc.GetResult()))
|
|
{
|
|
delete [] lpTransMsgList;
|
|
return S_FALSE;
|
|
}
|
|
|
|
PostTransMsg(GetFocus(), iNum, &lpTransMsgList->TransMsg[0]);
|
|
}
|
|
|
|
delete [] lpTransMsgList;
|
|
}
|
|
|
|
return hr;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::InitIMMX
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::InitIMMX(
|
|
TLS* ptls)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::InitIMMX entered."));
|
|
|
|
if (m_fCicInit.IsSetFlag())
|
|
return S_OK;
|
|
|
|
//
|
|
// Create ITfThreadMgr instance.
|
|
//
|
|
HRESULT hr;
|
|
|
|
if (ptls->GetTIM() == NULL)
|
|
{
|
|
ITfThreadMgr* ptim;
|
|
ITfThreadMgr_P* ptim_P;
|
|
|
|
//
|
|
// ITfThreadMgr is per thread instance.
|
|
//
|
|
hr = TF_CreateThreadMgr(&ptim);
|
|
if (hr != S_OK)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::InitIMMX. TF_CreateThreadMgr==NULL"));
|
|
Assert(0); // couldn't create tim!
|
|
goto ExitError;
|
|
}
|
|
|
|
hr = ptim->QueryInterface(IID_ITfThreadMgr_P, (void **)&ptim_P);
|
|
ptim->Release();
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::InitIMMX. IID_ITfThreadMgr_P==NULL"));
|
|
Assert(0); // couldn't find ITfThreadMgr_P
|
|
goto ExitError;
|
|
}
|
|
Assert(ptls->GetTIM() == NULL);
|
|
ptls->SetTIM(ptim_P); // Set ITfThreadMgr instance in the TLS data.
|
|
|
|
//
|
|
// Create Thread Manager Event Sink Callback for detect Cicero Aware Apps.
|
|
//
|
|
if (m_pDIMCallback == NULL) {
|
|
m_pDIMCallback = new CThreadMgrEventSink_DIMCallBack();
|
|
if (m_pDIMCallback == NULL) {
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::InitIMMX. CThreadMgrEventSink_DIMCallBack==NULL"));
|
|
Assert(0); // couldn't create CThreadMgrEventSink_DIMCallBack
|
|
goto ExitError;
|
|
}
|
|
m_pDIMCallback->SetCallbackDataPointer(m_pDIMCallback);
|
|
m_pDIMCallback->_Advise(ptim_P);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create CicProfile instance.
|
|
//
|
|
if (ptls->GetCicProfile() == NULL)
|
|
{
|
|
//
|
|
// ITfInputProcessorProfiles is per thread instance.
|
|
//
|
|
CicProfile* pProfile = new CicProfile;
|
|
if (pProfile == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::InitIMMX. pProfile==NULL"));
|
|
Assert(0); // couldn't create profile
|
|
goto ExitError;
|
|
}
|
|
ptls->SetCicProfile(pProfile);
|
|
|
|
hr = pProfile->InitProfileInstance(ptls);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::InitIMMX. InitProfileInstance==NULL"));
|
|
Assert(0); // couldn't create profile
|
|
goto ExitError;
|
|
}
|
|
}
|
|
|
|
//
|
|
// get the keystroke manager ready
|
|
//
|
|
if (FAILED(::GetService(ptls->GetTIM(), IID_ITfKeystrokeMgr_P, (IUnknown **)&m_pkm_P))) {
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::InitIMMX. IID_ITfKeystrokeMgr==NULL"));
|
|
Assert(0); // couldn't get ksm!
|
|
goto ExitError;
|
|
}
|
|
|
|
// cleanup/error code assumes this is the last thing we do, doesn't call
|
|
// UninitDAL on error
|
|
if (FAILED(InitDisplayAttrbuteLib(&_libTLS)))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::InitIMMX. InitDisplayAttributeLib==NULL"));
|
|
Assert(0); // couldn't init lib!
|
|
goto ExitError;
|
|
}
|
|
|
|
m_fCicInit.SetFlag();
|
|
|
|
|
|
//
|
|
// Start Edit Subclasss.
|
|
//
|
|
// StartEditSubClass();
|
|
|
|
return S_OK;
|
|
|
|
ExitError:
|
|
UnInitIMMX(ptls);
|
|
return E_FAIL;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::UnInitIMMX
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CicBridge::UnInitIMMX(
|
|
TLS* ptls)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::UnInitIMMX"));
|
|
|
|
// clear the display lib
|
|
UninitDisplayAttrbuteLib(&_libTLS);
|
|
|
|
TFUninitLib_Thread(&_libTLS);
|
|
|
|
// clear the keystroke mgr
|
|
SafeReleaseClear(m_pkm_P);
|
|
|
|
// clear the profile
|
|
CicProfile* pProfile;
|
|
if ((pProfile=ptls->GetCicProfile()) != NULL)
|
|
{
|
|
pProfile->Release();
|
|
ptls->SetCicProfile(NULL);
|
|
}
|
|
|
|
// clear Thread Manager Event Sink Callback for detect Cicero Aware Apps.
|
|
if (m_pDIMCallback) {
|
|
m_pDIMCallback->_Unadvise();
|
|
m_pDIMCallback->Release();
|
|
m_pDIMCallback = NULL;
|
|
}
|
|
|
|
// clear the thread mgr
|
|
ITfThreadMgr_P* ptim_P;
|
|
if ((ptim_P=ptls->GetTIM()) != NULL)
|
|
{
|
|
SafeReleaseClear(ptim_P);
|
|
ptls->SetTIM(NULL);
|
|
}
|
|
|
|
m_fCicInit.ResetFlag();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::ActivateMMX
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::ActivateIMMX(
|
|
TLS *ptls,
|
|
ITfThreadMgr_P* ptim_P)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::ActivateIMMX"));
|
|
|
|
//
|
|
// Activate thread manager
|
|
//
|
|
Assert(m_tfClientId == TF_CLIENTID_NULL);
|
|
|
|
HRESULT hr;
|
|
hr = ptim_P->ActivateEx(&m_tfClientId, TF_TMAE_NOACTIVATETIP);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ActivateIMMX. ptim_P->Activate==NULL"));
|
|
Assert(0); // couldn't activate thread!
|
|
m_tfClientId = TF_CLIENTID_NULL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
m_lCicActive++;
|
|
|
|
|
|
if (m_lCicActive == 1)
|
|
{
|
|
Interface<ITfSourceSingle> SourceSingle;
|
|
hr = ptim_P->QueryInterface(IID_ITfSourceSingle, (void**)SourceSingle);
|
|
if (hr != S_OK)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ActivateIMMX. IID_ITfSourceSingle==NULL"));
|
|
Assert(0);
|
|
DeactivateIMMX(ptls, ptim_P);
|
|
return E_FAIL;
|
|
}
|
|
|
|
CFunctionProvider* pFunc = new CFunctionProvider(m_tfClientId);
|
|
if (pFunc == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ActivateIMMX. pFunc==NULL"));
|
|
Assert(0);
|
|
DeactivateIMMX(ptls, ptim_P);
|
|
return E_FAIL;
|
|
}
|
|
|
|
SourceSingle->AdviseSingleSink(m_tfClientId, IID_ITfFunctionProvider, (ITfFunctionProvider*)pFunc);
|
|
pFunc->Release();
|
|
|
|
if (m_dimEmpty == NULL)
|
|
{
|
|
hr = ptim_P->CreateDocumentMgr(&m_dimEmpty);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ActivateIMMX. m_dimEmpty==NULL"));
|
|
Assert(0);
|
|
DeactivateIMMX(ptls, ptim_P);
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// mark this is an owned dim.
|
|
//
|
|
SetCompartmentDWORD(m_tfClientId, m_dimEmpty,
|
|
GUID_COMPARTMENT_CTFIME_DIMFLAGS,
|
|
COMPDIMFLAG_OWNEDDIM, FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// set ITfSysHookSink
|
|
//
|
|
ptim_P->SetSysHookSink(this);
|
|
|
|
if (ptls->IsDeactivatedOnce())
|
|
{
|
|
ENUMIMC edimc;
|
|
edimc.ptls = ptls;
|
|
edimc._this = this;
|
|
ImmEnumInputContext(0,
|
|
EnumCreateInputContextCallback,
|
|
(LPARAM)&edimc);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::DeactivateMMX
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::DeactivateIMMX(
|
|
TLS *ptls,
|
|
ITfThreadMgr_P* ptim_P)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::DeactivateIMMX"));
|
|
|
|
if (m_fInDeactivate.IsSetFlag())
|
|
{
|
|
//
|
|
// Prevent recursive call of CicBridge::DeactivateIMMX().
|
|
// ptim_P->Deactivate() might call DestroyWindow() via some TIP's deactivation,
|
|
// then imm32 ! CtfImmLastEnabledWndDestroy will call and this functoin also call again.
|
|
// In this case, this function return S_FALSE. Caller won't call UninitIMMX.
|
|
//
|
|
return S_FALSE;
|
|
}
|
|
|
|
m_fInDeactivate.SetFlag();
|
|
|
|
// Deactivate thread manager.
|
|
if (m_tfClientId != TF_CLIENTID_NULL)
|
|
{
|
|
ENUMIMC edimc;
|
|
edimc.ptls = ptls;
|
|
edimc._this = this;
|
|
ImmEnumInputContext(0,
|
|
EnumDestroyInputContextCallback,
|
|
(LPARAM)&edimc);
|
|
ptls->SetDeactivatedOnce();
|
|
|
|
Interface<ITfSourceSingle> SourceSingle;
|
|
if (ptim_P->QueryInterface(IID_ITfSourceSingle, (void**)SourceSingle) == S_OK)
|
|
{
|
|
SourceSingle->UnadviseSingleSink(m_tfClientId, IID_ITfFunctionProvider);
|
|
}
|
|
|
|
m_tfClientId = TF_CLIENTID_NULL;
|
|
while (m_lCicActive)
|
|
{
|
|
m_lCicActive--;
|
|
ptim_P->Deactivate();
|
|
}
|
|
}
|
|
|
|
//
|
|
// clear empty dim
|
|
//
|
|
// Release DIM should after tim->Deactivate. #480603
|
|
//
|
|
// If msctf ! DLL_THREAD_DETACH already runs before this DeactivateIMMX via msctfime ! DLL_THREAD_DETACH (depended DLL_THREAD_DETACH calling order).
|
|
// then msctf ! SYSTHREAD is already released by msctf ! FreeSYSTHREAD.
|
|
//
|
|
// In this time, msctf lost TIM list in SYSTHREAD then CThreadInputMgr::*_GetThis() returns NULL.
|
|
// And below Release DIM, dtor CDocumentInputManager doesn't remove DIM object from tim->_rgdim array.
|
|
// If Release DIM is before tim->Deactivate, some TIM might access DIM by tim->_rgdim array. But it DIM already released.
|
|
//
|
|
SafeReleaseClear(m_dimEmpty);
|
|
|
|
|
|
//
|
|
// reset ITfSysHookSink
|
|
//
|
|
ptim_P->SetSysHookSink(NULL);
|
|
|
|
Assert(!m_lCicActive);
|
|
|
|
m_fInDeactivate.ResetFlag();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::CreateInputContext
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::CreateInputContext(
|
|
TLS* ptls,
|
|
HIMC hImc)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::CreateInputContext"));
|
|
|
|
HRESULT hr;
|
|
|
|
IMCLock imc(hImc);
|
|
if (FAILED(hr=imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::CreateInputContext. imc==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
if (imc->hCtfImeContext == NULL)
|
|
{
|
|
HIMCC h = ImmCreateIMCC(sizeof(CTFIMECONTEXT));
|
|
if (h == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::CreateInputContext. hCtfImeContext==NULL"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
imc->hCtfImeContext = h;
|
|
}
|
|
|
|
{
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::CreateInputContext. imc_ctfime==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
if (imc_ctfime->m_pCicContext)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
CicInputContext* _pCicContext = new CicInputContext(_GetClientId(), _GetLibTLS(), hImc);
|
|
if (_pCicContext == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::CreateInputContext. _pCicContext==NULL"));
|
|
hr = E_OUTOFMEMORY;
|
|
goto out_of_block;
|
|
}
|
|
|
|
ITfThreadMgr_P* ptim_P;
|
|
if ((ptim_P=ptls->GetTIM()) == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::CreateInputContext. ptim_P==NULL"));
|
|
_pCicContext->Release();
|
|
imc_ctfime->m_pCicContext = NULL;
|
|
hr = E_NOINTERFACE;
|
|
goto out_of_block;
|
|
}
|
|
|
|
imc_ctfime->m_pCicContext = _pCicContext;
|
|
|
|
hr = _pCicContext->CreateInputContext(ptim_P, imc);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::CreateInputContext. _pCicContext->CreateInputContext==NULL"));
|
|
_pCicContext->Release();
|
|
imc_ctfime->m_pCicContext = NULL;
|
|
goto out_of_block;
|
|
}
|
|
|
|
//
|
|
// If this himc is already activated, we need to associate now.
|
|
// IMM32 won't call ImmSetActiveContext().
|
|
//
|
|
if (imc->hWnd && (imc->hWnd == ::GetFocus()))
|
|
{
|
|
Interface_Attach<ITfDocumentMgr> dim(GetDocumentManager(imc_ctfime));
|
|
SetAssociate(ptls, imc->hWnd, ptim_P, dim.GetPtr());
|
|
}
|
|
}
|
|
} // dtor imc_ctfime
|
|
|
|
out_of_block:
|
|
if (FAILED(hr))
|
|
{
|
|
DestroyInputContext(ptls, hImc);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::DestroyInputContext
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::DestroyInputContext(
|
|
TLS* ptls,
|
|
HIMC hImc)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::DestroyInputContext"));
|
|
|
|
HRESULT hr;
|
|
|
|
IMCLock imc(hImc);
|
|
if (FAILED(hr=imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::DestroyInputContext. imc==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
{
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::DestroyInputContext. imc_ctfime==NULL"));
|
|
goto out_of_block;
|
|
}
|
|
|
|
//
|
|
// #548378
|
|
//
|
|
// stop resursion call of _pCicContext->DestroyInputContext().
|
|
if (imc_ctfime->m_fInDestroy)
|
|
{
|
|
hr = S_OK;
|
|
goto exit;
|
|
}
|
|
imc_ctfime->m_fInDestroy = TRUE;
|
|
|
|
// imc->m_pContext may be NULL if ITfThreadMgr::Activate has not been called
|
|
if (imc_ctfime->m_pCicContext == NULL)
|
|
goto out_of_block;
|
|
|
|
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
|
|
imc_ctfime->m_pCicContext = NULL;
|
|
|
|
hr = _pCicContext->DestroyInputContext();
|
|
|
|
_pCicContext->Release();
|
|
imc_ctfime->m_pCicContext = NULL;
|
|
|
|
} // dtor imc_ctfime
|
|
|
|
out_of_block:
|
|
if (imc->hCtfImeContext != NULL)
|
|
{
|
|
ImmDestroyIMCC(imc->hCtfImeContext);
|
|
imc->hCtfImeContext = NULL;
|
|
hr = S_OK;
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::SelectEx
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::SelectEx(
|
|
TLS* ptls,
|
|
ITfThreadMgr_P* ptim_P, // using private for RequestPostponedLock
|
|
HIMC hImc,
|
|
BOOL fSelect,
|
|
HKL hKL)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::SelectEx(hImc=%x, fSelect=%x, hKL=%x)"), hImc, fSelect, hKL);
|
|
|
|
HRESULT hr;
|
|
IMCLock imc(hImc);
|
|
if (FAILED(hr = imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::SelectEx. imc==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::SelectEx. imc_ctfime==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
#ifdef UNSELECTCHECK
|
|
if (_pAImeContext)
|
|
_pAImeContext->m_fSelected = (dwFlags & AIMMP_SE_SELECT) ? TRUE : FALSE;
|
|
#endif UNSELECTCHECK
|
|
|
|
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
|
|
|
|
if (_pCicContext)
|
|
_pCicContext->m_fSelectingInSelectEx.SetFlag();
|
|
|
|
if (fSelect)
|
|
{
|
|
|
|
if (_pCicContext)
|
|
_pCicContext->m_fOpenCandidateWindow.ResetFlag(); // TRUE: opening candidate list window.
|
|
|
|
//
|
|
// #501445
|
|
//
|
|
// If imc is open, update GUID_COMPARTMENT_KEYBOARD_OPENCLOSE.
|
|
//
|
|
if (imc->fOpen)
|
|
OnSetOpenStatus(ptim_P, imc, *_pCicContext);
|
|
|
|
}
|
|
else { // being unselected
|
|
|
|
Interface_Attach<ITfContext> ic(GetInputContext(imc_ctfime));
|
|
if (ic.Valid())
|
|
{
|
|
ptim_P->RequestPostponedLock(ic.GetPtr());
|
|
}
|
|
|
|
}
|
|
|
|
if (_pCicContext)
|
|
_pCicContext->m_fSelectingInSelectEx.ResetFlag();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::SetActiveContextAlways
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::SetActiveContextAlways(
|
|
TLS* ptls,
|
|
HIMC hImc,
|
|
BOOL fOn,
|
|
HWND hWnd,
|
|
HKL hKL)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::SetActiveContextEx(hImc=%x, fOn=%x, hWnd=%x)"), hImc, fOn, hWnd);
|
|
|
|
ITfThreadMgr_P* ptim_P = ptls->GetTIM();
|
|
if (ptim_P == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::SetActiveContextEx. ptim_P==NULL"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (fOn && hImc != NULL)
|
|
{
|
|
HRESULT hr;
|
|
IMCLock imc(hImc);
|
|
if (FAILED(hr = imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::SetActiveContextEx. imc==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::SetActiveContextEx. imc_ctfime==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
if (hImc == ImmGetContext(hWnd)) {
|
|
/*
|
|
* Selecting hIMC has been current active hIMC,
|
|
* then associate this DIM with the TIM.
|
|
*/
|
|
Interface_Attach<ITfDocumentMgr> dim(GetDocumentManager(imc_ctfime));
|
|
SetAssociate(ptls, imc->hWnd, ptim_P, dim.GetPtr());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// When focus killed, composition string should completed.
|
|
//
|
|
// This is just for non-EA keyboard layouts. For example, we don't
|
|
// have a specific way to finilize the composition string like
|
|
// we use Enter key on EA kayboard layout. So we need to have
|
|
// a service to finalize the composition string at focus change
|
|
// automatically. (This is similar to Korean behaviour.)
|
|
//
|
|
if (!fOn && hImc && !IS_EA_KBDLAYOUT(hKL))
|
|
{
|
|
HRESULT hr;
|
|
IMCLock imc(hImc);
|
|
if (FAILED(hr = imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::SetActiveContextEx. imc==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::SetActiveContextEx. imc_ctfime==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// #482346
|
|
//
|
|
// If we are updating compstr, we don't have to complete it.
|
|
// App change the focus druing it handles WM_IME_xxx messages.
|
|
//
|
|
if (imc_ctfime->m_pCicContext->m_fInCompComplete.IsResetFlag() &&
|
|
imc_ctfime->m_pCicContext->m_fInUpdateComposition.IsResetFlag())
|
|
ImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
|
|
|
|
}
|
|
|
|
//
|
|
// #501449
|
|
//
|
|
// When Win32k.sys generates IMS_DEACTIVATECONTEXT, it does not
|
|
// guarantee to generate IMS_ACTIVATECONTEXT. It always checks
|
|
// (pwndReceive == pti->pq->spwndFocus) in xxxSendFocusMessage().
|
|
//
|
|
if (!fOn && (::GetFocus() == hWnd) &&
|
|
hImc && (hImc == ImmGetContext(hWnd)))
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// this new focus change performance improvement breaks some
|
|
// assumption of IsRealIME() in AssociateContext in dimm\immapp.cpp.
|
|
// Associate NULL dim under IsPresent() window has not been the case
|
|
// AIMM1.2 handles. In fact, this breaks IE that calls
|
|
// AssociateContext on the focus window that is IsPresent().
|
|
//
|
|
#ifdef FOCUSCHANGE_PERFORMANCE
|
|
//
|
|
// set empty dim so no text store to simulate NULL-HIMC.
|
|
//
|
|
BOOL fUseEmptyDIM = FALSE;
|
|
ITfDocumentMgr *pdimPrev; // just to receive prev for now
|
|
if (SUCCEEDED(m_tim->GetFocus(&pdimPrev)) && pdimPrev)
|
|
{
|
|
fUseEmptyDIM = TRUE;
|
|
pdimPrev->Release();
|
|
|
|
}
|
|
|
|
SetAssociate(hWnd, fUseEmptyDIM ? m_dimEmpty : NULL);
|
|
#else
|
|
SetAssociate(ptls, hWnd, ptim_P, m_dimEmpty);
|
|
#endif
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::IsDefaultIMCDim
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CicBridge::IsDefaultIMCDim(ITfDocumentMgr *pdim)
|
|
{
|
|
HWND hDefImeWnd = ImmGetDefaultIMEWnd(NULL);
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Get the default hIMC of this thread.
|
|
//
|
|
// Assume none associate any hIMC to the default IME window.
|
|
//
|
|
IMCLock imc(ImmGetContext(hDefImeWnd));
|
|
if (FAILED(hr = imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::SetActiveContextEx. imc==NULL"));
|
|
return FALSE;
|
|
}
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::SetActiveContextEx. imc_ctfime==NULL"));
|
|
return FALSE;
|
|
}
|
|
|
|
Interface_Attach<ITfDocumentMgr> dim(GetDocumentManager(imc_ctfime));
|
|
|
|
if (dim.GetPtr() == pdim)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::SetAssociate
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CicBridge::SetAssociate(
|
|
TLS* ptls,
|
|
HWND hWnd,
|
|
ITfThreadMgr_P* ptim_P,
|
|
ITfDocumentMgr* pdim)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::SetAssociate"));
|
|
|
|
if (m_fOnSetAssociate.IsSetFlag()) {
|
|
/*
|
|
* Prevent reentrance call from m_tim->AssociateFocus.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
m_fOnSetAssociate.SetFlag();
|
|
|
|
if (::IsWindow(hWnd) && m_fCicInit.IsSetFlag()) {
|
|
ITfDocumentMgr *pdimPrev = NULL; // just to receive prev for now
|
|
ITfDocumentMgr *pdimAssoc = NULL;
|
|
BOOL fIsAssociated = FALSE;
|
|
|
|
ptim_P->GetAssociated(hWnd, &pdimAssoc);
|
|
if (pdimAssoc) {
|
|
//
|
|
// Check if it is our dim or app dim.
|
|
//
|
|
if (!IsOwnDim(pdimAssoc))
|
|
fIsAssociated = TRUE;
|
|
|
|
SafeReleaseClear(pdimAssoc);
|
|
}
|
|
|
|
//
|
|
// If an app dim is associated to hWnd, msctf.dll will do SetAssociate().
|
|
//
|
|
if (!fIsAssociated)
|
|
{
|
|
ptim_P->AssociateFocus(hWnd, pdim, &pdimPrev);
|
|
|
|
//
|
|
// #610113
|
|
//
|
|
// if pdimPrev is DIM for the default hIMC, we need to associate
|
|
// a window to the dim. If the dim is not associated to any
|
|
// window, Cicero thinks it is the dim for Cicero native app
|
|
// so it skips to do _SetFocus().
|
|
//
|
|
if (pdimPrev)
|
|
{
|
|
if (IsDefaultIMCDim(pdimPrev))
|
|
{
|
|
ITfDocumentMgr *pdimDefPrev = NULL;
|
|
HWND hDefImeWnd = ImmGetDefaultIMEWnd(NULL);
|
|
ptim_P->AssociateFocus(hDefImeWnd, pdimPrev, &pdimDefPrev);
|
|
if (pdimDefPrev)
|
|
pdimDefPrev->Release();
|
|
}
|
|
pdimPrev->Release();
|
|
}
|
|
|
|
//
|
|
// If pdim is the focus dim, we call CTFDetection() to check
|
|
// the focus change between AIMM12, Cicero controls.
|
|
//
|
|
Interface<ITfDocumentMgr> pdimFocus;
|
|
ptim_P->GetFocus(pdimFocus);
|
|
if ((ITfDocumentMgr *)pdimFocus == pdim)
|
|
CTFDetection(ptls, pdim);
|
|
}
|
|
|
|
}
|
|
|
|
m_fOnSetAssociate.ResetFlag();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::IsOwnDim
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CicBridge::IsOwnDim(ITfDocumentMgr *pdim)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwFlags;
|
|
|
|
hr = GetCompartmentDWORD(pdim, GUID_COMPARTMENT_CTFIME_DIMFLAGS,
|
|
&dwFlags, FALSE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
return (dwFlags & COMPDIMFLAG_OWNEDDIM) ? TRUE : FALSE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::ProcessKey
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CicBridge::ProcessKey(
|
|
TLS* ptls,
|
|
ITfThreadMgr_P* ptim_P, // using private for RequestPostponedLock
|
|
HIMC hIMC,
|
|
UINT uVirtKey,
|
|
LPARAM lParam,
|
|
CONST LPBYTE lpbKeyState)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::ProcessKey"));
|
|
|
|
BOOL fEaten;
|
|
BOOL fKeysEnabled;
|
|
HRESULT hr;
|
|
BOOL fRet;
|
|
|
|
#if 0
|
|
// has anyone disabled system key feeding?
|
|
if (ptim_P->IsKeystrokeFeedEnabled(&fKeysEnabled) == S_OK && !fKeysEnabled)
|
|
return FALSE;
|
|
#endif
|
|
|
|
if (uVirtKey == VK_PROCESSKEY)
|
|
{
|
|
LANGID langid;
|
|
CicProfile* _pProfile = ptls->GetCicProfile();
|
|
|
|
if (_pProfile == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ProcessKey. _pProfile==NULL."));
|
|
}
|
|
else
|
|
{
|
|
_pProfile->GetLangId(&langid);
|
|
|
|
if (PRIMARYLANGID(langid) == LANG_KOREAN)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = m_pkm_P->KeyDownUpEx(uVirtKey, lParam, (DWORD)TF_KEY_MSCTFIME | TF_KEY_TEST, &fEaten);
|
|
|
|
if (hr == S_OK && fEaten) {
|
|
return TRUE;
|
|
}
|
|
|
|
IMCLock imc(hIMC);
|
|
if (FAILED(hr=imc.GetResult()))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// m_fGeneratedEndComposition should be set only when m_fInProcessKey
|
|
// is set.
|
|
//
|
|
Assert(imc_ctfime->m_pCicContext->m_fGeneratedEndComposition.IsResetFlag());
|
|
imc_ctfime->m_pCicContext->m_fInProcessKey.SetFlag();
|
|
|
|
if (!fEaten)
|
|
{
|
|
if (imc_ctfime->m_pCicContext &&
|
|
ptim_P != NULL)
|
|
{
|
|
ptim_P->RequestPostponedLock(imc_ctfime->m_pCicContext->GetInputContext());
|
|
}
|
|
}
|
|
|
|
|
|
if ((HIWORD(lParam) & KF_UP) ||
|
|
(HIWORD(lParam) & KF_ALTDOWN)) {
|
|
fRet = FALSE;
|
|
}
|
|
else
|
|
fRet = DefaultKeyHandling(ptls, imc, imc_ctfime->m_pCicContext, uVirtKey, lParam);
|
|
|
|
imc_ctfime->m_pCicContext->m_fGeneratedEndComposition.ResetFlag();
|
|
imc_ctfime->m_pCicContext->m_fInProcessKey.ResetFlag();
|
|
|
|
return fRet;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::ToAsciiEx
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::ToAsciiEx(
|
|
TLS* ptls,
|
|
ITfThreadMgr_P* ptim_P, // using private for RequestPostponedLock
|
|
UINT uVirtKey,
|
|
UINT uScanCode,
|
|
CONST LPBYTE lpbKeyState,
|
|
LPTRANSMSGLIST lpTransBuf,
|
|
UINT fuState,
|
|
HIMC hIMC,
|
|
UINT *uNum)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::ToAsciiEx"));
|
|
|
|
BOOL fEaten;
|
|
HRESULT hr;
|
|
|
|
*uNum = 0;
|
|
|
|
Assert(ptim_P);
|
|
|
|
IMCLock imc(hIMC);
|
|
if (FAILED(hr=imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ToAsciiEx. imc==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ToAsciiEx. imc_ctfime==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
|
|
ASSERT(_pCicContext != NULL);
|
|
if (! _pCicContext)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ToAsciiEx. _pCicContext==NULL"));
|
|
return S_FALSE;
|
|
}
|
|
|
|
//
|
|
// Backup the m_fOpenCandidateWindow flag.
|
|
// If open the candidate list and press "Cancel" key, Kana TIP would want to
|
|
// close candidate UI window in the KeyDown() action.
|
|
// Candidate UI calss maybe call m_pdim->Pop() and this function notify to
|
|
// the ThreadMgrEventSinkCallback.
|
|
// Win32 layer advised this callback and toggled m_fOpenCandidateWindow flag.
|
|
// Win32 layer doesn't know candidate status after KeyDown() call.
|
|
//
|
|
BOOL fOpenCandidateWindow = _pCicContext->m_fOpenCandidateWindow.IsSetFlag();
|
|
|
|
//
|
|
// If candidate window were open, send IMN_CHANGECANDIDATE message.
|
|
// In the case of PPT's centering composition string, it expect IMN_CHANGECANDIDATE.
|
|
//
|
|
if (fOpenCandidateWindow &&
|
|
*uNum < lpTransBuf->uMsgCount) {
|
|
TRANSMSG* pTransMsg = &lpTransBuf->TransMsg[*uNum];
|
|
pTransMsg->message = WM_IME_NOTIFY;
|
|
pTransMsg->wParam = IMN_CHANGECANDIDATE;
|
|
pTransMsg->lParam = 1; // bit 0 to first candidate list.
|
|
(*uNum)++;
|
|
}
|
|
|
|
//
|
|
// AIMM put char code in hiword. So we need to bail it out.
|
|
//
|
|
// if we don't need charcode, we may want to
|
|
// remove IME_PROP_KBD_CHAR_FIRST.
|
|
//
|
|
uVirtKey = uVirtKey & 0xffff;
|
|
|
|
if (uVirtKey == VK_PROCESSKEY)
|
|
{
|
|
/*
|
|
* KOREAN:
|
|
* Finalize current composition string
|
|
*/
|
|
LANGID langid;
|
|
CicProfile* _pProfile = ptls->GetCicProfile();
|
|
if (_pProfile == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ToAsciiEx. _pProfile==NULL."));
|
|
}
|
|
else
|
|
{
|
|
_pProfile->GetLangId(&langid);
|
|
|
|
if (PRIMARYLANGID(langid) == LANG_KOREAN)
|
|
{
|
|
//
|
|
// Composition complete.
|
|
//
|
|
_pCicContext->EscbCompComplete(imc);
|
|
|
|
//
|
|
// #506324
|
|
//
|
|
// we don't want to eat this VK_PROCESSKEY. So we don't
|
|
// stop generating VK_LBUTTONDOWN.
|
|
// Because we don't generate any message here, it is ok
|
|
// to return S_FALSE;
|
|
//
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
Interface<ITfContext_P> icp;
|
|
hr = _pCicContext->GetInputContext()->QueryInterface(IID_ITfContext_P,
|
|
(void **)icp);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ToAsciiEx. QueryInterface failed"));
|
|
return hr;
|
|
}
|
|
|
|
imc_ctfime->m_pCicContext->m_fInToAsciiEx.SetFlag();
|
|
|
|
//
|
|
// stop posting LockRequest message and we call RequestPostponedLock
|
|
// forcefully so we don't have to have unnecessary PostThreadMessage().
|
|
//
|
|
// some application detect the unknown message in the queue and
|
|
// do much
|
|
//
|
|
icp->EnableLockRequestPosting(FALSE);
|
|
|
|
//
|
|
// consider: dimm12 set high bit oflower WORD at keyup.
|
|
//
|
|
hr = m_pkm_P->KeyDownUpEx(uVirtKey, (uScanCode << 16), TF_KEY_MSCTFIME, &fEaten);
|
|
|
|
icp->EnableLockRequestPosting(TRUE);
|
|
|
|
//
|
|
// enpty the edit session queue of the ic.
|
|
//
|
|
ptim_P->RequestPostponedLock(icp);
|
|
|
|
imc_ctfime->m_pCicContext->m_fInToAsciiEx.ResetFlag();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::ProcessCicHotkey
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CicBridge::ProcessCicHotkey(
|
|
TLS* ptls,
|
|
ITfThreadMgr_P* ptim_P, // using private for RequestPostponedLock
|
|
HIMC hIMC,
|
|
UINT uVirtKey,
|
|
LPARAM lParam)
|
|
{
|
|
if (!CtfImmIsCiceroStartedInThread()) {
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ProcessCicHotkey. StopImm32HotkeyHandler returns Error."));
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT hr;
|
|
BOOL bHandled;
|
|
|
|
hr = ptim_P->CallImm32HotkeyHanlder((WPARAM)uVirtKey, lParam, &bHandled);
|
|
|
|
if (FAILED(hr)) {
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ProcessCicHotkey. CallImm32HotkeyHandler returns Error."));
|
|
return FALSE;
|
|
}
|
|
|
|
return bHandled;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::Notify
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::Notify(
|
|
TLS* ptls,
|
|
ITfThreadMgr_P* ptim_P,
|
|
HIMC hIMC,
|
|
DWORD dwAction,
|
|
DWORD dwIndex,
|
|
DWORD dwValue)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::Notify(hIMC=%x, dwAction=%x, dwIndex=%x, dwValue=%x)"), hIMC, dwAction, dwIndex, dwValue);
|
|
|
|
HRESULT hr;
|
|
IMCLock imc(hIMC);
|
|
if (FAILED(hr=imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::Notify. imc==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::Notify. imc_ctfime==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
|
|
if (_pCicContext == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::Notify. _pCicContext==NULL."));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LANGID langid;
|
|
CicProfile* _pProfile = ptls->GetCicProfile();
|
|
if (_pProfile == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::Notify. _pProfile==NULL."));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
_pProfile->GetLangId(&langid);
|
|
|
|
switch (dwAction) {
|
|
|
|
case NI_CONTEXTUPDATED:
|
|
switch (dwValue) {
|
|
case IMC_SETOPENSTATUS:
|
|
return OnSetOpenStatus(ptim_P, imc, *_pCicContext);
|
|
|
|
case IMC_SETCONVERSIONMODE:
|
|
case IMC_SETSENTENCEMODE:
|
|
return OnSetConversionSentenceMode(ptim_P, imc, *_pCicContext, dwValue, langid);
|
|
|
|
case IMC_SETCOMPOSITIONWINDOW:
|
|
case IMC_SETCOMPOSITIONFONT:
|
|
return E_NOTIMPL;
|
|
|
|
case IMC_SETCANDIDATEPOS:
|
|
return _pCicContext->OnSetCandidatePos(ptls, imc);
|
|
|
|
default:
|
|
return E_FAIL;
|
|
}
|
|
break;
|
|
|
|
case NI_COMPOSITIONSTR:
|
|
switch (dwIndex) {
|
|
case CPS_COMPLETE:
|
|
_pCicContext->EscbCompComplete(imc);
|
|
return S_OK;
|
|
|
|
case CPS_CONVERT:
|
|
case CPS_REVERT:
|
|
return E_NOTIMPL;
|
|
|
|
case CPS_CANCEL:
|
|
_pCicContext->EscbCompCancel(imc);
|
|
return S_OK;
|
|
|
|
default:
|
|
return E_FAIL;
|
|
}
|
|
break;
|
|
|
|
case NI_OPENCANDIDATE:
|
|
if (PRIMARYLANGID(langid) == LANG_KOREAN)
|
|
{
|
|
if (DoOpenCandidateHanja(ptim_P, imc, *_pCicContext))
|
|
return S_OK;
|
|
else
|
|
return E_FAIL;
|
|
}
|
|
case NI_CLOSECANDIDATE:
|
|
case NI_SELECTCANDIDATESTR:
|
|
case NI_CHANGECANDIDATELIST:
|
|
case NI_SETCANDIDATE_PAGESIZE:
|
|
case NI_SETCANDIDATE_PAGESTART:
|
|
case NI_IMEMENUSELECTED:
|
|
return E_NOTIMPL;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::OnSetOpenStatus
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::OnSetOpenStatus(
|
|
ITfThreadMgr_P* ptim_P,
|
|
IMCLock& imc,
|
|
CicInputContext& CicContext)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::OnSetOpenStatus"));
|
|
|
|
if (! imc->fOpen && imc.ValidCompositionString())
|
|
{
|
|
//
|
|
// #503401 - Finalize the composition string.
|
|
//
|
|
CicContext.EscbCompComplete(imc);
|
|
}
|
|
|
|
CicContext.m_fOpenStatusChanging.SetFlag();
|
|
HRESULT hr = SetCompartmentDWORD(m_tfClientId,
|
|
ptim_P,
|
|
GUID_COMPARTMENT_KEYBOARD_OPENCLOSE,
|
|
imc->fOpen,
|
|
FALSE);
|
|
CicContext.m_fOpenStatusChanging.ResetFlag();
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::OnSetConversionSentenceMode
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::OnSetConversionSentenceMode(
|
|
ITfThreadMgr_P* ptim_P,
|
|
IMCLock& imc,
|
|
CicInputContext& CicContext,
|
|
DWORD dwValue,
|
|
LANGID langid)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::OnSetConversionSentenceMode"));
|
|
|
|
CicContext.m_fOnceModeChanged.SetFlag();
|
|
CicContext.m_fConversionSentenceModeChanged.SetFlag();
|
|
Interface_Attach<ITfContextOwnerServices> iccb(CicContext.GetInputContextOwnerSink());
|
|
|
|
if (dwValue == IMC_SETCONVERSIONMODE)
|
|
{
|
|
CicContext.m_nInConversionModeChangingRef++;
|
|
|
|
if (PRIMARYLANGID(langid) == LANG_JAPANESE)
|
|
{
|
|
if (imc->fdwSentence == IME_SMODE_PHRASEPREDICT) {
|
|
CicContext.m_nInConversionModeResetRef++;
|
|
iccb->OnAttributeChange(GUID_PROP_MODEBIAS);
|
|
CicContext.m_nInConversionModeResetRef--;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we're in EscHanjaMode, we already makes Reconversion. So
|
|
// we don't have to make AttributeChange for IMC_CMODE_HANJACONVERT.
|
|
//
|
|
BOOL fSkipOnAttributeChange = FALSE;
|
|
if ((PRIMARYLANGID(langid) == LANG_KOREAN) &&
|
|
CicContext.m_fHanjaReConversion.IsSetFlag())
|
|
{
|
|
fSkipOnAttributeChange = TRUE;
|
|
}
|
|
|
|
// let cicero know the mode bias has changed
|
|
// consider: perf: we could try to filter out false-positives here
|
|
// (sometimes a bit that cicero ignores changes, we could check and avoid the call,
|
|
// but it would complicate the code)
|
|
if (!fSkipOnAttributeChange)
|
|
iccb->OnAttributeChange(GUID_PROP_MODEBIAS);
|
|
|
|
//
|
|
// let Korean Tip sync up the current mode status changing...
|
|
//
|
|
if (PRIMARYLANGID(langid) == LANG_KOREAN)
|
|
{
|
|
OnSetKorImxConversionMode(ptim_P, imc, CicContext);
|
|
}
|
|
|
|
if (dwValue == IMC_SETCONVERSIONMODE)
|
|
CicContext.m_nInConversionModeChangingRef--;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::OnSetKorImxConversionMode
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::OnSetKorImxConversionMode(
|
|
ITfThreadMgr_P* ptim_P,
|
|
IMCLock& imc,
|
|
CicInputContext& CicContext)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::OnSetKorImxConversionMode"));
|
|
|
|
DWORD fdwConvMode = 0;
|
|
|
|
CicContext.m_fKorImxModeChanging.SetFlag();
|
|
|
|
if (imc->fdwConversion & IME_CMODE_HANGUL)
|
|
{
|
|
if (imc->fdwConversion & IME_CMODE_FULLSHAPE)
|
|
fdwConvMode = KORIMX_HANGULJUNJA_MODE;
|
|
else
|
|
fdwConvMode = KORIMX_HANGUL_MODE;
|
|
}
|
|
else
|
|
{
|
|
if (imc->fdwConversion & IME_CMODE_FULLSHAPE)
|
|
fdwConvMode = KORIMX_JUNJA_MODE;
|
|
else
|
|
fdwConvMode = KORIMX_ALPHANUMERIC_MODE;
|
|
}
|
|
|
|
HRESULT hr = SetCompartmentDWORD(m_tfClientId,
|
|
ptim_P,
|
|
GUID_COMPARTMENT_KORIMX_CONVMODE,
|
|
fdwConvMode,
|
|
FALSE);
|
|
CicContext.m_fKorImxModeChanging.ResetFlag();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::ConfigureGeneral
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::ConfigureGeneral(
|
|
TLS* ptls,
|
|
ITfThreadMgr_P* ptim_P,
|
|
HKL hKL,
|
|
HWND hAppWnd)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::ConfigureGeneral"));
|
|
|
|
TF_LANGUAGEPROFILE LanguageProfile;
|
|
CicProfile* _pProfile = ptls->GetCicProfile();
|
|
if (_pProfile == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ConfigureGeneral. _pProfile==NULL."));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
HRESULT hr;
|
|
hr = _pProfile->GetActiveLanguageProfile(hKL,
|
|
GUID_TFCAT_TIP_KEYBOARD,
|
|
&LanguageProfile);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ConfigureGeneral. LanguageProfile==NULL."));
|
|
return hr;
|
|
}
|
|
|
|
Interface<ITfFunctionProvider> pFuncProv;
|
|
hr = ptim_P->GetFunctionProvider(LanguageProfile.clsid, // CLSID of tip
|
|
pFuncProv);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ConfigureGeneral. pFuncProv==NULL."));
|
|
return hr;
|
|
}
|
|
|
|
Interface<ITfFnConfigure> pFnConfigure;
|
|
hr = pFuncProv->GetFunction(GUID_NULL,
|
|
IID_ITfFnConfigure,
|
|
(IUnknown**)(ITfFnConfigure**)pFnConfigure);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ConfigureGeneral. pFnCofigure==NULL."));
|
|
return hr;
|
|
}
|
|
|
|
hr = pFnConfigure->Show(hAppWnd,
|
|
LanguageProfile.langid,
|
|
LanguageProfile.guidProfile);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::ConfigureGeneral
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::ConfigureRegisterWord(
|
|
TLS* ptls,
|
|
ITfThreadMgr_P* ptim_P,
|
|
HKL hKL,
|
|
HWND hAppWnd,
|
|
REGISTERWORDW* pRegisterWord)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::ConfigureRegisterWord"));
|
|
|
|
TF_LANGUAGEPROFILE LanguageProfile;
|
|
CicProfile* _pProfile = ptls->GetCicProfile();
|
|
if (_pProfile == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ConfigureRegisterWord. _pProfile==NULL."));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
HRESULT hr;
|
|
hr = _pProfile->GetActiveLanguageProfile(hKL,
|
|
GUID_TFCAT_TIP_KEYBOARD,
|
|
&LanguageProfile);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ConfigureRegisterWord. LanguageProfile==NULL."));
|
|
return hr;
|
|
}
|
|
|
|
Interface<ITfFunctionProvider> pFuncProv;
|
|
hr = ptim_P->GetFunctionProvider(LanguageProfile.clsid, // CLSID of tip
|
|
pFuncProv);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ConfigureRegisterWord. pFuncProv==NULL."));
|
|
return hr;
|
|
}
|
|
|
|
Interface<ITfFnConfigureRegisterWord> pFnRegisterWord;
|
|
hr = pFuncProv->GetFunction(GUID_NULL,
|
|
IID_ITfFnConfigureRegisterWord,
|
|
(IUnknown**)(ITfFnConfigureRegisterWord**)pFnRegisterWord);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::ConfigureRegisterWord. pFnRegisterWord==NULL."));
|
|
return hr;
|
|
}
|
|
|
|
if (!pRegisterWord || !pRegisterWord->lpWord)
|
|
{
|
|
hr = pFnRegisterWord->Show(hAppWnd,
|
|
LanguageProfile.langid,
|
|
LanguageProfile.guidProfile,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
BSTR bstrWord = SysAllocString(pRegisterWord->lpWord);
|
|
if (!bstrWord)
|
|
return E_OUTOFMEMORY;
|
|
|
|
hr = pFnRegisterWord->Show(hAppWnd,
|
|
LanguageProfile.langid,
|
|
LanguageProfile.guidProfile,
|
|
bstrWord);
|
|
|
|
SysFreeString(bstrWord);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::EscapeKorean
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
LRESULT
|
|
CicBridge::EscapeKorean(
|
|
TLS* ptls,
|
|
HIMC hImc,
|
|
UINT uSubFunc,
|
|
LPVOID lpData)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::EscapeKorean"));
|
|
|
|
switch (uSubFunc)
|
|
{
|
|
case IME_ESC_QUERY_SUPPORT:
|
|
switch (*(LPUINT)lpData)
|
|
{
|
|
case IME_ESC_HANJA_MODE: return TRUE;
|
|
default: return FALSE;
|
|
}
|
|
break;
|
|
|
|
case IME_ESC_HANJA_MODE:
|
|
return EscHanjaMode(ptls, hImc, (LPWSTR)lpData);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::EscHanjaMode
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
LRESULT
|
|
CicBridge::EscHanjaMode(
|
|
TLS* ptls,
|
|
HIMC hImc,
|
|
LPWSTR lpwStr)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::EscHanjaMode"));
|
|
|
|
HRESULT hr;
|
|
IMCLock imc(hImc);
|
|
if (FAILED(hr=imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::EscHanjaMode. imc==NULL"));
|
|
return FALSE;
|
|
}
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::EscHanjaMode. imc_ctfime==NULL"));
|
|
return FALSE;
|
|
}
|
|
|
|
CicInputContext* pCicContext = imc_ctfime->m_pCicContext;
|
|
if (pCicContext)
|
|
{
|
|
//
|
|
// This is for only Excel since Excel calling Hanja escape function two
|
|
// times. we going to just ignore the second request not to close Hanja
|
|
// candidate window.
|
|
//
|
|
if (pCicContext->m_fOpenCandidateWindow.IsSetFlag())
|
|
{
|
|
//
|
|
// Need to set the result value since some apps(Trident) also call
|
|
// Escape() twice and expect the right result value.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
pCicContext->m_fHanjaReConversion.SetFlag();
|
|
}
|
|
|
|
CWReconvertString wReconvStr(imc);
|
|
wReconvStr.WriteCompData(lpwStr, 1);
|
|
|
|
BOOL fCompMem = FALSE;
|
|
LPRECONVERTSTRING lpReconvertString = NULL;
|
|
DWORD dwLen = wReconvStr.ReadCompData();
|
|
if (dwLen) {
|
|
lpReconvertString = (LPRECONVERTSTRING) new BYTE[ dwLen ];
|
|
if (lpReconvertString) {
|
|
fCompMem = TRUE;
|
|
wReconvStr.ReadCompData(lpReconvertString, dwLen);
|
|
}
|
|
}
|
|
|
|
LRESULT ret;
|
|
ret = ImmSetCompositionStringW(hImc, SCS_QUERYRECONVERTSTRING, lpReconvertString, dwLen, NULL, 0);
|
|
if (ret) {
|
|
ret = ImmSetCompositionStringW(hImc, SCS_SETRECONVERTSTRING, lpReconvertString, dwLen, NULL, 0);
|
|
if (ret) {
|
|
ret = ImmSetConversionStatus(hImc, imc->fdwConversion | IME_CMODE_HANJACONVERT,
|
|
imc->fdwSentence);
|
|
}
|
|
}
|
|
|
|
if (pCicContext)
|
|
{
|
|
//
|
|
// enpty the edit session queue of the ic.
|
|
//
|
|
ITfThreadMgr_P* ptim_P;
|
|
|
|
if (ptls != NULL && ((ptim_P = ptls->GetTIM()) != NULL))
|
|
{
|
|
Interface<ITfContext_P> icp;
|
|
hr = pCicContext->GetInputContext()->QueryInterface(IID_ITfContext_P,
|
|
(void **)icp);
|
|
if (hr == S_OK)
|
|
ptim_P->RequestPostponedLock(icp);
|
|
else
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::EscHanjaMode. QueryInterface is failed"));
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::EscHanjaMode. ptls or ptim_P==NULL"));
|
|
}
|
|
|
|
pCicContext->m_fHanjaReConversion.ResetFlag();
|
|
}
|
|
|
|
|
|
if (fCompMem)
|
|
delete [] lpReconvertString;
|
|
|
|
return ret;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::DoOpenCandidateHanja
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
LRESULT
|
|
CicBridge::DoOpenCandidateHanja(
|
|
ITfThreadMgr_P* ptim_P,
|
|
IMCLock& imc,
|
|
CicInputContext& CicContext)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::DoOpenCandidateHanja"));
|
|
|
|
|
|
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
|
|
|
|
if (SUCCEEDED(comp.GetResult()) && comp->dwCompStrLen)
|
|
{
|
|
//
|
|
// This is for only Excel since Excel calling Hanja escape function two
|
|
// times. we going to just ignore the second request not to close Hanja
|
|
// candidate window.
|
|
//
|
|
if (CicContext.m_fOpenCandidateWindow.IsSetFlag())
|
|
{
|
|
//
|
|
// Need to set the result value since some apps(Trident) also call
|
|
// Escape() twice and expect the right result value.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
CicContext.m_fHanjaReConversion.SetFlag();
|
|
|
|
HRESULT hr;
|
|
Interface<ITfRange> Selection;
|
|
Interface<ITfFunctionProvider> FuncProv;
|
|
Interface<ITfFnReconversion> Reconversion;
|
|
|
|
hr = CicContext.EscbGetSelection(imc, &Selection);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::DoOpenCandidateHanja. EscbGetSelection failed"));
|
|
goto Exit;
|
|
}
|
|
|
|
hr = ptim_P->GetFunctionProvider(GUID_SYSTEM_FUNCTIONPROVIDER, FuncProv);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::DoOpenCandidateHanja. FuncProv==NULL"));
|
|
goto Exit;
|
|
}
|
|
|
|
hr = FuncProv->GetFunction(GUID_NULL,
|
|
IID_ITfFnReconversion,
|
|
(IUnknown**)(ITfFnReconversion**)Reconversion);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
Interface<ITfRange> RangeNew;
|
|
BOOL fConvertable;
|
|
|
|
hr = Reconversion->QueryRange(Selection, RangeNew, &fConvertable);
|
|
if (SUCCEEDED(hr) && fConvertable)
|
|
{
|
|
//
|
|
// Tip has a chance to close Hanja candidate UI window during
|
|
// the changes of conversion mode, so update conversion status
|
|
// first.
|
|
//
|
|
ImmSetConversionStatus(imc, imc->fdwConversion | IME_CMODE_HANJACONVERT,
|
|
imc->fdwSentence);
|
|
|
|
hr = Reconversion->Reconvert(RangeNew);
|
|
if (FAILED(hr))
|
|
{
|
|
ImmSetConversionStatus(imc,
|
|
imc->fdwConversion & ~IME_CMODE_HANJACONVERT,
|
|
imc->fdwSentence);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::DoOpenCandidateHanja. QueryRange failed so the compoisiton string will be completed."));
|
|
|
|
CicContext.EscbCompComplete(imc);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
fRet = TRUE;
|
|
Exit:
|
|
CicContext.m_fHanjaReConversion.ResetFlag();
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::SetCompositionString
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CicBridge::SetCompositionString(
|
|
TLS* ptls,
|
|
ITfThreadMgr_P* ptim_P,
|
|
HIMC hImc,
|
|
DWORD dwIndex,
|
|
void* pComp,
|
|
DWORD dwCompLen,
|
|
void* pRead,
|
|
DWORD dwReadLen)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::SetCompositionString"));
|
|
|
|
HRESULT hr;
|
|
IMCLock imc(hImc);
|
|
if (FAILED(hr=imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::SetCompositionString. imc==NULL"));
|
|
return FALSE;
|
|
}
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::SetCompositionString. imc_ctfime==NULL"));
|
|
return FALSE;
|
|
}
|
|
|
|
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
|
|
if (_pCicContext == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::SetCompositionString. _pCicContext==NULL."));
|
|
return FALSE;
|
|
}
|
|
|
|
UINT cp;
|
|
CicProfile* _pProfile = ptls->GetCicProfile();
|
|
if (_pProfile == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::SetCompositionString. _pProfile==NULL."));
|
|
return FALSE;
|
|
}
|
|
|
|
_pProfile->GetCodePageA(&cp);
|
|
|
|
if (dwIndex == SCS_SETSTR &&
|
|
pComp != NULL && (*(LPWSTR)pComp) == L'\0' && dwCompLen != 0)
|
|
{
|
|
LANGID langid;
|
|
hr = _pProfile->GetLangId(&langid);
|
|
|
|
//
|
|
// Bug#580455 - Some korean specific apps calls it for completing
|
|
// the current composition immediately.
|
|
//
|
|
if (SUCCEEDED(hr) && PRIMARYLANGID(langid) == LANG_KOREAN)
|
|
{
|
|
if (imc->fdwConversion & IME_CMODE_HANGUL)
|
|
{
|
|
ImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return _pCicContext->SetCompositionString(imc, ptim_P, dwIndex, pComp, dwCompLen, pRead, dwReadLen, cp);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::GetGuidAtom
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::GetGuidAtom(
|
|
TLS* ptls,
|
|
HIMC hImc,
|
|
BYTE bAttr,
|
|
TfGuidAtom* atom)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("CicBridge::GetGuidAtom"));
|
|
|
|
HRESULT hr;
|
|
IMCLock imc(hImc);
|
|
if (FAILED(hr=imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::GetGuidAtom. imc==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::GetGuidAtom. imc_ctfime==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
|
|
if (_pCicContext == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::GetGuidAtom. _pCicContext==NULL."));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return _pCicContext->GetGuidAtom(imc, bAttr, atom);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::GetDisplayAttributeInfo
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CicBridge::GetDisplayAttributeInfo(
|
|
TfGuidAtom atom,
|
|
TF_DISPLAYATTRIBUTE* da)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
GUID guid;
|
|
GetGUIDFromGUIDATOM(&_libTLS, atom, &guid);
|
|
|
|
Interface<ITfDisplayAttributeInfo> dai;
|
|
CLSID clsid;
|
|
ITfDisplayAttributeMgr* dam = GetDAMLib(&_libTLS);
|
|
if (dam != NULL)
|
|
{
|
|
if (SUCCEEDED(hr=dam->GetDisplayAttributeInfo(guid, dai, &clsid)))
|
|
{
|
|
dai->GetAttributeInfo(da);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::DefaultKeyHandling
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CicBridge::DefaultKeyHandling(
|
|
TLS* ptls,
|
|
IMCLock& imc,
|
|
CicInputContext* CicContext,
|
|
UINT uVirtKey,
|
|
LPARAM lParam)
|
|
{
|
|
if (CicContext == NULL)
|
|
return FALSE;
|
|
|
|
LANGID langid;
|
|
CicProfile* _pProfile = ptls->GetCicProfile();
|
|
if (_pProfile == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CicBridge::DefaultKeyHandling. _pProfile==NULL."));
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT hr = _pProfile->GetLangId(&langid);
|
|
|
|
if (SUCCEEDED(hr) && PRIMARYLANGID(langid) == LANG_KOREAN)
|
|
{
|
|
if (!MsimtfIsWindowFiltered(::GetFocus()) &&
|
|
(CicContext->m_fGeneratedEndComposition.IsSetFlag() || uVirtKey == VK_HANJA))
|
|
{
|
|
//
|
|
// Korean IME alwaus generate WM_IME_KEYDOWN message
|
|
// if it finalizes the interim char in order to keep message
|
|
// order.
|
|
//
|
|
PostMessage(imc->hWnd, WM_IME_KEYDOWN, uVirtKey, lParam);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Korean won't _WantThisKey / _HandleThisKey
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
if (! (HIWORD(uVirtKey) & KF_UP)) {
|
|
if (CicContext->WantThisKey(uVirtKey)) {
|
|
CicContext->EscbHandleThisKey(imc, uVirtKey);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::CTFDetection
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CicBridge::CTFDetection(
|
|
TLS* ptls,
|
|
ITfDocumentMgr* dim)
|
|
{
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Get TIM
|
|
//
|
|
ITfThreadMgr_P* ptim_P;
|
|
if ((ptim_P=ptls->GetTIM()) == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CThreadMgrEventSink_DIMCallBack::DIMCallback. ptim_P==NULL"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Get cskf
|
|
//
|
|
Interface<ITfConfigureSystemKeystrokeFeed> cskf;
|
|
hr = ptim_P->QueryInterface(IID_ITfConfigureSystemKeystrokeFeed, (void**)cskf);
|
|
if (hr != S_OK)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CThreadMgrEventSink_DIMCallBack::DIMCallback. IID_ITfConfigureSystemKeystrokeFeed==NULL"));
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL fEnableKeystrokeFeed = FALSE;
|
|
|
|
//
|
|
// Cicero aware application detection...
|
|
//
|
|
// if dim is NULL, it is not Ciceor aware apps document.
|
|
//
|
|
if (!dim || IsOwnDim(dim))
|
|
{
|
|
//
|
|
// CTFIME owns document
|
|
//
|
|
fEnableKeystrokeFeed = FALSE;
|
|
ptls->ResetCTFAware();
|
|
}
|
|
else
|
|
{
|
|
fEnableKeystrokeFeed = TRUE;
|
|
ptls->SetCTFAware();
|
|
}
|
|
|
|
//
|
|
// Call ImmGetAppCompatFlags with NULL to get the global app compat flag.
|
|
//
|
|
DWORD dwImeCompatFlags = ImmGetAppCompatFlags(NULL);
|
|
if (dwImeCompatFlags & (IMECOMPAT_AIMM12 | IMECOMPAT_AIMM_LEGACY_CLSID | IMECOMPAT_AIMM12_TRIDENT))
|
|
{
|
|
//
|
|
// we want to get hwnd from hIMC that is associated to dim.
|
|
// Now we don't have a back pointer to hIMC in dim.
|
|
//
|
|
HWND hwndFocus = ::GetFocus();
|
|
if (hwndFocus && MsimtfIsWindowFiltered(hwndFocus))
|
|
{
|
|
//
|
|
// AIMM aware apps. Never processing ImeProcessKey
|
|
//
|
|
fEnableKeystrokeFeed = TRUE;
|
|
ptls->SetAIMMAware();
|
|
}
|
|
else
|
|
{
|
|
ptls->ResetAIMMAware();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enable or disable keystroke feed if necessary.
|
|
//
|
|
if (ptls->IsEnabledKeystrokeFeed() && !fEnableKeystrokeFeed)
|
|
{
|
|
hr = cskf->DisableSystemKeystrokeFeed();
|
|
if (hr != S_OK)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CThreadMgrEventSink_DIMCallBack::CTFDetection. DisableSystemKeystrokeFeed==NULL"));
|
|
}
|
|
ptls->ResetEnabledKeystrokeFeed();
|
|
}
|
|
else if (!ptls->IsEnabledKeystrokeFeed() && fEnableKeystrokeFeed)
|
|
{
|
|
hr = cskf->EnableSystemKeystrokeFeed();
|
|
if (hr != S_OK)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CThreadMgrEventSink_DIMCallBack::CTFDetection. EnableSystemKeystrokeFeed==NULL"));
|
|
}
|
|
ptls->SetEnabledKeystrokeFeed();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::PostTransMsg
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CicBridge::PostTransMsg(
|
|
HWND hwnd,
|
|
INT iNum,
|
|
LPTRANSMSG lpTransMsg)
|
|
{
|
|
while (iNum--)
|
|
{
|
|
PostMessageW(hwnd,
|
|
lpTransMsg->message,
|
|
lpTransMsg->wParam,
|
|
lpTransMsg->lParam);
|
|
lpTransMsg++;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::EnumCreateInputContextCallback(HIMC hIMC, LPARAM lParam)
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CicBridge::EnumCreateInputContextCallback(HIMC hIMC, LPARAM lParam)
|
|
{
|
|
ENUMIMC *pedimc = (ENUMIMC *)lParam;
|
|
|
|
pedimc->_this->CreateInputContext(pedimc->ptls, hIMC);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicBridge::EnumDestroyInputContextCallback(HIMC hIMC, LPARAM lParam)
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CicBridge::EnumDestroyInputContextCallback(HIMC hIMC, LPARAM lParam)
|
|
{
|
|
ENUMIMC *pedimc = (ENUMIMC *)lParam;
|
|
|
|
pedimc->_this->DestroyInputContext(pedimc->ptls, hIMC);
|
|
|
|
return TRUE;
|
|
}
|