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.
 
 
 
 
 
 

3270 lines
97 KiB

/*++
Copyright (c) 2001, Microsoft Corporation
Module Name:
editses.cpp
Abstract:
This file implements the EditSession Class.
Author:
Revision History:
Notes:
--*/
#include "private.h"
#include "editses.h"
#include "compstr.h"
#include "reconvps.h"
#include "delay.h"
#include "profile.h"
/////////////////////////////////////////////////////////////////////////////
// ImmIfEditSessionCallBack
HRESULT
ImmIfEditSessionCallBack::GetAllTextRange(
TfEditCookie ec,
Interface_Attach<ITfContext>& ic,
Interface<ITfRange>* range,
LONG* lpTextLength,
TF_HALTCOND* lpHaltCond
)
{
ITfRange *rangeFull = NULL;
HRESULT hr;
BOOL fFound = FALSE;
BOOL fIsReadOnlyRange = FALSE;
ITfProperty *prop;
ITfRange *rangeTmp;
LONG cch;
//
// init lpTextLength first.
//
*lpTextLength = 0;
//
// Create the range that covers all the text.
//
if (FAILED(hr=ic->GetStart(ec, &rangeFull)))
return hr;
if (FAILED(hr=rangeFull->ShiftEnd(ec, LONG_MAX, &cch, lpHaltCond)))
return hr;
//
// find the first non readonly range in the text store.
//
if (SUCCEEDED(ic->GetProperty(GUID_PROP_MSIMTF_READONLY, &prop)))
{
IEnumTfRanges *enumranges;
if (SUCCEEDED(prop->EnumRanges(ec, &enumranges, rangeFull)))
{
while(!fFound && (enumranges->Next(1, &rangeTmp, NULL) == S_OK))
{
VARIANT var;
QuickVariantInit(&var);
prop->GetValue(ec, rangeTmp, &var);
if ((var.vt == VT_EMPTY) || (var.lVal == 0))
{
fFound = TRUE;
hr = rangeTmp->Clone(*range);
rangeTmp->Release();
break;
}
fIsReadOnlyRange = TRUE;
rangeTmp->Release();
VariantClear(&var);
}
enumranges->Release();
}
prop->Release();
}
if (FAILED(hr))
return hr;
if (!fFound)
{
if (fIsReadOnlyRange)
{
//
// all text store is readonly. So we just return an empty range.
//
if (FAILED(hr = GetSelectionSimple(ec, ic.GetPtr(), *range)))
return hr;
if (FAILED(hr = (*range)->Collapse(ec, TF_ANCHOR_START)))
return hr;
}
else
{
if (FAILED(hr = rangeFull->Clone(*range)))
return hr;
*lpTextLength = cch;
}
}
else
{
if (SUCCEEDED((*range)->Clone(&rangeTmp)))
{
BOOL fEmpty;
WCHAR wstr[256 + 1];
ULONG ul = 0;
while (rangeTmp->IsEmpty(ec, &fEmpty) == S_OK && !fEmpty)
{
ULONG ulcch;
rangeTmp->GetText(ec,
TF_TF_MOVESTART,
wstr,
ARRAYSIZE(wstr) - 1,
&ulcch);
ul += ulcch;
}
rangeTmp->Release();
*lpTextLength = (LONG)ul;
}
}
SafeRelease(rangeFull);
return S_OK;
}
HRESULT
ImmIfEditSessionCallBack::SetTextInRange(
TfEditCookie ec,
ITfRange* range,
LPWSTR psz,
DWORD len,
CicInputContext& CicContext
)
{
CicContext.m_fModifyingDoc.SetFlag();
//
// Set the text in Cicero TOM
//
HRESULT hr = range->SetText(ec, 0, psz, len);
CicContext.m_fModifyingDoc.ResetFlag();
return hr;
}
HRESULT
ImmIfEditSessionCallBack::ClearTextInRange(
TfEditCookie ec,
ITfRange* range,
CicInputContext& CicContext
)
{
//
// Clear the text in Cicero TOM
//
return SetTextInRange(ec, range, NULL, 0, CicContext);
}
HRESULT
ImmIfEditSessionCallBack::GetReadingString(
TfEditCookie ec,
Interface_Attach<ITfContext>& ic,
CWCompString& reading_string,
CWCompClause& reading_clause
)
{
HRESULT hr;
Interface<ITfRange> range;
LONG l;
if (FAILED(hr=GetAllTextRange(ec, ic, &range, &l)))
return hr;
return GetReadingString(ec, ic, range, reading_string, reading_clause);
}
HRESULT
ImmIfEditSessionCallBack::GetReadingString(
TfEditCookie ec,
Interface_Attach<ITfContext>& ic,
ITfRange* range,
CWCompString& reading_string,
CWCompClause& reading_clause
)
{
HRESULT hr;
EnumReadingPropertyArgs args;
if (FAILED(hr=ic->GetProperty(GUID_PROP_READING, args.Property)))
return hr;
Interface<IEnumTfRanges> EnumReadingProperty;
hr = args.Property->EnumRanges(ec, EnumReadingProperty, range);
if (FAILED(hr))
return hr;
args.ec = ec;
args.reading_string = &reading_string;
args.reading_clause = &reading_clause;
args.ulClausePos = (reading_clause.GetSize() > 0 ? reading_clause[ reading_clause.GetSize() - 1]
: 0);
CEnumrateInterface<IEnumTfRanges,
ITfRange,
EnumReadingPropertyArgs> Enumrate(EnumReadingProperty,
EnumReadingPropertyCallback,
&args); // Argument of callback func.
Enumrate.DoEnumrate();
return S_OK;
}
//
// Enumrate callbacks
//
/* static */
ENUM_RET
ImmIfEditSessionCallBack::EnumReadingPropertyCallback(
ITfRange* pRange,
EnumReadingPropertyArgs *pargs
)
{
ENUM_RET ret = ENUM_CONTINUE;
VARIANT var;
QuickVariantInit(&var);
HRESULT hr = pargs->Property->GetValue(pargs->ec, pRange, &var);
if (SUCCEEDED(hr)) {
if (V_VT(&var) == VT_BSTR) {
BSTR bstr = V_BSTR(&var);
LONG cch = SysStringLen(bstr);
pargs->reading_string->AddCompData(bstr, cch);
if (pargs->reading_clause->GetSize() == 0)
pargs->reading_clause->Add(0);
pargs->reading_clause->Add( pargs->ulClausePos += cch );
}
VariantClear(&var);
}
return ret;
}
HRESULT
ImmIfEditSessionCallBack::CompClauseToResultClause(
IMCLock& imc,
CWCompClause& result_clause,
UINT cch
)
{
LONG num_of_written;
// Check GCS_COMPCLAUSE office set
IMCCLock<COMPOSITIONSTRING> lpCompStr(imc->hCompStr);
if (lpCompStr.Invalid())
return E_FAIL;
if (lpCompStr->dwCompClauseOffset > lpCompStr->dwSize)
return E_FAIL;
if (lpCompStr->dwCompClauseOffset + lpCompStr->dwCompClauseLen > lpCompStr->dwSize)
return E_FAIL;
if (num_of_written=ImmGetCompositionStringW((HIMC)imc,
GCS_COMPCLAUSE,
NULL,
0)) {
DWORD* buffer = new DWORD[ num_of_written / sizeof(DWORD) ];
if (buffer != NULL) {
num_of_written = ImmGetCompositionStringW((HIMC)imc,
GCS_COMPCLAUSE,
buffer,
num_of_written);
int idx = num_of_written / sizeof(DWORD);
if (idx > 1)
{
idx -= 1;
if (buffer[idx] == cch)
{
result_clause.WriteCompData(buffer, num_of_written / sizeof(DWORD));
}
else
{
// this is the case comp clause is corrupted
// it is the least we can do for the failure case
buffer[0] = 0;
buffer[1] = cch;
result_clause.WriteCompData(buffer, 2);
}
}
delete [] buffer;
}
}
return S_OK;
}
HRESULT
ImmIfEditSessionCallBack::CheckStrClauseAndReadClause(
CWCompClause& str_clause,
CWCompClause& reading_clause,
LONG cch
)
{
if (str_clause.GetSize() == reading_clause.GetSize())
return S_OK;
//
// string clause and reading clause is not much size of buffer array.
// some office application expect that two clause should the same buffer length.
//
str_clause.RemoveAll();
reading_clause.RemoveAll();
str_clause.Add(0);
str_clause.Add(cch);
reading_clause.Add(0);
reading_clause.Add(cch);
return S_OK;
}
//
// Get cursor position
//
HRESULT
ImmIfEditSessionCallBack::_GetCursorPosition(
TfEditCookie ec,
IMCLock& imc,
CicInputContext& CicContext,
Interface_Attach<ITfContext>& ic,
CWCompCursorPos& CompCursorPos,
CWCompAttribute& CompAttr
)
{
TLS* ptls = TLS::GetTLS();
if (ptls == NULL)
{
return E_OUTOFMEMORY;
}
LANGID langid;
CicProfile* _pProfile = ptls->GetCicProfile();
if (_pProfile == NULL)
{
DebugMsg(TF_ERROR, TEXT("ImmIfEditSessionCallBack::_GetCursorPosition. _pProfile==NULL."));
return E_FAIL;
}
_pProfile->GetLangId(&langid);
CicInputContext::IME_QUERY_POS qpos = CicInputContext::IME_QUERY_POS_UNKNOWN;
if (CicContext.m_fStartComposition.IsSetFlag()) {
//
// This method should not call before sending WM_IME_STARTCOMPOSITION
// because some apps confusing to receive QUERYCHARPOSITION due to
// no composing.
//
CicContext.InquireIMECharPosition(langid, imc, &qpos);
}
//
// Is apps support "query positioning" ?
//
DWORD dwImeCompatFlags = ImmGetAppCompatFlags((HIMC)imc);
if (((dwImeCompatFlags & IMECOMPAT_AIMM_LEGACY_CLSID) || (dwImeCompatFlags & IMECOMPAT_AIMM12_TRIDENT)) &&
(qpos != CicInputContext::IME_QUERY_POS_YES) &&
MsimtfIsWindowFiltered(imc->hWnd)) {
//
// IE5.0 candidate window positioning code.
// They except of it position from COMPOSITIONSTRING.dwCursorPos.
//
INT_PTR ich = 0;
if (_FindCompAttr(CompAttr, ATTR_TARGET_CONVERTED, &ich) == S_OK)
{
CompCursorPos.Set((DWORD)ich);
return S_OK;
}
}
//
// Japanese IME cursor position behavior.
//
if (PRIMARYLANGID(langid) == LANG_JAPANESE)
{
IME_UIWND_STATE uists;
uists = UIComposition::InquireImeUIWndState(imc);
if (CicContext.m_fStartComposition.IsSetFlag() &&
// even close CandidateWindow, cursor position should move to ATTR_TARGET_CONVERTED
//
// CicContext.m_fOpenCandidateWindow.IsSetFlag() &&
uists == IME_UIWND_LEVEL3 &&
qpos == CicInputContext::IME_QUERY_POS_NO)
{
INT_PTR ich = 0;
if (_FindCompAttr(CompAttr, ATTR_TARGET_CONVERTED, &ich) == S_OK)
{
CompCursorPos.Set((DWORD)ich);
return S_OK;
}
}
}
HRESULT hr;
Interface_TFSELECTION sel;
ULONG cFetched;
if (SUCCEEDED(hr = ic->GetSelection(ec, TF_DEFAULT_SELECTION, 1, sel, &cFetched))) {
Interface<ITfRange> start;
LONG ich;
TF_HALTCOND hc;
hc.pHaltRange = sel->range;
hc.aHaltPos = (sel->style.ase == TF_AE_START) ? TF_ANCHOR_START : TF_ANCHOR_END;
hc.dwFlags = 0;
if (SUCCEEDED(hr=GetAllTextRange(ec, ic, &start, &ich, &hc))) {
CompCursorPos.Set(ich);
}
}
return hr;
}
HRESULT
ImmIfEditSessionCallBack::_FindCompAttr(
CWCompAttribute& CompAttr,
BYTE bAttr,
INT_PTR* pich)
{
INT_PTR ich = 0;
INT_PTR attr_size;
if (attr_size = CompAttr.GetSize()) {
while (ich < attr_size && CompAttr[ich] != bAttr)
ich++;
if (ich < attr_size) {
*pich = ich;
return S_OK;
}
}
return S_FALSE;
}
//
// Get text and attribute in given range
//
// ITfRange::range
// TF_ANCHOR_START
// |======================================================================|
// +--------------------+ #+----------+
// |ITfRange::pPropRange| #|pPropRange|
// +--------------------+ #+----------+
// | GUID_ATOM | #
// +--------------------+ #
// ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^#
// ITfRange::gap_range gap_range #
// #
// V
// ITfRange::no_display_attribute_range
// result_comp
// +1 <- 0 -> -1
//
HRESULT
ImmIfEditSessionCallBack::_GetTextAndAttribute(
LIBTHREAD *pLibTLS,
TfEditCookie ec,
IMCLock& imc,
CicInputContext& CicContext,
Interface_Attach<ITfContext>& ic,
Interface<ITfRange>& rangeIn,
CWCompString& CompStr,
CWCompAttribute& CompAttr,
CWCompClause& CompClause,
CWCompTfGuidAtom& CompGuid,
CWCompString& CompReadStr,
CWCompClause& CompReadClause,
CWCompString& ResultStr,
CWCompClause& ResultClause,
CWCompString& ResultReadStr,
CWCompClause& ResultReadClause,
BOOL bInWriteSession
)
{
//
// Get no display attribute range if there exist.
// Otherwise, result range is the same to input range.
//
LONG result_comp;
Interface<ITfRange> no_display_attribute_range;
if (FAILED(rangeIn->Clone(no_display_attribute_range)))
return E_FAIL;
const GUID* guids[] = {&GUID_PROP_COMPOSING,
&GUID_PROP_MSIMTF_PREPARE_RECONVERT};
const int guid_size = sizeof(guids) / sizeof(GUID*);
if (FAILED(_GetNoDisplayAttributeRange(pLibTLS,
ec,
ic,
rangeIn,
guids, guid_size,
no_display_attribute_range)))
return E_FAIL;
IME_UIWND_STATE uists;
uists = UIComposition::InquireImeUIWndState(imc);
Interface<ITfReadOnlyProperty> propComp;
Interface<IEnumTfRanges> enumComp;
HRESULT hr;
if (FAILED(hr = ic->TrackProperties(guids, guid_size, // system property
NULL, 0, // application property
propComp)))
return FALSE;
if (FAILED(hr = propComp->EnumRanges(ec, enumComp, rangeIn)))
return hr;
CompClause.Add(0); // setup composition clause at 0
ResultClause.Add(0); // setup result clause at 0
Interface<ITfRange> range;
while(enumComp->Next(1, range, NULL) == S_OK)
{
VARIANT var;
BOOL fCompExist = FALSE;
hr = propComp->GetValue(ec, range, &var);
if (S_OK == hr)
{
Interface<IEnumTfPropertyValue> EnumPropVal;
hr = var.punkVal->QueryInterface(IID_IEnumTfPropertyValue, EnumPropVal);
if (SUCCEEDED(hr)) {
TF_PROPERTYVAL tfPropertyVal;
while (EnumPropVal->Next(1, &tfPropertyVal, NULL) == S_OK) {
for (int i=0; i < guid_size; i++) {
if (IsEqualGUID(tfPropertyVal.guidId, *guids[i])) {
if ((V_VT(&tfPropertyVal.varValue) == VT_I4 && V_I4(&tfPropertyVal.varValue) != 0)) {
fCompExist = TRUE;
break;
}
}
}
VariantClear(&tfPropertyVal.varValue);
if (fCompExist)
break;
}
}
}
VariantClear(&var);
ULONG ulNumProp;
//
// Get display attribute track property range
//
Interface<IEnumTfRanges> enumProp;
Interface<ITfReadOnlyProperty> prop;
if (FAILED(GetDisplayAttributeTrackPropertyRange(ec, ic.GetPtr(), range, prop, enumProp, &ulNumProp))) {
return E_FAIL;
}
// use text range for get text
Interface<ITfRange> textRange;
if (FAILED(range->Clone(textRange)))
return E_FAIL;
// use text range for gap text (no property range).
Interface<ITfRange> gap_range;
if (FAILED(range->Clone(gap_range)))
return E_FAIL;
ITfRange* pPropRange = NULL;
while (enumProp->Next(1, &pPropRange, NULL) == S_OK) {
// pick up the gap up to the next property
gap_range->ShiftEndToRange(ec, pPropRange, TF_ANCHOR_START);
//
// GAP range
//
no_display_attribute_range->CompareStart(ec,
gap_range,
TF_ANCHOR_START,
&result_comp);
_GetTextAndAttributeGapRange(pLibTLS,
ec,
uists,
CicContext,
gap_range,
result_comp,
CompStr, CompAttr, CompClause, CompGuid,
ResultStr, ResultClause);
//
// Get display attribute data if some GUID_ATOM exist.
//
TF_DISPLAYATTRIBUTE da;
TfGuidAtom guidatom = TF_INVALID_GUIDATOM;
GetDisplayAttributeData(pLibTLS, ec, prop, pPropRange, &da, &guidatom, ulNumProp);
//
// Property range
//
no_display_attribute_range->CompareStart(ec,
pPropRange,
TF_ANCHOR_START,
&result_comp);
// Adjust GAP range's start anchor to the end of proprty range.
gap_range->ShiftStartToRange(ec, pPropRange, TF_ANCHOR_END);
//
// Get reading string from property.
//
if (fCompExist == TRUE && result_comp <= 0)
GetReadingString(ec, ic, pPropRange, CompReadStr, CompReadClause);
else
GetReadingString(ec, ic, pPropRange, ResultReadStr, ResultReadClause);
//
// Get property text
//
_GetTextAndAttributePropertyRange(pLibTLS,
ec,
imc,
uists,
CicContext,
pPropRange,
fCompExist,
result_comp,
bInWriteSession,
da,
guidatom,
CompStr, CompAttr, CompClause, CompGuid,
ResultStr, ResultClause);
SafeReleaseClear(pPropRange);
} // while
// the last non-attr
textRange->ShiftStartToRange(ec, gap_range, TF_ANCHOR_START);
textRange->ShiftEndToRange(ec, range, TF_ANCHOR_END);
LONG ulClausePos = 0;
BOOL fEmpty;
while (textRange->IsEmpty(ec, &fEmpty) == S_OK && !fEmpty)
{
WCHAR wstr0[256 + 1];
ULONG ulcch0 = ARRAYSIZE(wstr0) - 1;
textRange->GetText(ec, TF_TF_MOVESTART, wstr0, ulcch0, &ulcch0);
TfGuidAtom guidatom;
guidatom = TF_INVALID_GUIDATOM;
TF_DISPLAYATTRIBUTE da;
da.bAttr = TF_ATTR_INPUT;
CompGuid.AddCompData(guidatom, ulcch0);
CompAttr.AddCompData(_ConvertAttributeToImm32(uists, da.bAttr), ulcch0);
CompStr.AddCompData(wstr0, ulcch0);
ulClausePos += ulcch0;
}
if (ulClausePos) {
DWORD last_clause;
if (CompClause.GetSize() > 0) {
last_clause = CompClause[ CompClause.GetSize() - 1 ];
CompClause.Add( last_clause + ulClausePos );
}
}
textRange->Collapse(ec, TF_ANCHOR_END);
range->Release();
*(ITfRange **)(range) = NULL;
} // out-most while for GUID_PROP_COMPOSING
//
// Fix up empty comp clause
//
if (CompClause.GetSize() <= 1)
{
CompClause.RemoveAll();
CompReadClause.RemoveAll();
}
else
{
//
// Check StrClause and ReadClause
//
// #578666
// we should not break CompClause if there is no reading string.
//
if (CompReadStr.GetSize())
CheckStrClauseAndReadClause(CompClause, CompReadClause, (LONG)CompStr.GetSize());
}
//
// Fix up empty result clause
//
if (ResultClause.GetSize() <= 1)
{
ResultClause.RemoveAll();
ResultReadClause.RemoveAll();
}
else
{
//
// Check StrClause and ReadClause
//
CheckStrClauseAndReadClause(ResultClause, ResultReadClause, (LONG)ResultStr.GetSize());
}
//
// set GUID_PROP_MSIMTF_TRACKCOMPOSITION
//
Interface<ITfProperty> PropertyTrackComposition;
if (SUCCEEDED(ic->GetProperty(GUID_PROP_MSIMTF_TRACKCOMPOSITION,
PropertyTrackComposition)))
{
VARIANT var;
var.vt = VT_I4;
var.lVal = 1;
PropertyTrackComposition->SetValue(ec, rangeIn, &var);
}
return S_OK;
}
//
// Retrieve text from gap range
//
HRESULT
ImmIfEditSessionCallBack::_GetTextAndAttributeGapRange(
LIBTHREAD *pLibTLS,
TfEditCookie ec,
IME_UIWND_STATE uists,
CicInputContext& CicContext,
Interface<ITfRange>& gap_range,
LONG result_comp,
CWCompString& CompStr,
CWCompAttribute& CompAttr,
CWCompClause& CompClause,
CWCompTfGuidAtom& CompGuid,
CWCompString& ResultStr,
CWCompClause& ResultClause
)
{
TfGuidAtom guidatom;
guidatom = TF_INVALID_GUIDATOM;
TF_DISPLAYATTRIBUTE da;
da.bAttr = TF_ATTR_INPUT;
ULONG ulClausePos = 0;
BOOL fEmpty;
WCHAR wstr0[256 + 1];
ULONG ulcch0;
while (gap_range->IsEmpty(ec, &fEmpty) == S_OK && !fEmpty)
{
Interface<ITfRange> backup_range;
if (FAILED(gap_range->Clone(backup_range)))
return E_FAIL;
//
// Retrieve gap text if there exist.
//
ulcch0 = ARRAYSIZE(wstr0) - 1;
if (FAILED(gap_range->GetText(ec,
TF_TF_MOVESTART, // Move range to next after get text.
wstr0,
ulcch0, &ulcch0)))
return E_FAIL;
ulClausePos += ulcch0;
if (result_comp <= 0) {
CompGuid.AddCompData(guidatom, ulcch0);
CompAttr.AddCompData(_ConvertAttributeToImm32(uists, da.bAttr), ulcch0);
CompStr.AddCompData(wstr0, ulcch0);
}
else {
ResultStr.AddCompData(wstr0, ulcch0);
ClearTextInRange(ec, backup_range, CicContext);
}
}
if (ulClausePos) {
DWORD last_clause;
if (result_comp <= 0) {
if (CompClause.GetSize() > 0) {
last_clause = CompClause[ CompClause.GetSize() - 1 ];
CompClause.Add( last_clause + ulClausePos );
}
}
else {
if (ResultClause.GetSize() > 0) {
last_clause = ResultClause[ ResultClause.GetSize() - 1 ];
ResultClause.Add( last_clause + ulClausePos );
}
}
}
return S_OK;
}
//
// Retrieve text from property range
//
HRESULT
ImmIfEditSessionCallBack::_GetTextAndAttributePropertyRange(
LIBTHREAD *pLibTLS,
TfEditCookie ec,
IMCLock& imc,
IME_UIWND_STATE uists,
CicInputContext& CicContext,
ITfRange* pPropRange,
BOOL fCompExist,
LONG result_comp,
BOOL bInWriteSession,
TF_DISPLAYATTRIBUTE da,
TfGuidAtom guidatom,
CWCompString& CompStr,
CWCompAttribute& CompAttr,
CWCompClause& CompClause,
CWCompTfGuidAtom& CompGuid,
CWCompString& ResultStr,
CWCompClause& ResultClause
)
{
ULONG ulClausePos = 0;
BOOL fEmpty;
WCHAR wstr0[256 + 1];
ULONG ulcch0;
while (pPropRange->IsEmpty(ec, &fEmpty) == S_OK && !fEmpty)
{
Interface<ITfRange> backup_range;
if (FAILED(pPropRange->Clone(backup_range)))
return E_FAIL;
//
// Retrieve property text if there exist.
//
ulcch0 = ARRAYSIZE(wstr0) - 1;
if (FAILED(pPropRange->GetText(ec,
TF_TF_MOVESTART, // Move range to next after get text.
wstr0,
ulcch0, &ulcch0)))
return E_FAIL;
ulClausePos += ulcch0; // we only need to addup the char position for clause info
// see if there is a valid disp attribute
if (fCompExist == TRUE && result_comp <= 0)
{
if (guidatom == TF_INVALID_GUIDATOM) {
da.bAttr = TF_ATTR_INPUT;
}
CompGuid.AddCompData(guidatom, ulcch0);
CompAttr.AddCompData(_ConvertAttributeToImm32(uists, da.bAttr), ulcch0);
CompStr.AddCompData(wstr0, ulcch0);
}
else if (bInWriteSession)
{
// if there's no disp attribute attached, it probably means
// the part of string is finalized.
//
ResultStr.AddCompData(wstr0, ulcch0);
// it was a 'determined' string
// so the doc has to shrink
//
ClearTextInRange(ec, backup_range, CicContext);
}
else
{
//
// Prevent infinite loop
//
break;
}
}
if (ulClausePos) {
DWORD last_clause;
if (fCompExist == TRUE && result_comp <= 0) {
if (CompClause.GetSize() > 0) {
last_clause = CompClause[ CompClause.GetSize() - 1 ];
CompClause.Add( last_clause + ulClausePos );
}
}
else if (result_comp == 0) {
//
// Copy CompClause data to ResultClause
//
CompClauseToResultClause(imc, ResultClause, ulcch0);
}
else {
if (ResultClause.GetSize() > 0) {
last_clause = ResultClause[ ResultClause.GetSize() - 1 ];
ResultClause.Add( last_clause + ulClausePos );
}
}
}
return S_OK;
}
HRESULT
ImmIfEditSessionCallBack::_GetNoDisplayAttributeRange(
LIBTHREAD *pLibTLS,
TfEditCookie ec,
Interface_Attach<ITfContext>& ic,
Interface<ITfRange>& rangeIn,
const GUID** guids,
const int guid_size,
Interface<ITfRange>& no_display_attribute_range
)
{
Interface<ITfReadOnlyProperty> propComp;
Interface<IEnumTfRanges> enumComp;
HRESULT hr = ic->TrackProperties(guids, guid_size, // system property
NULL, 0, // application property
propComp);
if (FAILED(hr))
return hr;
hr = propComp->EnumRanges(ec, enumComp, rangeIn);
if (FAILED(hr))
return hr;
ITfRange *pRange;
while(enumComp->Next(1, &pRange, NULL) == S_OK)
{
VARIANT var;
BOOL fCompExist = FALSE;
hr = propComp->GetValue(ec, pRange, &var);
if (S_OK == hr)
{
Interface<IEnumTfPropertyValue> EnumPropVal;
hr = var.punkVal->QueryInterface(IID_IEnumTfPropertyValue, EnumPropVal);
if (SUCCEEDED(hr)) {
TF_PROPERTYVAL tfPropertyVal;
while (EnumPropVal->Next(1, &tfPropertyVal, NULL) == S_OK) {
for (int i=0; i < guid_size; i++) {
if (IsEqualGUID(tfPropertyVal.guidId, *guids[i])) {
if ((V_VT(&tfPropertyVal.varValue) == VT_I4 && V_I4(&tfPropertyVal.varValue) != 0)) {
fCompExist = TRUE;
break;
}
}
}
VariantClear(&tfPropertyVal.varValue);
if (fCompExist)
break;
}
}
}
if (!fCompExist) {
// Adjust GAP range's start anchor to the end of proprty range.
no_display_attribute_range->ShiftStartToRange(ec, pRange, TF_ANCHOR_START);
}
VariantClear(&var);
pRange->Release();
}
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfEditSession::_Init
void
ImmIfEditSession::_Init(
ESCB escb
)
{
m_pfnCallback = EditSessionCallBack;
m_cRef = 1;
m_ImmIfCallBack = NULL;
switch(escb) {
case ESCB_HANDLETHISKEY:
m_ImmIfCallBack = new ImmIfHandleThisKey(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_COMPCOMPLETE:
m_ImmIfCallBack = new ImmIfCompositionComplete(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_COMPCANCEL:
m_ImmIfCallBack = new ImmIfCompositionCancel(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_UPDATECOMPOSITIONSTRING:
m_ImmIfCallBack = new ImmIfUpdateCompositionString(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_REPLACEWHOLETEXT:
m_ImmIfCallBack = new ImmIfReplaceWholeText(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_RECONVERTSTRING:
m_ImmIfCallBack = new ImmIfReconvertString(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_CLEARDOCFEEDBUFFER:
m_ImmIfCallBack = new ImmIfClearDocFeedBuffer(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_GETTEXTANDATTRIBUTE:
m_ImmIfCallBack = new ImmIfGetTextAndAttribute(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_QUERYRECONVERTSTRING:
m_ImmIfCallBack = new ImmIfQueryReconvertString(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_CALCRANGEPOS:
m_ImmIfCallBack = new ImmIfCalcRangePos(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_GETSELECTION:
m_ImmIfCallBack = new ImmIfGetSelection(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_GET_READONLY_PROP_MARGIN:
m_ImmIfCallBack = new ImmIfGetReadOnlyPropMargin(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_GET_CURSOR_POSITION:
m_ImmIfCallBack = new ImmIfGetCursorPosition(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_GET_ALL_TEXT_RANGE:
m_ImmIfCallBack = new ImmIfGetAllTextRange(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
case ESCB_REMOVE_PROPERTY:
m_ImmIfCallBack = new ImmIfRemoveProperty(m_state.hIMC, m_tid, m_ic, m_pLibTLS);
break;
}
}
ImmIfEditSession::~ImmIfEditSession(
)
{
if (m_ImmIfCallBack)
delete m_ImmIfCallBack;
}
bool
ImmIfEditSession::Valid(
)
{
return (m_ic.Valid()) ? true : false;
}
// ImmIfEditSession::ITfEditCallback method
STDAPI
ImmIfEditSession::DoEditSession(
TfEditCookie ec
)
{
return m_pfnCallback(ec, this);
}
// ImmIfEditSession::IUnknown
STDAPI
ImmIfEditSession::QueryInterface(
REFIID riid,
void** ppvObj
)
{
*ppvObj = NULL;
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_ITfEditSession)) {
*ppvObj = SAFECAST(this, ImmIfEditSession*);
}
if (*ppvObj) {
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDAPI_(ULONG)
ImmIfEditSession::AddRef(
)
{
return ++m_cRef;
}
STDAPI_(ULONG)
ImmIfEditSession::Release(
)
{
long cr;
cr = --m_cRef;
Assert(cr >= 0);
if (cr == 0) {
delete this;
}
return cr;
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfHandleThisKey
HRESULT
ImmIfHandleThisKey::HandleThisKey(
TfEditCookie ec,
UINT uVKey,
HIMC hIMC,
Interface_Attach<ITfContext> ic
)
{
Interface_TFSELECTION sel;
BOOL fEmpty;
ULONG cFetched;
HRESULT hr;
IMCLock imc(hIMC);
if (FAILED(hr=imc.GetResult()))
return hr;
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(hr=imc_ctfime.GetResult()))
return hr;
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
ASSERT(_pCicContext != NULL);
//
// Finalize the composition string
//
if (uVKey == VK_RETURN) {
return EscbCompComplete(imc, TRUE);
}
else if (uVKey == VK_ESCAPE) {
return EscbCompCancel(imc);
}
//
// Keys that change its behavior on selection
//
if (ic->GetSelection(ec, TF_DEFAULT_SELECTION, 1, sel, &cFetched) != S_OK)
return E_FAIL;
sel->range->IsEmpty(ec, &fEmpty);
if (!fEmpty) {
//
// Selection is not empty.
//
switch (uVKey) {
case VK_BACK:
case VK_DELETE:
//
// Delete the selection
//
ClearTextInRange(ec, sel->range, *_pCicContext);
return EscbUpdateCompositionString(imc);
}
}
// Determine if current range is vertical writing
ITfReadOnlyProperty *pProperty = NULL;
BOOL fVertical = FALSE;
if (SUCCEEDED(ic->GetAppProperty(TSATTRID_Text_Orientation, &pProperty)) && pProperty )
{
VARIANT var;
if (pProperty->GetValue(ec, sel->range, &var) == S_OK )
{
fVertical = (var.lVal == 2700) ? TRUE : FALSE;
}
pProperty->Release();
VariantClear(&var);
}
int nShift;
switch (uVKey) {
case VK_BACK:
// Make selection
if (SUCCEEDED(ShiftSelectionToLeft(ec, sel->range, 1, false))) {
// Clear the current selection
if (SUCCEEDED(ClearTextInRange(ec, sel->range, *_pCicContext))) {
return EscbUpdateCompositionString(imc);
}
}
break;
case VK_DELETE:
if (SUCCEEDED(ShiftSelectionToRight(ec, sel->range, 1, false))) {
if (SUCCEEDED(ClearTextInRange(ec, sel->range, *_pCicContext))) {
return EscbUpdateCompositionString(imc);
}
}
break;
case VK_HOME:
nShift = 0x7fffffff;
goto ShiftLeft;
case VK_UP:
nShift = 1;
if (!fVertical)
break;
goto ShiftLeft;
case VK_LEFT:
nShift = 1;
if (fVertical)
break;
ShiftLeft:
sel->style.ase = TF_AE_START;
if (::GetKeyState(VK_CONTROL) >= 0) {
if (SUCCEEDED(ShiftSelectionToLeft(ec,
sel->range,
nShift,
::GetKeyState(VK_SHIFT) >= 0 ? true : false)) &&
SUCCEEDED(ic->SetSelection(ec, 1, sel))) {
return EscbUpdateCompositionString(imc);
}
}
break;
case VK_END:
nShift = 0x7fffffff;
goto ShiftRight;
case VK_DOWN:
nShift = 1;
if (!fVertical)
break;
goto ShiftRight;
case VK_RIGHT:
nShift = 1;
if (fVertical)
break;
ShiftRight:
sel->style.ase = TF_AE_END;
if (::GetKeyState(VK_CONTROL) >= 0) {
if (SUCCEEDED(ShiftSelectionToRight(ec,
sel->range,
nShift,
::GetKeyState(VK_SHIFT) >= 0 ? true : false)) &&
SUCCEEDED(ic->SetSelection(ec, 1, sel))) {
return EscbUpdateCompositionString(imc);
}
}
break;
}
return E_FAIL;
}
HRESULT
ImmIfHandleThisKey::ShiftSelectionToLeft(
TfEditCookie ec,
ITfRange *range,
int nShift,
bool fShiftEnd
)
{
LONG cch;
if (SUCCEEDED(range->ShiftStart(ec, 0-nShift, &cch, NULL))) {
HRESULT hr = S_OK;
if (fShiftEnd) {
hr = range->Collapse(ec, TF_ANCHOR_START);
}
return hr;
}
return E_FAIL;
}
HRESULT
ImmIfHandleThisKey::ShiftSelectionToRight(
TfEditCookie ec,
ITfRange *range,
int nShift,
bool fShiftStart
)
{
LONG cch;
if (SUCCEEDED(range->ShiftEnd(ec, nShift, &cch, NULL))) {
HRESULT hr = S_OK;
if (fShiftStart) {
hr = range->Collapse(ec, TF_ANCHOR_END);
}
return hr;
}
return E_FAIL;
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfCompositionComplete
HRESULT
ImmIfCompositionComplete::CompComplete(
TfEditCookie ec,
HIMC hIMC,
BOOL fTerminateComp,
Interface_Attach<ITfContext> ic
)
{
HRESULT hr;
if (fTerminateComp == TRUE)
{
Interface<ITfContextOwnerCompositionServices> icocs;
hr = ic->QueryInterface(IID_ITfContextOwnerCompositionServices, (void **)icocs);
if (S_OK == hr)
{
icocs->TerminateComposition(NULL);
}
}
IMCLock imc(hIMC);
if (FAILED(hr = imc.GetResult()))
return hr;
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(hr = imc_ctfime.GetResult()))
return hr;
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
if (_pCicContext == NULL)
return E_FAIL;
//
// we're doing CompComplete now. So stop recurse calls.
//
if (_pCicContext->m_fInCompComplete.IsSetFlag())
return S_OK;
//
// Get the whole text, finalize it, and set empty string in TOM
//
Interface<ITfRange> start;
LONG cch;
if (SUCCEEDED(hr=GetAllTextRange(ec, ic, &start, &cch))) {
//
// If there is no string in TextStore and we havenot sent
// WM_IME_STARTCOMPOSITION, we don't have to do anything.
//
if (!cch) {
if (_pCicContext->m_fStartComposition.IsResetFlag())
return S_OK;
}
LPWSTR wstr = new WCHAR[ cch + 1 ];
if (!wstr)
return E_OUTOFMEMORY;
Interface<ITfProperty> prop;
//
// Get the whole text, finalize it, and erase the whole text.
//
if (SUCCEEDED(start->GetText(ec, TF_TF_IGNOREEND, wstr, (ULONG)cch, (ULONG*)&cch))) {
//
// Make Result String.
//
CWCompString ResultStr(hIMC, wstr, cch);
CWCompString ResultReadStr;
CWCompClause ResultReadClause;
CWCompClause ResultClause;
if (cch) {
//
// Get reading string from property.
//
GetReadingString(ec, ic, ResultReadStr, ResultReadClause);
//
// Copy CompClause data to ResultClause
//
CompClauseToResultClause(imc, ResultClause, cch);
//
// Check StrClause and ReadClause
//
CheckStrClauseAndReadClause(ResultClause, ResultReadClause, cch);
}
//
// Prevent reentrance call of CPS_COMPLETE.
//
_pCicContext->m_fInCompComplete.SetFlag();
//
// set composition string
//
hr = _SetCompositionString(imc,
*_pCicContext,
&ResultStr, &ResultClause,
&ResultReadStr, &ResultReadClause);
if (SUCCEEDED(hr))
{
_pCicContext->GenerateMessage(imc);
}
_pCicContext->m_fInCompComplete.ResetFlag();
//
// Clear the TOM
//
if (SUCCEEDED(hr))
{
hr = ClearTextInRange(ec, start, *_pCicContext);
}
//
// Bug#493094
// Clear the composition list here if it isn't removed yet.
//
if (fTerminateComp == FALSE)
{
Interface<ITfContextOwnerCompositionServices> icocs;
hr = ic->QueryInterface(IID_ITfContextOwnerCompositionServices, (void **)icocs);
if (S_OK == hr)
{
icocs->TerminateComposition(NULL);
}
}
}
delete [] wstr;
}
else {
EscbCompCancel(imc);
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfCompositionCancel
HRESULT
ImmIfCompositionCancel::CompCancel(
TfEditCookie ec,
HIMC hIMC,
Interface_Attach<ITfContext> ic
)
{
HRESULT hr;
IMCLock imc(hIMC);
if (FAILED(hr = imc.GetResult()))
return hr;
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(hr = imc_ctfime.GetResult()))
return hr;
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
if (_pCicContext == NULL)
return E_FAIL;
ASSERT(_pCicContext != NULL);
LANGID langid = LANG_NEUTRAL;
//
// TLS doesn't inherit in edit session.
//
TLS* ptls = TLS::GetTLS();
if (ptls != NULL)
{
CicProfile* _pProfile = ptls->GetCicProfile();
if (_pProfile != NULL)
{
_pProfile->GetLangId(&langid);
}
}
if (_pCicContext->m_fStartComposition.IsSetFlag()) {
CCompStrFactory comp(imc->hCompStr);
if (SUCCEEDED(hr = comp.GetResult())) {
if (FAILED(hr = comp.ClearCompositionString()))
return hr;
TRANSMSG msg;
msg.message = WM_IME_COMPOSITION;
if ((PRIMARYLANGID(langid) != LANG_JAPANESE))
{
msg.wParam = (WPARAM)VK_ESCAPE;
msg.lParam = (LPARAM)(GCS_COMPREAD | GCS_COMP | GCS_CURSORPOS | GCS_DELTASTART);
}
else
{
//
// #509247
//
// Some apps don't accept lParam without compstr in hIMC.
//
msg.wParam = 0;
msg.lParam = 0;
}
if (_pCicContext->m_pMessageBuffer)
_pCicContext->m_pMessageBuffer->SetData(msg);
_pCicContext->m_fStartComposition.ResetFlag();
msg.message = WM_IME_ENDCOMPOSITION;
msg.wParam = (WPARAM) 0;
msg.lParam = (LPARAM) 0;
if (_pCicContext->m_pMessageBuffer)
_pCicContext->m_pMessageBuffer->SetData(msg);
//
// Clear the text in Cicero TOM
//
Interface<ITfRange> range;
LONG l;
if (SUCCEEDED(GetAllTextRange(ec, ic, &range, &l))) {
hr = ClearTextInRange(ec, range, *_pCicContext);
}
}
_pCicContext->GenerateMessage(imc);
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfUpdateCompositionString
HRESULT
ImmIfUpdateCompositionString::UpdateCompositionString(
TfEditCookie ec,
HIMC hIMC,
Interface_Attach<ITfContext> ic,
DWORD dwDeltaStart,
TfClientId ClientId,
LIBTHREAD* pLibTLS
)
{
HRESULT hr;
IMCLock imc(hIMC);
if (FAILED(hr = imc.GetResult()))
return hr;
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(hr = imc_ctfime.GetResult()))
return hr;
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
if (_pCicContext == NULL)
return E_FAIL;
BOOL bInWriteSession;
if (FAILED(hr = ic->InWriteSession(ClientId, &bInWriteSession)))
return hr;
Interface<ITfRange> FullTextRange;
LONG lTextLength;
if (FAILED(hr=GetAllTextRange(ec, ic, &FullTextRange, &lTextLength)))
return hr;
//
// Prevent reentrance call of CPS_COMPLETE.
//
_pCicContext->m_fInUpdateComposition.SetFlag();
Interface<ITfRange> InterimRange;
BOOL fInterim = FALSE;
if (FAILED(hr = _IsInterimSelection(ec, ic, &InterimRange, &fInterim)))
return hr;
if (fInterim) {
hr = _MakeInterimString(pLibTLS,
ec, imc, *_pCicContext, ic, FullTextRange,
InterimRange, lTextLength,
bInWriteSession);
}
else {
hr = _MakeCompositionString(pLibTLS,
ec, imc, *_pCicContext, ic, FullTextRange,
dwDeltaStart,
bInWriteSession);
}
_pCicContext->m_fInUpdateComposition.ResetFlag();
return hr;
}
HRESULT
ImmIfUpdateCompositionString::_IsInterimSelection(
TfEditCookie ec,
Interface_Attach<ITfContext>& ic,
Interface<ITfRange>* pInterimRange,
BOOL *pfInterim
)
{
Interface_TFSELECTION sel;
ULONG cFetched;
*pfInterim = FALSE;
if (ic->GetSelection(ec, TF_DEFAULT_SELECTION, 1, sel, &cFetched) != S_OK)
{
// no selection. we can return S_OK.
return S_OK;
}
if (sel->style.fInterimChar) {
HRESULT hr;
if (FAILED(hr = sel->range->Clone(*pInterimRange)))
return hr;
*pfInterim = TRUE;
}
return S_OK;
}
HRESULT
ImmIfUpdateCompositionString::_MakeCompositionString(
LIBTHREAD *pLibTLS,
TfEditCookie ec,
IMCLock& imc,
CicInputContext& CicContext,
Interface_Attach<ITfContext>& ic,
Interface<ITfRange>& FullTextRange,
DWORD dwDeltaStart,
BOOL bInWriteSession
)
{
HRESULT hr;
CWCompString CompStr;
CWCompAttribute CompAttr;
CWCompClause CompClause;
CWCompTfGuidAtom CompGuid;
CWCompCursorPos CompCursorPos;
CWCompDeltaStart CompDeltaStart;
CWCompString CompReadStr;
CWCompClause CompReadClause;
CWCompString ResultStr;
CWCompClause ResultClause;
CWCompString ResultReadStr;
CWCompClause ResultReadClause;
if (FAILED(hr = _GetTextAndAttribute(pLibTLS, ec, imc, CicContext, ic, FullTextRange,
CompStr, CompAttr, CompClause,
CompGuid,
CompReadStr, CompReadClause,
ResultStr, ResultClause,
ResultReadStr, ResultReadClause,
bInWriteSession
))) {
return hr;
}
if (FAILED(hr = _GetCursorPosition(ec, imc, CicContext, ic, CompCursorPos, CompAttr))) {
return hr;
}
if (FAILED(hr = _GetDeltaStart(CompDeltaStart, CompStr, dwDeltaStart))) {
return hr;
}
//
// Clear the GUID attribute map array
//
CicContext.ClearGuidMap();
BOOL bBufferOverflow = FALSE;
// handle result string
hr = _SetCompositionString(imc,
CicContext,
&CompStr, &CompAttr, &CompClause,
&CompCursorPos, &CompDeltaStart,
&CompGuid,
&bBufferOverflow,
&CompReadStr,
&ResultStr, &ResultClause,
&ResultReadStr, &ResultReadClause);
if (SUCCEEDED(hr))
{
//
// Map the GUID attribute array
//
CicContext.MapAttributes(imc);
//
// Send message to aplication
//
CicContext.GenerateMessage(imc);
}
if (SUCCEEDED(hr) && bBufferOverflow) {
//
// Buffer overflow in COMPOSITIONSTRING.compstr[NMAXKEY],
// Then, Clear the TOM
//
//
// Get the whole text, finalize it, and set empty string in TOM
//
Interface<ITfRange> start;
LONG cch;
if (SUCCEEDED(hr=GetAllTextRange(ec, ic, &start, &cch))) {
hr = ClearTextInRange(ec, start, CicContext);
}
}
return hr;
}
HRESULT
ImmIfUpdateCompositionString::_MakeInterimString(
LIBTHREAD *pLibTLS,
TfEditCookie ec,
IMCLock& imc,
CicInputContext& CicContext,
Interface_Attach<ITfContext>& ic,
Interface<ITfRange>& FullTextRange,
Interface<ITfRange>& InterimRange,
LONG lTextLength,
BOOL bInWriteSession
)
{
LONG lStartResult;
LONG lEndResult;
FullTextRange->CompareStart(ec, InterimRange, TF_ANCHOR_START, &lStartResult);
if (lStartResult > 0) {
return E_FAIL;
}
FullTextRange->CompareEnd(ec, InterimRange, TF_ANCHOR_END, &lEndResult);
if (lEndResult < 0) {
return E_FAIL;
}
if (lEndResult > 1) {
return E_FAIL;
}
HRESULT hr = S_OK;
CWInterimString InterimStr((HIMC)imc);
if (lStartResult < 0) {
//
// Make result string.
//
#if 0
BOOL fEqual;
do {
LONG cch;
FullTextRange->ShiftEnd(ec, -1, &cch, NULL);
if (cch == 0) {
return E_FAIL;
}
lTextLength -= abs(cch);
FullTextRange->IsEqualEnd(ec, InterimRange, TF_ANCHOR_START, &fEqual);
} while(! fEqual);
#endif
if (FAILED(hr=FullTextRange->ShiftEndToRange(ec, InterimRange, TF_ANCHOR_START)))
return hr;
//
// Interim char assume 1 char length.
// Full text length - 1 means result string length.
//
lTextLength --;
ASSERT(lTextLength > 0);
if (lTextLength > 0) {
LPWSTR wstr = new WCHAR[ lTextLength + 1 ];
//
// Get the result text, finalize it, and erase the result text.
//
if (SUCCEEDED(FullTextRange->GetText(ec, TF_TF_IGNOREEND, wstr, (ULONG)lTextLength, (ULONG*)&lTextLength))) {
//
// Clear the TOM
//
if (SUCCEEDED(hr = ClearTextInRange(ec, FullTextRange, CicContext))) {
InterimStr.WriteCompData(wstr, lTextLength);
}
}
delete [] wstr;
}
}
//
// Make interim character
//
CWCompString CompStr;
CWCompAttribute CompAttr;
CWCompClause CompClause;
CWCompTfGuidAtom CompGuid;
CWCompString CompReadStr;
CWCompClause CompReadClause;
CWCompString ResultStr;
CWCompClause ResultClause;
CWCompString ResultReadStr;
CWCompClause ResultReadClause;
if (FAILED(hr = _GetTextAndAttribute(pLibTLS, ec, imc, CicContext, ic, InterimRange,
CompStr, CompAttr, CompClause,
CompGuid,
CompReadStr, CompReadClause,
ResultStr, ResultClause,
ResultReadStr, ResultReadClause,
bInWriteSession
))) {
return hr;
}
WCHAR ch = L'\0';
BYTE attr = 0;
if (CompStr.GetSize() > 0) {
CompStr.ReadCompData(&ch, 1);
}
if (CompAttr.GetSize() > 0) {
CompAttr.ReadCompData(&attr, 1);
}
InterimStr.WriteInterimChar(ch, attr);
hr = _SetCompositionString(imc, CicContext, &InterimStr);
if (SUCCEEDED(hr))
{
CicContext.GenerateMessage(imc);
}
return hr;
}
//
// Get delta start
//
HRESULT
ImmIfUpdateCompositionString::_GetDeltaStart(
CWCompDeltaStart& CompDeltaStart,
CWCompString& CompStr,
DWORD dwDeltaStart
)
{
if (dwDeltaStart < (DWORD)CompStr.GetSize())
CompDeltaStart.Set(dwDeltaStart); // Set COMPOSITIONSTRING.dwDeltaStart.
else
CompDeltaStart.Set(0);
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfReplaceWholeText
HRESULT
ImmIfReplaceWholeText::ReplaceWholeText(
TfEditCookie ec,
HIMC hIMC,
Interface_Attach<ITfContext> ic,
CWCompString* lpwCompStr
)
{
HRESULT hr;
IMCLock imc(hIMC);
if (FAILED(hr = imc.GetResult()))
return hr;
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(hr = imc_ctfime.GetResult()))
return hr;
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
if (_pCicContext == NULL)
return E_FAIL;
DWORD dwSize = (DWORD)lpwCompStr->GetSize();
LPWSTR lpszComp = new WCHAR[dwSize + 1];
if (!lpszComp)
return hr;
lpwCompStr->ReadCompData(lpszComp, dwSize + 1);
lpszComp[dwSize] = L'\0';
Interface<ITfRange> whole;
LONG cch;
if (SUCCEEDED(hr=GetAllTextRange(ec, ic, &whole, &cch))) {
Interface<ITfContextComposition> icc;
hr = ic->QueryInterface(IID_ITfContextComposition, (void **)icc);
if (hr == S_OK)
{
Interface<ITfComposition> composition;
hr = icc->StartComposition(ec, whole, _pCicContext, composition);
if (hr == S_OK)
{
hr = SetTextInRange(ec, whole, lpszComp, dwSize, *_pCicContext);
}
}
}
delete [] lpszComp;
return hr;
}
void SetReadOnlyRange(TfEditCookie ec,
Interface_Attach<ITfContext> ic,
ITfRange *range,
BOOL fSet)
{
ITfProperty *prop;
if (SUCCEEDED(ic->GetProperty(GUID_PROP_MSIMTF_READONLY, &prop)))
{
if (fSet)
{
VARIANT var;
var.vt = VT_I4;
var.lVal = 1;
prop->SetValue(ec, range, &var);
}
else
{
prop->Clear(ec, range);
}
prop->Release();
}
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfReconvertString
HRESULT
ImmIfReconvertString::ReconvertString(
TfEditCookie ec,
HIMC hIMC,
Interface_Attach<ITfContext> ic,
Interface<ITfRange>* rangeSrc,
BOOL fDocFeedOnly,
CWReconvertString* lpwReconvStr
)
/*+++
LPRECONVERTSTRING structure:
+00 DWORD dwSize // Sizeof data (include this structure size) with byte count.
+04 DWORD dwVersion
+08 DWORD dwStrLen // String length with character count.
+0C DWORD dwStrOffset // Offset from start of this structure with byte count.
+10 DWORD dwCompStrLen // Comp Str length with character count.
+14 DWORD dwCompStrOffset // Offset from this->dwStrOffset with byte count.
+18 DWORD dwTargetStrLen // Target Str length with character count.
+1C DWORD dwTargetStrOffset // Offset from this->dwStrOffset with byte count.
+20
---*/
{
HRESULT hr = E_FAIL;
IMCLock imc(hIMC);
if (FAILED(hr = imc.GetResult()))
return hr;
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(hr = imc_ctfime.GetResult()))
return hr;
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
if (_pCicContext == NULL)
return E_FAIL;
DWORD dwLen;
dwLen = lpwReconvStr->ReadCompData();
if (dwLen) {
LPRECONVERTSTRING lpReconvertString;
lpReconvertString = (LPRECONVERTSTRING) new BYTE[ dwLen ];
if (lpReconvertString == NULL)
return hr;
lpwReconvStr->ReadCompData(lpReconvertString, dwLen);
if (lpReconvertString->dwStrLen) {
hr = ic->GetStart(ec, *rangeSrc);
if (SUCCEEDED(hr)) {
LONG cch;
hr = (*rangeSrc)->ShiftEnd(ec, LONG_MAX, &cch, NULL);
SetReadOnlyRange(ec, ic, *rangeSrc, FALSE);
BOOL fSkipSetText = FALSE;
if (SUCCEEDED(hr)) {
Interface<ITfRange> rangeOrgSelection;
if (lpReconvertString->dwCompStrLen)
{
WCHAR *pwstr = NULL;
ULONG ul = 0;
Interface<ITfRange> rangeTmp;
if (SUCCEEDED((*rangeSrc)->Clone(rangeTmp)))
{
UINT uSize = lpReconvertString->dwCompStrLen + 2;
pwstr = new WCHAR[uSize + 1];
if (pwstr)
{
ULONG ulcch;
rangeTmp->GetText(ec, 0, pwstr, uSize, &ulcch);
if ((lpReconvertString->dwCompStrLen == ulcch) &&
!memcmp(((LPBYTE)lpReconvertString +
lpReconvertString->dwStrOffset +
lpReconvertString->dwCompStrOffset),
pwstr,
lpReconvertString->dwCompStrLen * sizeof(WCHAR)))
fSkipSetText = TRUE;
delete [] pwstr;
}
}
if (!fSkipSetText && fDocFeedOnly)
{
TraceMsg(TF_WARNING, "ImmIfReconvertString::ReconvertString the current text store does not match with the string from App.");
goto Exit;
}
if (!fSkipSetText)
{
hr = SetTextInRange(ec,
*rangeSrc,
(LPWSTR)((LPBYTE)lpReconvertString +
lpReconvertString->dwStrOffset +
lpReconvertString->dwCompStrOffset),
lpReconvertString->dwCompStrLen,
*_pCicContext);
if (S_OK == hr)
{
//
// set GUID_PROP_MSIMTF_PREPARE_RECONVERT
//
Interface<ITfProperty> PropertyPrepareReconvert;
if (SUCCEEDED(ic->GetProperty(GUID_PROP_MSIMTF_PREPARE_RECONVERT,
PropertyPrepareReconvert)))
{
//
// create CReconvertPropStore
//
Interface_Creator<CReconvertPropStore> reconvps(new CReconvertPropStore(GUID_PROP_MSIMTF_PREPARE_RECONVERT, VT_I4, 1));
if (reconvps.Valid())
{
PropertyPrepareReconvert->SetValueStore(ec, *rangeSrc, reconvps);
}
}
}
}
else
{
GetSelectionSimple(ec, ic.GetPtr(), rangeOrgSelection);
hr = S_OK;
}
}
else
{
BOOL fEmpty;
if (SUCCEEDED((*rangeSrc)->IsEmpty(ec, &fEmpty)) && !fEmpty)
{
if (fDocFeedOnly)
{
DebugMsg(TF_WARNING, TEXT("ImmIfReconvertString::ReconvertString the current text store does not match with the string from App."));
goto Exit;
}
hr = ClearTextInRange(ec, *rangeSrc, *_pCicContext);
}
}
//
// set read only string
//
if (lpReconvertString->dwCompStrOffset)
{
//
// keep rangeSrc and rangeOrgSelection
//
(*rangeSrc)->SetGravity(ec,
TF_GRAVITY_FORWARD,
TF_GRAVITY_FORWARD);
if (rangeOrgSelection.Valid())
rangeOrgSelection->SetGravity(ec,
TF_GRAVITY_FORWARD,
TF_GRAVITY_FORWARD);
Interface<ITfRange> rangeStart;
if (SUCCEEDED((*rangeSrc)->Clone(rangeStart)))
{
if (SUCCEEDED(rangeStart->Collapse(ec, TF_ANCHOR_START)))
{
rangeStart->SetGravity(ec,
TF_GRAVITY_BACKWARD,
TF_GRAVITY_FORWARD);
hr = SetTextInRange(ec,
rangeStart,
(LPWSTR)((LPBYTE)lpReconvertString +
lpReconvertString->dwStrOffset),
lpReconvertString->dwCompStrOffset / sizeof(WCHAR),
*_pCicContext);
if (SUCCEEDED(hr))
SetReadOnlyRange(ec, ic, rangeStart, TRUE);
}
}
}
if ((lpReconvertString->dwCompStrOffset + lpReconvertString->dwCompStrLen * sizeof(WCHAR)) < lpReconvertString->dwStrLen * sizeof(WCHAR))
{
//
// keep rangeSrc and rangeOrgSelection
//
(*rangeSrc)->SetGravity(ec,
TF_GRAVITY_BACKWARD,
TF_GRAVITY_BACKWARD);
if (rangeOrgSelection.Valid())
rangeOrgSelection->SetGravity(ec,
TF_GRAVITY_BACKWARD,
TF_GRAVITY_BACKWARD);
Interface<ITfRange> rangeEnd;
if (SUCCEEDED((*rangeSrc)->Clone(rangeEnd)))
{
if (SUCCEEDED(rangeEnd->Collapse(ec, TF_ANCHOR_END)))
{
rangeEnd->SetGravity(ec,
TF_GRAVITY_BACKWARD,
TF_GRAVITY_FORWARD);
hr = SetTextInRange(ec,
rangeEnd,
(LPWSTR)((LPBYTE)lpReconvertString +
lpReconvertString->dwStrOffset +
lpReconvertString->dwCompStrOffset +
(lpReconvertString->dwCompStrLen * sizeof(WCHAR))),
((lpReconvertString->dwStrLen * sizeof(WCHAR)) -
(lpReconvertString->dwCompStrOffset +
(lpReconvertString->dwCompStrLen * sizeof(WCHAR)))) / sizeof(WCHAR),
*_pCicContext);
if (SUCCEEDED(hr))
SetReadOnlyRange(ec, ic, rangeEnd, TRUE);
}
}
}
(*rangeSrc)->SetGravity(ec,
TF_GRAVITY_FORWARD,
TF_GRAVITY_BACKWARD);
//
// we just set a selection to the target string.
//
Interface<ITfRange> range;
if (fSkipSetText)
{
if (rangeOrgSelection.Valid())
{
//
//
//
TF_SELECTION sel;
sel.range = rangeOrgSelection;
sel.style.ase = TF_AE_NONE;
sel.style.fInterimChar = FALSE;
ic->SetSelection(ec, 1, &sel);
}
}
else if (SUCCEEDED((*rangeSrc)->Clone(range)))
{
LONG cchStart;
LONG cchEnd;
if (lpReconvertString->dwTargetStrOffset == 0 &&
lpReconvertString->dwTargetStrLen == 0 ) {
cchStart = lpReconvertString->dwCompStrOffset / sizeof(WCHAR);
cchEnd = lpReconvertString->dwCompStrOffset / sizeof(WCHAR) + lpReconvertString->dwCompStrLen;
}
else {
cchStart = (lpReconvertString->dwTargetStrOffset - lpReconvertString->dwCompStrOffset) / sizeof(WCHAR);
cchEnd = (lpReconvertString->dwTargetStrOffset - lpReconvertString->dwCompStrOffset) / sizeof(WCHAR) + lpReconvertString->dwTargetStrLen;
// cchStart = (lpReconvertString->dwTargetStrOffset) / sizeof(WCHAR);
// cchEnd = (lpReconvertString->dwTargetStrOffset) / sizeof(WCHAR) + lpReconvertString->dwTargetStrLen;
}
range->Collapse(ec, TF_ANCHOR_START);
//
// shift end first then shift start.
//
if ((SUCCEEDED(range->ShiftEnd(ec,
cchEnd,
&cch,
NULL))) &&
(SUCCEEDED(range->ShiftStart(ec,
cchStart,
&cch,
NULL))))
{
//
//
//
TF_SELECTION sel;
sel.range = range;
sel.style.ase = TF_AE_NONE;
sel.style.fInterimChar = FALSE;
ic->SetSelection(ec, 1, &sel);
}
}
//
// it's time to generate WM_IME_COMPOSITION.
//
// ReconvertString() should call UpdateCompositionString with SYNCHRONIZATION.
// ASync would happen time lag of send WM_IME_STARTCOMPOSITION and WM_IME_COMPOSITION.
// This time lag is broken candidate window positioning because
// IID_ITfFnReconversion::Reconvert might open candidate window immediately.
//
// This synchronization call just want generate WM_IME_STARTCOMPOSITION and WM_IME_COMPOSITION messages.
// ReconvertString() won't modify text store in the edit session.
//
EscbUpdateCompositionStringSync(imc);
}
}
}
Exit:
delete [] lpReconvertString;
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfClearDocFeedBuffer
HRESULT
ImmIfClearDocFeedBuffer::ClearDocFeedBuffer(
TfEditCookie ec,
HIMC hIMC,
Interface_Attach<ITfContext> ic
)
{
HRESULT hr = E_FAIL;
IMCLock imc(hIMC);
if (FAILED(hr = imc.GetResult()))
return hr;
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(hr = imc_ctfime.GetResult()))
return hr;
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
if (_pCicContext == NULL)
return E_FAIL;
ITfRange *rangeFull = NULL;
ITfProperty *prop;
ITfRange *rangeTmp;
LONG cch;
//
// Create the range that covers all the text.
//
if (FAILED(hr=ic->GetStart(ec, &rangeFull)))
return hr;
if (FAILED(hr=rangeFull->ShiftEnd(ec, LONG_MAX, &cch, NULL)))
return hr;
//
// find the first non readonly range in the text store.
//
if (SUCCEEDED(ic->GetProperty(GUID_PROP_MSIMTF_READONLY, &prop)))
{
IEnumTfRanges *enumranges;
if (SUCCEEDED(prop->EnumRanges(ec, &enumranges, rangeFull)))
{
while (enumranges->Next(1, &rangeTmp, NULL) == S_OK)
{
VARIANT var;
QuickVariantInit(&var);
prop->GetValue(ec, rangeTmp, &var);
if ((var.vt == VT_I4) && (var.lVal != 0))
{
prop->Clear(ec, rangeTmp);
ClearTextInRange(ec, rangeTmp, *_pCicContext);
}
rangeTmp->Release();
VariantClear(&var);
}
enumranges->Release();
}
prop->Release();
}
rangeFull->Release();
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfGetTextAndAttribute
HRESULT
ImmIfGetTextAndAttribute::GetTextAndAttribute(
TfEditCookie ec,
HIMC hIMC,
Interface_Attach<ITfContext> ic,
CWCompString* lpwCompString,
CWCompAttribute* lpwCompAttribute,
TfClientId ClientId,
LIBTHREAD* pLibTLS
)
{
HRESULT hr;
IMCLock imc(hIMC);
if (FAILED(hr = imc.GetResult()))
return hr;
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(hr = imc_ctfime.GetResult()))
return hr;
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
if (_pCicContext == NULL)
return E_FAIL;
BOOL bInWriteSession;
if (FAILED(hr = ic->InWriteSession(ClientId, &bInWriteSession)))
return hr;
Interface<ITfRange> FullTextRange;
LONG lTextLength;
if (FAILED(hr=GetAllTextRange(ec, ic, &FullTextRange, &lTextLength)))
return hr;
if (FAILED(hr = _GetTextAndAttribute(pLibTLS, ec, imc, *_pCicContext, ic,
FullTextRange,
*lpwCompString,
*lpwCompAttribute,
bInWriteSession))) {
return hr;
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfQueryReconvertString
HRESULT
ImmIfQueryReconvertString::QueryReconvertString(
TfEditCookie ec,
HIMC hIMC,
Interface_Attach<ITfContext> ic,
Interface<ITfRange>* rangeQuery,
CWReconvertString* lpwReconvStr
)
/*+++
LPRECONVERTSTRING structure:
+00 DWORD dwSize // Sizeof data (include this structure size) with byte count.
+04 DWORD dwVersion
+08 DWORD dwStrLen // String length with character count.
+0C DWORD dwStrOffset // Offset from start of this structure with byte count.
+10 DWORD dwCompStrLen // Comp Str length with character count.
+14 DWORD dwCompStrOffset // Offset from this->dwStrOffset with byte count.
+18 DWORD dwTargetStrLen // Target Str length with character count.
+1C DWORD dwTargetStrOffset // Offset from this->dwStrOffset with byte count.
+20
---*/
{
HRESULT hr = E_FAIL;
IMCLock imc(hIMC);
if (FAILED(hr = imc.GetResult()))
return hr;
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(hr = imc_ctfime.GetResult()))
return hr;
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
if (_pCicContext == NULL)
return E_FAIL;
DWORD dwLen;
dwLen = lpwReconvStr->ReadCompData();
if (dwLen) {
LPRECONVERTSTRING lpReconvertString;
lpReconvertString = (LPRECONVERTSTRING) new BYTE[ dwLen ];
if (lpReconvertString == NULL)
return hr;
lpwReconvStr->ReadCompData(lpReconvertString, dwLen);
if (lpReconvertString->dwStrLen) {
Interface<ITfRange> rangeSrc;
hr = ic->GetStart(ec, rangeSrc);
if (SUCCEEDED(hr)) {
LONG cch;
hr = rangeSrc->ShiftEnd(ec, LONG_MAX, &cch, NULL);
if (SUCCEEDED(hr)) {
hr = SetTextInRange(ec,
rangeSrc,
(LPWSTR)((LPBYTE)lpReconvertString +
lpReconvertString->dwStrOffset),
lpReconvertString->dwStrLen,
*_pCicContext);
//
// we just set a selection to the target string.
//
Interface<ITfRange> range;
if (SUCCEEDED(rangeSrc->Clone(range)))
{
LONG cchStart;
LONG cchEnd;
if (lpReconvertString->dwTargetStrOffset == 0 &&
lpReconvertString->dwTargetStrLen == 0 ) {
cchStart = lpReconvertString->dwCompStrOffset / sizeof(WCHAR);
cchEnd = lpReconvertString->dwCompStrOffset / sizeof(WCHAR) + lpReconvertString->dwCompStrLen;
}
else {
cchStart = lpReconvertString->dwTargetStrOffset / sizeof(WCHAR);
cchEnd = lpReconvertString->dwTargetStrOffset / sizeof(WCHAR) + lpReconvertString->dwTargetStrLen;
}
range->Collapse(ec, TF_ANCHOR_START);
//
// shift end first then shift start.
//
if ((SUCCEEDED(range->ShiftEnd(ec,
cchEnd,
&cch,
NULL))) &&
(SUCCEEDED(range->ShiftStart(ec,
cchStart,
&cch,
NULL))))
{
//
//
//
TF_SELECTION sel;
sel.range = range;
sel.style.ase = TF_AE_NONE;
sel.style.fInterimChar = FALSE;
ic->SetSelection(ec, 1, &sel);
hr = range->Clone(*rangeQuery);
}
}
}
}
}
delete [] lpReconvertString;
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfCalcRangePos
HRESULT
ImmIfCalcRangePos::CalcRangePos(
TfEditCookie ec,
Interface_Attach<ITfContext> ic,
Interface<ITfRange>* rangeSrc,
CWReconvertString* lpwReconvStr
)
{
HRESULT hr;
Interface<ITfRange> pFullRange;
hr = ic->GetStart(ec, pFullRange);
if (SUCCEEDED(hr)) {
lpwReconvStr->m_CompStrIndex = 0;
lpwReconvStr->m_TargetStrIndex = 0;
BOOL equal = FALSE;
while (SUCCEEDED(hr=(*rangeSrc)->IsEqualStart(ec, pFullRange, TF_ANCHOR_START, &equal)) &&
! equal) {
LONG cch;
hr = pFullRange->ShiftStart(ec, 1, &cch, NULL);
if (FAILED(hr))
break;
lpwReconvStr->m_CompStrIndex++;
lpwReconvStr->m_TargetStrIndex++;
}
if (S_OK == hr) {
lpwReconvStr->m_CompStrLen = 0;
lpwReconvStr->m_TargetStrLen = 0;
Interface<ITfRange> rangeTmp;
if (SUCCEEDED(hr=(*rangeSrc)->Clone(rangeTmp)))
{
BOOL fEmpty;
WCHAR wstr[256 + 1];
ULONG ul = 0;
while (rangeTmp->IsEmpty(ec, &fEmpty) == S_OK && !fEmpty)
{
ULONG ulcch;
rangeTmp->GetText(ec,
TF_TF_MOVESTART,
wstr,
ARRAYSIZE(wstr) - 1,
&ulcch);
ul += ulcch;
}
//
// Hack for Satori
// Satori receives empty range with Reconversion->QueryRange().
// Apps couldn't call reconversion.
//
if (ul == 0) {
ul++;
}
lpwReconvStr->m_CompStrLen = (LONG)ul;
lpwReconvStr->m_TargetStrLen = (LONG)ul;
}
}
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfGetSelection
HRESULT
ImmIfGetSelection::GetSelection(
TfEditCookie ec,
Interface_Attach<ITfContext> ic,
Interface<ITfRange>* rangeSrc
)
{
Interface_TFSELECTION sel;
ULONG cFetched;
if (ic->GetSelection(ec, TF_DEFAULT_SELECTION, 1, sel, &cFetched) != S_OK)
return E_FAIL;
return sel->range->Clone(*rangeSrc);
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfGetReadOnlyPropMargin
HRESULT
ImmIfGetReadOnlyPropMargin::GetReadOnlyPropMargin(
TfEditCookie ec,
Interface_Attach<ITfContext> ic,
Interface<ITfRangeACP>* rangeSrc,
LONG* cch
)
{
HRESULT hr;
Interface<ITfRange> range_readonly_prop;
*cch = 0;
//
// Create the range that covers start of text to rangeSrc.
//
if (FAILED(hr=ic->GetStart(ec, range_readonly_prop)))
return hr;
//
// if rangeSrc is NULL, we check whole ic.
//
if (rangeSrc)
{
if (FAILED(hr=range_readonly_prop->ShiftEndToRange(ec,
*rangeSrc,
TF_ANCHOR_START)))
return hr;
}
else
{
Interface<ITfRange> range_end;
if (FAILED(hr=ic->GetEnd(ec, range_end)))
return hr;
if (FAILED(hr=range_readonly_prop->ShiftEndToRange(ec,
range_end,
TF_ANCHOR_START)))
return hr;
}
//
// same ?
//
BOOL empty;
if (FAILED(hr=range_readonly_prop->IsEmpty(ec, &empty)))
return hr;
if (empty)
return S_OK;
//
// find the first non readonly range in the text store.
//
ITfProperty *prop;
if (SUCCEEDED(ic->GetProperty(GUID_PROP_MSIMTF_READONLY, &prop)))
{
IEnumTfRanges *enumranges;
if (SUCCEEDED(prop->EnumRanges(ec, &enumranges, range_readonly_prop)))
{
ITfRange *rangeTmp;
BOOL fFoundNotReadOnly = FALSE;
while (!fFoundNotReadOnly &&
(enumranges->Next(1, &rangeTmp, NULL) == S_OK))
{
VARIANT var;
QuickVariantInit(&var);
prop->GetValue(ec, rangeTmp, &var);
if ((var.vt == VT_I4) && (var.lVal != 0))
{
while (rangeTmp->IsEmpty(ec, &empty) == S_OK && !empty)
{
WCHAR wstr[256 + 1];
ULONG ulcch;
rangeTmp->GetText(ec,
TF_TF_MOVESTART,
wstr,
ARRAYSIZE(wstr) - 1,
&ulcch);
*cch += ulcch;
}
}
else
{
fFoundNotReadOnly = TRUE;
}
rangeTmp->Release();
VariantClear(&var);
}
enumranges->Release();
}
prop->Release();
}
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfGetCursorPosition
HRESULT
ImmIfGetCursorPosition::GetCursorPosition(
TfEditCookie ec,
HIMC hIMC,
Interface_Attach<ITfContext> ic,
CWCompCursorPos* lpwCursorPosition,
TfClientId ClientId,
LIBTHREAD* pLibTLS
)
{
HRESULT hr;
IMCLock imc(hIMC);
if (FAILED(hr = imc.GetResult()))
return hr;
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
if (FAILED(hr = imc_ctfime.GetResult()))
return hr;
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
if (_pCicContext == NULL)
return E_FAIL;
BOOL bInWriteSession;
if (FAILED(hr = ic->InWriteSession(ClientId, &bInWriteSession)))
return hr;
Interface<ITfRange> FullTextRange;
LONG lTextLength;
if (FAILED(hr=GetAllTextRange(ec, ic, &FullTextRange, &lTextLength)))
return hr;
CWCompString CompStr;
CWCompAttribute CompAttr;
if (FAILED(hr = _GetTextAndAttribute(pLibTLS, ec, imc, *_pCicContext, ic,
FullTextRange,
CompStr,
CompAttr,
bInWriteSession))) {
return hr;
}
if (FAILED(hr = _GetCursorPosition(ec, imc, *_pCicContext, ic, *lpwCursorPosition, CompAttr))) {
return hr;
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// ImmIfRemoveProperty
HRESULT
ImmIfRemoveProperty::RemoveProperty(
TfEditCookie ec,
Interface_Attach<ITfContext> ic,
const GUID* guid
)
{
HRESULT hr;
Interface<ITfProperty> prop;
if (SUCCEEDED(hr = ic->GetProperty(*guid, prop)))
{
prop->Clear(ec, NULL); // remove CReconvertPropStore object.
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbHandleThisKey
HRESULT
EscbHandleThisKey(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
UINT uVKey)
{
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_HANDLETHISKEY,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
return _pEditSession->RequestEditSession(TF_ES_READWRITE | TF_ES_SYNC,
uVKey);
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbUpdateCompositionString
HRESULT
EscbUpdateCompositionString(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
DWORD dwDeltaStart,
DWORD dwFlags)
{
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_UPDATECOMPOSITIONSTRING,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
//
// This method should not set synchronize mode becuase the edit session call back routine
// modify a text in the input context.
//
// Except ReconvertString()
//
return _pEditSession->RequestEditSession(TF_ES_READWRITE | dwFlags,
(UINT)dwDeltaStart);
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbCompCancel
HRESULT
EscbCompCancel(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS)
{
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_COMPCANCEL,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
return _pEditSession->RequestEditSession(TF_ES_READWRITE | TF_ES_SYNC);
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbCompComplete
HRESULT
EscbCompComplete(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
BOOL fSync)
{
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_COMPCOMPLETE,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
return _pEditSession->RequestEditSession(TF_ES_READWRITE | (fSync ? TF_ES_SYNC : 0),
fSync == TRUE);
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbReplaceWholeText
HRESULT
EscbReplaceWholeText(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
CWCompString* wCompString)
{
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_REPLACEWHOLETEXT,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
return _pEditSession->RequestEditSession(TF_ES_READWRITE | TF_ES_SYNC,
wCompString);
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbClearDocFeedBuffer
HRESULT
EscbClearDocFeedBuffer(
IMCLock& imc,
CicInputContext& CicContext,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
BOOL fSync)
{
HRESULT hr = E_FAIL;
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_CLEARDOCFEEDBUFFER,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
{
goto Exit;
}
CicContext.m_fInClearDocFeedEditSession.SetFlag();
hr = _pEditSession->RequestEditSession(TF_ES_READWRITE | (fSync ? TF_ES_SYNC : 0));
CicContext.m_fInClearDocFeedEditSession.ResetFlag();
Exit:
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbGetTextAndAttribute
HRESULT
EscbGetTextAndAttribute(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
CWCompString* wCompString,
CWCompAttribute* wCompAttribute)
{
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_GETTEXTANDATTRIBUTE,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
return _pEditSession->RequestEditSession(TF_ES_READ | TF_ES_SYNC,
wCompString, wCompAttribute);
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbGetCursorPosition
HRESULT
EscbGetCursorPosition(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
CWCompCursorPos* wCursorPosition)
{
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_GET_CURSOR_POSITION,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
return _pEditSession->RequestEditSession(TF_ES_READ | TF_ES_SYNC,
wCursorPosition);
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbGetSelection
HRESULT
EscbGetSelection(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
Interface<ITfRange>* selection)
{
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_GETSELECTION,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
return _pEditSession->RequestEditSession(TF_ES_READWRITE | TF_ES_SYNC,
selection);
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbGetStartEndSelection
HRESULT
EscbGetStartEndSelection(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
CWCompCursorPos& wStartSelection,
CWCompCursorPos& wEndSelection)
{
HRESULT hr;
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_GETSELECTION,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
Interface<ITfRange> Selection;
hr = _pEditSession->RequestEditSession(TF_ES_READ | TF_ES_SYNC,
&Selection);
if (S_OK == hr) {
//
// Calcurate start position of RangeNew on text store
//
Interface_Creator<ImmIfEditSession> _pEditSession2(
new ImmIfEditSession(ESCB_CALCRANGEPOS,
imc, tid, pic, pLibTLS)
);
if (_pEditSession2.Valid()) {
CWReconvertString wReconvStr(imc);
hr = _pEditSession2->RequestEditSession(TF_ES_READ | TF_ES_SYNC,
&wReconvStr, &Selection, FALSE);
if (S_OK == hr) {
wStartSelection.Set((DWORD) wReconvStr.m_CompStrIndex);
wEndSelection.Set((DWORD)(wReconvStr.m_CompStrIndex + wReconvStr.m_CompStrLen));
}
}
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbReconvertString
HRESULT
EscbReconvertString(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
CWReconvertString* wReconvertString,
Interface<ITfRange>* selection,
BOOL fDocFeedOnly)
{
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_RECONVERTSTRING,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
return _pEditSession->RequestEditSession(TF_ES_READWRITE | TF_ES_SYNC,
wReconvertString, selection, fDocFeedOnly);
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbQueryReconvertString
HRESULT
EscbQueryReconvertString(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
CWReconvertString* wReconvertString,
Interface<ITfRange>* selection)
{
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_QUERYRECONVERTSTRING,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
return _pEditSession->RequestEditSession(TF_ES_READWRITE | TF_ES_SYNC,
wReconvertString, selection, FALSE);
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbCalcRangePos
HRESULT
EscbCalcRangePos(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
CWReconvertString* wReconvertString,
Interface<ITfRange>* range)
{
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_CALCRANGEPOS,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
return _pEditSession->RequestEditSession(TF_ES_READ | TF_ES_SYNC,
wReconvertString, range, FALSE);
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbReadOnlyPropMargin
HRESULT
EscbReadOnlyPropMargin(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
Interface<ITfRangeACP>* range_acp,
LONG* pcch)
{
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_GET_READONLY_PROP_MARGIN,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
return _pEditSession->RequestEditSession(TF_ES_READ | TF_ES_SYNC,
range_acp, pcch);
}
/////////////////////////////////////////////////////////////////////////////
// Edit session friend
// EscbRemoveProperty
HRESULT
EscbRemoveProperty(
IMCLock& imc,
TfClientId tid,
Interface_Attach<ITfContext> pic,
LIBTHREAD* pLibTLS,
const GUID* guid)
{
Interface_Creator<ImmIfEditSession> _pEditSession(
new ImmIfEditSession(ESCB_REMOVE_PROPERTY,
imc, tid, pic, pLibTLS)
);
if (_pEditSession.Invalid())
return E_FAIL;
//
// This method should not set synchronize mode becuase the edit session call back routine
// modify a property in the input context.
//
return _pEditSession->RequestEditSession(TF_ES_READWRITE,
guid);
}