|
|
//
// ic.cpp
//
#include "private.h"
#include "common.h"
#include "korimx.h"
#include "icpriv.h"
#include "ipointcic.h"
#include "cleanup.h"
#include "helpers.h"
//+---------------------------------------------------------------------------
//
// OnStartCleanupContext
//
//----------------------------------------------------------------------------
HRESULT CKorIMX::OnStartCleanupContext() { // nb: a real tip, for performace, should skip input contexts it knows
// it doesn't need a lock and callback on. For instance, kimx only
// cares about ic's with ongoing compositions. We could remember which ic's
// have compositions, then return FALSE for all but the ic's with compositions.
// It is really bad perf to have the library make a lock request for every
// ic!
m_fPendingCleanup = fTrue; return S_OK; }
//+---------------------------------------------------------------------------
//
// OnEndCleanupContext
//
// Called after all ic's with cleanup sinks have been called.
//----------------------------------------------------------------------------
HRESULT CKorIMX::OnEndCleanupContext() { // our profile just changed or we are about to be deactivated
// in either case we don't have to worry about anything interrupting ic cleanup
// callbacks anymore
m_fPendingCleanup = fFalse; return S_OK; }
//+---------------------------------------------------------------------------
//
// OnCleanupContext
//
// This method is a callback for the library helper CleanupAllContexts.
// We have to be very careful here because we may be called _after_ this tip
// has been deactivated, if the app couldn't grant a lock right away.
//----------------------------------------------------------------------------
HRESULT CKorIMX::OnCleanupContext(TfEditCookie ecWrite, ITfContext *pic) { // all kimx cares about is finalizing compositions
CleanupAllCompositions(ecWrite, pic, CLSID_KorIMX, _CleanupCompositionsCallback, this);
return S_OK; }
//+---------------------------------------------------------------------------
//
// ITfActiveLanguageProfileNotifySink::OnActivated
//
//----------------------------------------------------------------------------
STDAPI CKorIMX::OnActivated(REFCLSID clsid, REFGUID guidProfile, BOOL bActivated) { // our profile just changed or we are about to be deactivated
// in either case we don't have to worry about anything interrupting ic cleanup
// callbacks anymore
m_fPendingCleanup = fFalse;
//if (IsSoftKbdEnabled())
// OnActivatedSoftKbd(bActivated);
return S_OK; }
//+---------------------------------------------------------------------------
//
// _CleanupCompositionsCallback
//
//----------------------------------------------------------------------------
/* static */ void CKorIMX::_CleanupCompositionsCallback(TfEditCookie ecWrite, ITfRange *rangeComposition, void *pvPrivate) { CKorIMX* pKorTip = (CKorIMX*)pvPrivate; ITfContext *pic;
if (rangeComposition->GetContext(&pic) != S_OK) return; if (pKorTip) pKorTip->MakeResultString(ecWrite, pic, rangeComposition); // _FinalizeRange(ecWrite, pic, rangeComposition);
pic->Release(); }
/*---------------------------------------------------------------------------
CKorIMX::_InitICPriv
Init IC private data ---------------------------------------------------------------------------*/ HRESULT CKorIMX::_InitICPriv(ITfContext *pic) { CICPriv *picp; CCompartmentEventSink* pCompartmentSink; ITfSourceSingle *pSourceSingle; TF_STATUS dcs;
// Check pic
if (pic == NULL) return E_FAIL; //
// check enable/disable (Candidate stack)
//
if (IsDisabledIC(pic) || IsEmptyIC(pic)) return S_OK;
// Initialize Private data members
if ((picp = GetInputContextPriv(pic)) == NULL) { IUnknown *punk;
if ((picp = new CICPriv) == NULL) return E_OUTOFMEMORY;
// IC
picp->RegisterIC(pic); // IMX
picp->RegisterIMX(this);
if (picp->IsInitializedIPoint() == FALSE) { //struct _GUID RefID={0}; // dummy id
IImeIPoint1 *pIP; LPCIPointCic pCIPointCic = NULL;
//////////////////////////////////////////////////////////////////////
// Create IImeIPoint1 instance
//////////////////////////////////////////////////////////////////////
if ((pCIPointCic = new CIPointCic(this)) == NULL) { return E_OUTOFMEMORY; }
// This increments the reference count
if (FAILED(pCIPointCic->QueryInterface(IID_IImeIPoint1, (VOID **)&pIP))) { delete pCIPointCic; return E_OUTOFMEMORY; }
// initialize kernel
pCIPointCic->Initialize(pic);
// register ic depended objects.
picp->RegisterIPoint(pIP); picp->InitializedIPoint(fTrue); } //
// text edit sink/edit transaction sink
//
ITfSource *pSource; DWORD dwCookieForTextEditSink = 0; //DWORD dwCookieForTransactionSink = 0;
if (pic->QueryInterface(IID_ITfSource, (void **)&pSource ) == S_OK) { pSource->AdviseSink(IID_ITfTextEditSink, (ITfTextEditSink *)this, &dwCookieForTextEditSink); //pSource->AdviseSink(IID_ITfEditTransactionSink, (ITfEditTransactionSink *)this, &dwCookieForTransactionSink);
pSource->Release();
picp->RegisterCookieForTextEditSink(dwCookieForTextEditSink); //picp->RegisterCookieForTransactionSink(dwCookieForTransactionSink);
}
// compartment event sink
if ((pCompartmentSink = new CCompartmentEventSink(_CompEventSinkCallback, picp)) != NULL ) { picp->RegisterCompartmentEventSink(pCompartmentSink);
// On/Off - compartment
pCompartmentSink->_Advise(GetTIM(), GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, FALSE); // Conversion mode - compartment
pCompartmentSink->_Advise(GetTIM(), GUID_COMPARTMENT_KORIMX_CONVMODE, FALSE);
// SoftKeyboard Open/Close
pCompartmentSink->_Advise(GetTIM(), GUID_COMPARTMENT_KOR_SOFTKBD_OPENCLOSE, FALSE);
// Soft Keyboard layout change
pCompartmentSink->_Advise(GetTIM(), GUID_COMPARTMENT_SOFTKBD_KBDLAYOUT, FALSE); }
Assert(pCompartmentSink != NULL);
if (pic->QueryInterface(IID_ITfSourceSingle, (void **)&pSourceSingle) == S_OK) { // setup a cleanup callback
// nb: a real tip doesn't need to be this aggressive, for instance
// kimx probably only needs this sink on the focus ic.
pSourceSingle->AdviseSingleSink(GetTID(), IID_ITfCleanupContextSink, (ITfCleanupContextSink *)this); pSourceSingle->Release(); }
// Initialized kernel
picp->Initialized(fTrue);
// Set to compartment GUID
GetCompartmentUnknown(pic, GUID_IC_PRIVATE, &punk); if (!punk) { SetCompartmentUnknown(GetTID(), pic, GUID_IC_PRIVATE, picp); picp->Release(); } else { // Praive data already exist.
punk->Release(); return E_FAIL; }
}
// Set AIMM1.2
picp->SetAIMM(fFalse); pic->GetStatus(&dcs);
if (dcs.dwStaticFlags & TF_SS_TRANSITORY) picp->SetAIMM(fTrue);
return S_OK; }
/*---------------------------------------------------------------------------
CKorIMX::_DeleteICPriv
Delete IC private data ---------------------------------------------------------------------------*/ HRESULT CKorIMX::_DeleteICPriv(ITfContext *pic) { CICPriv *picp; IUnknown *punk; CCompartmentEventSink* pCompartmentSink; ITfSource *pSource; ITfSourceSingle *pSourceSingle; if (pic == NULL) return E_FAIL;
picp = GetInputContextPriv(pic);
#ifdef DBG
Assert(IsDisabledIC(pic) || picp != NULL ); #endif
if (picp == NULL) return S_FALSE;
//
// Compartment event sink
//
pCompartmentSink = picp->GetCompartmentEventSink(); if (pCompartmentSink) { pCompartmentSink->_Unadvise(); pCompartmentSink->Release(); }
//
// text edit sink
//
if (pic->QueryInterface( IID_ITfSource, (void **)&pSource) == S_OK) { pSource->UnadviseSink(picp->GetCookieForTextEditSink()); //pSource->UnadviseSink(picp->GetCookieForTransactionSink());
pSource->Release(); } picp->RegisterCookieForTextEditSink(0);
// Clear ITfCleanupContextSink
if (pic->QueryInterface(IID_ITfSourceSingle, (void **)&pSourceSingle) == S_OK) { pSourceSingle->UnadviseSingleSink(GetTID(), IID_ITfCleanupContextSink); pSourceSingle->Release(); }
// UnInitialize IPoint
IImeIPoint1 *pIP = GetIPoint(pic); // IImeIPoint
if (pIP) { pIP->Release(); } picp->RegisterIPoint(NULL); picp->InitializedIPoint(fFalse); // reset
// Reset init flag
picp->Initialized(fFalse);
// We MUST clear out the private data before cicero is free
// to release the ic
GetCompartmentUnknown(pic, GUID_IC_PRIVATE, &punk); if (punk) punk->Release(); ClearCompartment(GetTID(), pic, GUID_IC_PRIVATE, fFalse);
return S_OK; }
/*---------------------------------------------------------------------------
CKorIMX::GetInputContextPriv
Get IC private data ---------------------------------------------------------------------------*/ CICPriv *CKorIMX::GetInputContextPriv(ITfContext *pic) { IUnknown *punk;
if (pic == NULL) return NULL; GetCompartmentUnknown(pic, GUID_IC_PRIVATE, &punk);
if (punk) punk->Release();
return (CICPriv *)punk; }
/*---------------------------------------------------------------------------
CKorIMX::OnICChange ---------------------------------------------------------------------------*/ void CKorIMX::OnFocusChange(ITfContext *pic, BOOL fActivate) { BOOL fReleaseIC = fFalse; BOOL fDisabledIC = IsDisabledIC(pic); BOOL fEmptyIC = IsEmptyIC(pic); BOOL fCandidateIC = IsCandidateIC(pic);
BOOL fInEditSession; HRESULT hr;
if (fEmptyIC) { if (m_pToolBar) m_pToolBar->SetCurrentIC(NULL);
if (IsSoftKbdEnabled()) SoftKbdOnThreadFocusChange(fFalse); return; // do nothing
} if (fDisabledIC == fTrue && fCandidateIC == fFalse ) { if (m_pToolBar) m_pToolBar->SetCurrentIC(NULL);
if (IsSoftKbdEnabled()) SoftKbdOnThreadFocusChange(fFalse); return; // do nothing
}
// O10 #278261: Restore Soft Keyboard winfow after switched from Empty Context to normal IC.
if (IsSoftKbdEnabled()) SoftKbdOnThreadFocusChange(fActivate);
// Notify focus change to IME Pad svr
if (m_pPadCore) { m_pPadCore->SetFocus(fActivate); }
// Terminate
if (fActivate == fFalse) { if (!fDisabledIC && pic && GetIPComposition(pic)) { if (SUCCEEDED(pic->InWriteSession(GetTID(), &fInEditSession)) && !fInEditSession) { CEditSession2 *pes; ESSTRUCT ess;
ESStructInit(&ess, ESCB_COMPLETE); if ((pes = new CEditSession2(pic, this, &ess, _EditSessionCallback2))) { pes->Invoke(ES2_READWRITE | ES2_SYNC, &hr); pes->Release(); } } }
// Close cand UI if opened.
if (m_fCandUIOpen) CloseCandidateUIProc(); return; }
// fActivate == TRUE
if (fDisabledIC) { pic = GetRootIC(); fReleaseIC = fTrue; }
if (m_pToolBar) m_pToolBar->SetCurrentIC(pic);
if (m_pPadCore) { IImeIPoint1* pIP = GetIPoint(pic); m_pPadCore->SetIPoint(pIP); }
if (pic && !fDisabledIC) { CICPriv *picp;
// Sync GUID_COMPARTMENT_KEYBOARD_OPENCLOSE with GUID_COMPARTMENT_KORIMX_CONVMODE
// This for Word now but looks not good since we don't sync On/Off status with conv mode.
// In future Apps should set GUID_MODEBIAS_HANGUL on boot and should be Korean specific code.
if (GetConvMode(pic) == TIP_NULL_CONV_MODE) // if this is first boot.
{ if (IsOn(pic)) SetCompartmentDWORD(GetTID(), GetTIM(), GUID_COMPARTMENT_KORIMX_CONVMODE, TIP_HANGUL_MODE, fFalse); else SetCompartmentDWORD(GetTID(), GetTIM(), GUID_COMPARTMENT_KORIMX_CONVMODE, TIP_ALPHANUMERIC_MODE, fFalse); } else { // Reset ModeBias
picp = GetInputContextPriv(pic); if (picp) picp->SetModeBias(NULL); }
// Modebias check here
CheckModeBias(pic); }
if (fReleaseIC) SafeRelease(pic); }
// REVIEW::
// tmp solution
ITfContext* CKorIMX::GetRootIC(ITfDocumentMgr* pDim) { if (pDim == NULL) { pDim = m_pCurrentDim; if( pDim == NULL ) return NULL; }
IEnumTfContexts *pEnumIc = NULL; if (SUCCEEDED(pDim->EnumContexts(&pEnumIc))) { ITfContext *pic = NULL; while (pEnumIc->Next(1, &pic, NULL) == S_OK) break; pEnumIc->Release();
return pic; } return NULL; // error case
}
IImeIPoint1* CKorIMX::GetIPoint(ITfContext *pic) { CICPriv *picp; if (pic == NULL) { return NULL; } picp = GetInputContextPriv(pic);
if (picp) { return picp->GetIPoint(); } return NULL; } BOOL CKorIMX::IsDisabledIC(ITfContext *pic) { DWORD dwFlag;
if (pic == NULL) return fFalse; GetCompartmentDWORD(pic, GUID_COMPARTMENT_KEYBOARD_DISABLED, &dwFlag, fFalse);
if (dwFlag) return fTrue; // do not create any kernel related info into ic.
else return fFalse; }
/* I S E M P T Y I C */ BOOL CKorIMX::IsEmptyIC(ITfContext *pic) { DWORD dwFlag; if (pic == NULL) return fFalse; GetCompartmentDWORD(pic, GUID_COMPARTMENT_EMPTYCONTEXT, &dwFlag, fFalse);
if (dwFlag) return fTrue; // do not create any kernel related info into ic.
return fFalse; }
/* I S C A N D I D A T E I C */ /*------------------------------------------------------------------------------
Check if the input context is one of candidate UI
------------------------------------------------------------------------------*/ BOOL CKorIMX::IsCandidateIC(ITfContext *pic) { DWORD dwFlag; if (pic == NULL) return fFalse; GetCompartmentDWORD( pic, GUID_COMPARTMENT_KEYBOARD_DISABLED, &dwFlag, fFalse);
if (dwFlag) return fTrue; // do not create any kernel related info into ic.
return fFalse; }
HWND CKorIMX::GetAppWnd(ITfContext *pic) { ITfContextView* pView; HWND hwndApp = 0;
if (pic == NULL) return 0;
pic->GetActiveView(&pView); if (pView == NULL) return 0;
pView->GetWnd(&hwndApp); pView->Release(); return hwndApp;
}
|