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.
 
 
 
 
 
 

737 lines
22 KiB

#include "private.h"
#include "korimx.h"
#include "timsink.h"
#include "immxutil.h"
#include "fnrecon.h"
#include "helpers.h"
#include "skbdmode.h"
#include "osver.h"
// REVIEW
/*---------------------------------------------------------------------------
CKorIMX::_EditSessionCallback
---------------------------------------------------------------------------*/
HRESULT CKorIMX::_EditSessionCallback2(TfEditCookie ec, CEditSession2 *pes)
{
ITfContext* pic = pes->GetContext();
CKorIMX* pKorTip = pes->GetTIP();
ESSTRUCT* pess = pes->GetStruct();
ITfRange* pRange;
CHangulAutomata* pAutomata;
LPWSTR pszCand = NULL;
Assert(pic != NULL);
Assert(pKorTip != NULL);
if ((pKorTip == NULL) || (pic == NULL))
return E_FAIL;
switch (pess->id)
{
case ESCB_FINALIZECONVERSION:
{
CCandidateListEx *pCandList;
CCandidateStringEx *pCandItem;
pCandList = pess->pCandList;
pCandItem = pess->pCandStr;
pRange = pess->pRange;
pszCand = pCandItem->m_psz;
if (pszCand)
{
size_t cchCand = 0;
StringCchLengthW(pszCand, CIC_KOR_CANDSTR_MAX, &cchCand);
// Set Reading text
SetTextAndReading(pKorTip->_GetLibTLS(), ec, pic, pRange,
pszCand,
cchCand,
pCandItem->m_langid, pCandItem->m_pszRead);
}
pCandList->Release();
// First complete current comp string
if (pAutomata = pKorTip->GetAutomata(pic))
pAutomata->MakeComplete();
pKorTip->MakeResultString(ec, pic, pRange);
pKorTip->CloseCandidateUIProc();
break;
}
case ESCB_COMPLETE:
{
BOOL fReleaseRange = fFalse;
// If No composition exist, nothing to complete
if (pKorTip->GetIPComposition(pic) == NULL)
break;
pRange = pess->pRange;
pAutomata = pKorTip->GetAutomata(pic);
// Close cand UI if exist.
pKorTip->CloseCandidateUIProc();
if (pRange == NULL)
{
GetSelectionSimple(ec, pic, &pRange);
fReleaseRange = fTrue;
}
if (pRange)
{
if (pAutomata)
pAutomata->MakeComplete();
pKorTip->MakeResultString(ec, pic, pRange);
}
if (fReleaseRange)
{
SafeRelease(pRange);
}
//return pKorTip->_MultiRangeConversion(ec, pes->_state.u, pic, pRange);
break;
}
case ESCB_INSERT_PAD_STRING:
{
WCHAR szText[2];
GetSelectionSimple(ec, pic, &pRange);
szText[0] = (WCHAR)pess->wParam;
szText[1] = L'\0';
if (FAILED(pKorTip->SetInputString(ec, pic, pRange, szText, CKorIMX::GetLangID())))
break;
pKorTip->MakeResultString(ec, pic, pRange);
SafeRelease(pRange);
break;
}
case ESCB_KEYSTROKE:
{
WPARAM wParam = pess->wParam;
LPARAM lParam = pess->lParam;
return pKorTip->_Keystroke(ec, pic, wParam, lParam, (const BYTE *)pess->pv1);
break;
}
// Complete and Selection range changed
case ESCB_TEXTEVENT:
if (pKorTip->IsKeyFocus() && (GetSelectionSimple(ec, pic, &pRange) == S_OK))
{
ITfComposition *pComposition;
ITfRange *pRangeOldComp;
//IEnumTfRanges *pEnumText = pess->pEnumRange;
BOOL fChanged = fFalse;
BOOL fEmpty;
// Check modebias here
if (pess->fBool)
fChanged = pKorTip->CheckModeBias(ec, pic, pRange);
//////////////////////////////////////////////////////////////////
// To complete on mouse click we using Range change notification.
// In future version, we could remove this code and use custom property
// or reading string. Cutom property can hold Hangul Automata object.
//
// Office apps explicitly call complete but this for unknown Cicero apps.
//////////////////////////////////////////////////////////////////
pComposition = pKorTip->GetIPComposition(pic);
if (pComposition == NULL)
goto ExitTextEvent;
// Office apps are not going through here.
pComposition->GetRange(&pRangeOldComp);
if (pRangeOldComp == NULL)
goto ExitTextEvent;
pRange->IsEmpty(ec, &fEmpty);
if (fEmpty && (CR_EQUAL != CompareRanges(ec, pRange, pRangeOldComp)))
{
ITfProperty *pPropAttr;
TfGuidAtom attr;
// Clear attrib
if (SUCCEEDED(pic->GetProperty(GUID_PROP_ATTRIBUTE, &pPropAttr)))
{
if (SUCCEEDED(GetAttrPropertyData(ec, pPropAttr, pRangeOldComp, &attr)))
{
if (pKorTip->IsKorIMX_GUID_ATOM(attr))
{
pPropAttr->Clear(ec, pRangeOldComp);
}
}
pPropAttr->Release();
}
pAutomata = pKorTip->GetAutomata(pic);
if (pAutomata)
pAutomata->MakeComplete();
pKorTip->EndIPComposition(ec, pic);
// pKorTip->MakeResultString(ec, pic, pRangeOldComp);
fChanged = fTrue;
}
SafeRelease(pRangeOldComp);
ExitTextEvent:
pRange->Release();
// Close cand UI if exist.
if (fChanged)
pKorTip->CloseCandidateUIProc();
}
break;
// case ESCB_RANGEBROKEN:
// pKorTip->FlushIPRange(ec, pic);
// break;
case ESCB_CANDUI_CLOSECANDUI:
// u : ESCB_CANDUI_CLOSECANDUI
// pv : this
// hwnd : - (not used)
// wParam : - (not used)
// lParam : - (not used)
// pv1 : - (not used)
// pv2 : - (not used)
// pic : - (not used)
// pRange : - (not used)
// fBool : - (not used)
pKorTip->CloseCandidateUIProc();
break;
// Hanja conv button up
case ESCB_HANJA_CONV:
// u : ESCB_HANJA_CONV
// pv : this
// hwnd : - (not used)
// wParam : - (not used)
// lParam : - (not used)
// pv1 : - (not used)
// pv2 : - (not used)
// pic : - pic
// pRange : - (not used)
// fBool : - (not used)
// O10 #220177: Simulate VK_HANJA key to invoke HHC
if (GetAIMM(pic) && (IsOnNT5() || PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_JAPANESE))
{
keybd_event(VK_HANJA, 0, 0, 0);
keybd_event(VK_HANJA, 0, KEYEVENTF_KEYUP, 0);
}
else
if (GetSelectionSimple(ec, pic, &pRange) == S_OK)
{
if (pKorTip->GetIPComposition(pic))
pKorTip->DoHanjaConversion(ec, pic, pRange);
else
pKorTip->Reconvert(pRange);
SafeRelease(pRange);
}
// Update Hanja button
if (pKorTip->m_pToolBar != NULL)
pKorTip->m_pToolBar->Update(UPDTTB_HJMODE);
break;
///////////////////////////////////////////////////////////////////////////
// Reconversion Callbacks
case ESCB_FINALIZERECONVERSION:
{
CCandidateListEx *pCandList = pess->pCandList;
CCandidateStringEx *pCandItem = pess->pCandStr;
pRange = pess->pRange;
pszCand = pCandItem->m_psz;
Assert(pRange != NULL);
pKorTip->CloseCandidateUI(pic);
if (GetAIMM(pic) == fFalse)
{
if (pszCand)
{
size_t cchCand = 0;
StringCchLengthW(pszCand, CIC_KOR_CANDSTR_MAX, &cchCand);
//ITfRange *pRangeTmp;
SetTextAndReading(pKorTip->_GetLibTLS(), ec, pic, pRange,
pszCand,
cchCand,
pCandItem->m_langid, pCandItem->m_pszRead);
}
// To clear current selection and composition
pKorTip->MakeResultString(ec, pic, pRange);
}
else
{
if (pszCand)
{
pRange->SetText(ec, 0, pszCand, 1/* wcslen(pszCand)*/);
SetSelectionSimple(ec, pic, pRange);
}
pKorTip->EndIPComposition(ec, pic);
}
// if hit reconversion on composition string, we need to clear automata.
pAutomata = pKorTip->GetAutomata(pic);
if (pRange && pAutomata && pAutomata->GetCompositionChar())
pAutomata->MakeComplete();
SafeRelease(pRange);
break;
}
case ESCB_ONSELECTRECONVERSION:
break;
case ESCB_ONCANCELRECONVERSION:
pRange = pess->pRange;
pKorTip->CancelCandidate(ec, pic);
if (GetAIMM(pic) == fFalse)
{
// To clear current selection and composition
pKorTip->MakeResultString(ec, pic, pRange);
}
else
pKorTip->EndIPComposition(ec, pic);
// if hit reconversion on composition string, we need to clear automata.
pAutomata = pKorTip->GetAutomata(pic);
if (pRange && pAutomata && pAutomata->GetCompositionChar())
pAutomata->MakeComplete();
SafeRelease(pRange);
break;
case ESCB_RECONV_QUERYRECONV:
{
CFnReconversion *pReconv = (CFnReconversion *)pess->pv1;
if (pKorTip->IsCandUIOpen())
return E_FAIL;
return pReconv->_QueryRange(ec, pic, pess->pRange, (ITfRange **)pess->pv2);
}
case ESCB_RECONV_GETRECONV:
{
CFnReconversion *pReconv = (CFnReconversion *)pess->pv1;
if (pKorTip->IsCandUIOpen())
return E_FAIL;
return pReconv->_GetReconversion(ec, pic, pess->pRange, (CCandidateListEx **)pess->pv2, pess->fBool);
}
case ESCB_RECONV_SHOWCAND:
{
ITfComposition* pComposition;
GUID attr;
ITfProperty* pProp = NULL;
pRange = pess->pRange;
pComposition = pKorTip->GetIPComposition(pic);
if (/*GetAIMM(pic) == fFalse && */ pComposition == NULL)
{
pKorTip->CreateIPComposition(ec, pic, pRange);
// Set input attr and composing state.
if (SUCCEEDED(pic->GetProperty(GUID_PROP_ATTRIBUTE, &pProp)))
{
attr = GUID_ATTR_KORIMX_INPUT;
SetAttrPropertyData(pKorTip->_GetLibTLS(), ec, pProp, pRange, attr);
pProp->Release();
}
}
pKorTip->OpenCandidateUI(ec, pic, pess->pRange, pess->pCandList);
break;
}
case ESCB_INIT_MODEBIAS:
// Check mode bias
//
// id : ESCB_INIT_MODEBIAS
// ptip : this
// pic : pic
pKorTip->InitializeModeBias(ec, pic);
break;
}
return S_OK;
}
/*---------------------------------------------------------------------------
CKorIMX::_DIMCallback
---------------------------------------------------------------------------*/
/* static */
HRESULT CKorIMX::_DIMCallback(UINT uCode, ITfDocumentMgr *pdimNew, ITfDocumentMgr *pdimPrev, void *pv)
{
ITfContext *pic = NULL;
CKorIMX *pKorImx = (CKorIMX *)pv;
Assert(pKorImx != NULL);
switch (uCode)
{
case TIM_CODE_SETFOCUS:
if (pdimPrev)
{
TraceMsg(DM_TRACE, TEXT("TIM_CODE_SETFOCUS: pdimPrev"));
pdimPrev->GetTop(&pic);
pKorImx->OnFocusChange(pic, fFalse);
SafeRelease(pic);
SafeReleaseClear(pKorImx->m_pCurrentDim);
}
if (pdimNew)
{
TraceMsg(DM_TRACE, TEXT("TIM_CODE_SETFOCUS: pdimNew"));
SafeReleaseClear(pKorImx->m_pCurrentDim);
// Set New dim
pKorImx->m_pCurrentDim = pdimNew;
pKorImx->m_pCurrentDim->AddRef();
pdimNew->GetTop(&pic);
pKorImx->OnFocusChange(pic, fTrue);
if (pic)
pic->Release();
}
break;
}
return S_OK;
}
/*---------------------------------------------------------------------------
CKorIMX::_ICCallback
Document Input Manager callback. ITfThreadMgrEventSink
---------------------------------------------------------------------------*/
/* static */
HRESULT CKorIMX::_ICCallback(UINT uCode, ITfContext *pic, void *pv)
{
CKorIMX *_this = (CKorIMX *)pv;
switch (uCode)
{
case TIM_CODE_INITIC:
if (!_this->IsPendingCleanup()) // ignore new ic's if we're being shutdown.
{
_this->_InitICPriv(pic);
}
break;
case TIM_CODE_UNINITIC:
_this->_DeleteICPriv(pic);
break;
}
return S_OK;
}
/*---------------------------------------------------------------------------
CKorIMX::_CompEventSinkCallback
---------------------------------------------------------------------------*/
HRESULT CKorIMX::_CompEventSinkCallback(void *pv, REFGUID rguid)
{
CICPriv* picp = (CICPriv*)pv;
ITfContext* pic;
CKorIMX *_this;
if (picp == NULL)
return S_OK; // error
pic = picp->GetIC();
if (pic == NULL)
return S_OK; // error
_this = picp->GetIMX();
if (_this == NULL || _this->m_pToolBar == NULL)
return S_OK; // do nothinig
// if Open/Close compartment
if (IsEqualGUID(rguid, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE))
{
_this->m_pToolBar->Update(UPDTTB_CMODE|UPDTTB_FHMODE);
}
else
// if conversion mode compartment
if (IsEqualGUID(rguid, GUID_COMPARTMENT_KORIMX_CONVMODE))
{
DWORD dwConvMode = _this->GetConvMode(pic);
BOOL fIsOn = _this->IsOn(pic);
// We just open for Hangul mode do not close for Alphanumeric mode for Cicero full aware apps.
// This will prevent redundant Open/Close compartment call.
if (dwConvMode == TIP_ALPHANUMERIC_MODE && fIsOn)
_this->SetOnOff(pic, fFalse);
else
if (dwConvMode != TIP_ALPHANUMERIC_MODE && fIsOn == fFalse)
_this->SetOnOff(pic, fTrue);
_this->m_pToolBar->Update(UPDTTB_CMODE|UPDTTB_FHMODE);
}
else
// if SoftKeyboard compartmemnt
if (IsEqualGUID(rguid, GUID_COMPARTMENT_KOR_SOFTKBD_OPENCLOSE))
{
BOOL fSkbdOn = _this->GetSoftKBDOnOff();
_this->ShowSoftKBDWindow(fSkbdOn);
if (_this->m_pToolBar && _this->m_pToolBar->GetSkbdMode())
_this->m_pToolBar->GetSkbdMode()->UpdateToggle();
}
else
// if SoftKeyboard compartmemnt
if (IsEqualGUID(rguid, GUID_COMPARTMENT_SOFTKBD_KBDLAYOUT))
{
DWORD dwSoftLayout, dwCurLabel;
HRESULT hr;
if (_this->m_pSoftKbd == NULL)
return E_FAIL;
dwSoftLayout = _this->GetSoftKBDLayout();
dwCurLabel = _this->GetHangulSKbd()->dwCurLabel;
hr = _this->m_pSoftKbd->SelectSoftKeyboard(dwSoftLayout);
if (FAILED(hr))
return hr;
if (dwSoftLayout == _this->m_KbdStandard.dwSoftKbdLayout)
hr = _this->m_pSoftKbd->SetKeyboardLabelText(GetKeyboardLayout(0));
else
hr = _this->m_pSoftKbd->SetKeyboardLabelTextCombination(dwCurLabel);
if (FAILED(hr))
return hr;
if (_this->GetSoftKBDOnOff())
{
hr = _this->m_pSoftKbd->ShowSoftKeyboard(fTrue);
return hr;
}
}
return S_OK;
}
/*---------------------------------------------------------------------------
CKorIMX::_PreKeyCallback
---------------------------------------------------------------------------*/
HRESULT CKorIMX::_PreKeyCallback(ITfContext *pic, REFGUID rguid, BOOL *pfEaten, void *pv)
{
CKorIMX *_this = (CKorIMX *)pv;
if (_this == NULL)
return S_OK;
if (IsEqualGUID(rguid, GUID_KOREAN_HANGULSIMULATE))
{
DWORD dwConvMode;
// Toggle Hangul mode
dwConvMode = _this->GetConvMode(pic);
dwConvMode ^= TIP_HANGUL_MODE;
_this->SetConvMode(pic, dwConvMode);
*pfEaten = fTrue;
}
else if (IsEqualGUID(rguid, GUID_KOREAN_HANJASIMULATE))
{
// O10 #317983
if (PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_JAPANESE)
{
keybd_event(VK_HANJA, 0, 0, 0);
keybd_event(VK_HANJA, 0, KEYEVENTF_KEYUP, 0);
*pfEaten = fTrue;
}
else
*pfEaten = fFalse;
}
return S_OK;
}
/* O N E N D E D I T */
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
HRESULT CKorIMX::OnEndEdit(ITfContext *pic, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord)
{
UNREFERENCED_PARAMETER(ecReadOnly);
static const GUID *rgModeBiasProperties[] =
{
&GUID_PROP_MODEBIAS
};
static const GUID *rgAttrProperties[] =
{
&GUID_PROP_ATTRIBUTE,
};
CEditSession2 *pes;
ESSTRUCT ess;
HRESULT hr;
BOOL fInWriteSession;
CICPriv *picp;
IEnumTfRanges *pEnumText = NULL;
ITfRange *pRange = NULL;
ULONG ulFetched = 0;
BOOL fCallES = fFalse;
BOOL fSelChanged = fFalse;
Assert(pic != NULL);
if (pic == NULL)
return S_OK; // error
pic->InWriteSession(GetTID(), &fInWriteSession);
if (fInWriteSession)
return S_OK; // own change.
picp = GetInputContextPriv(pic);
if (picp == NULL)
return S_OK; // error
if (picp->GetfTransaction())
return S_OK; // skip in transaction.
//////////////////////////////////////////////////////////////////////////
// Init to call ESCB_TEXTEVENT
ESStructInit(&ess, ESCB_TEXTEVENT);
// Call ESCB_TEXTEVENT callback only if GUID_PROP_MODEBIAS changed.
hr = pEditRecord->GetTextAndPropertyUpdates(0/*TF_GTP_INCL_TEXT*/, rgModeBiasProperties, ARRAYSIZE(rgModeBiasProperties), &pEnumText);
if (FAILED(hr) || pEnumText == NULL)
return S_OK;
if (pEnumText->Next(1, &pRange, &ulFetched) == S_OK)
{
SafeRelease(pRange);
// ModeBias changed.
ess.fBool = fTrue;
}
pEnumText->Release();
// Selection changed?
pEditRecord->GetSelectionStatus(&fSelChanged);
// If Attribute changed, set selection change true.
if (fSelChanged == fFalse)
{
hr = pEditRecord->GetTextAndPropertyUpdates(0/*TF_GTP_INCL_TEXT*/, rgAttrProperties, ARRAYSIZE(rgAttrProperties), &pEnumText);
if (FAILED(hr) || pEnumText == NULL)
return S_OK;
if (pEnumText->Next(1, &pRange, &ulFetched) == S_OK)
{
SafeRelease(pRange);
fSelChanged = fTrue;
}
pEnumText->Release();
}
// Perf: Call ES only if (ModeBias change) or (Selection changed and comp object exist)
// I guess calling ES is pretty much costing since sel change occurs for ever cursor move.
if (fSelChanged)
fSelChanged = (GetIPComposition(pic) != NULL) ? fTrue : fFalse;
// If ModeBias changed or Selection changed, then call ESCB_TEXTEVENT sink
if (ess.fBool || fSelChanged)
{
if ((pes = new CEditSession2( pic, this, &ess, _EditSessionCallback2 )) != NULL)
{
pes->Invoke(ES2_READWRITE | ES2_ASYNC, &hr);
pes->Release();
}
}
return S_OK;
}
/* O N S T A R T E D I T T R A N S A C T I O N */
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
HRESULT CKorIMX::OnStartEditTransaction(ITfContext *pic)
{
CICPriv *picp;
if (pic == NULL)
return S_OK; // error
picp = GetInputContextPriv(pic);
if (picp)
picp->SetfTransaction(fTrue);
return S_OK;
}
/* O N E N D E D I T T R A N S A C T I O N */
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
HRESULT CKorIMX::OnEndEditTransaction(ITfContext *pic)
{
BOOL ftran;
CICPriv *picp;
if (pic == NULL)
return S_OK; // error
picp = GetInputContextPriv(pic);
if (picp)
{
ftran = picp->GetfTransaction();
if (ftran)
{
CEditSession2 *pes;
ESSTRUCT ess;
HRESULT hr;
picp->SetfTransaction(fFalse);
ESStructInit(&ess, ESCB_TEXTEVENT);
ess.pEnumRange = NULL;
if ((pes = new CEditSession2( pic, this, &ess, _EditSessionCallback2 )) != NULL)
{
pes->Invoke(ES2_READWRITE | ES2_ASYNC, &hr);
pes->Release();
}
}
}
return S_OK;
}