|
|
/*++
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; }
|