Leaked source code of windows server 2003
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.
 
 
 
 
 
 

570 lines
16 KiB

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