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.

2514 lines
75 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. editses.cpp
  5. Abstract:
  6. This file implements the EditSession Class.
  7. Author:
  8. Revision History:
  9. Notes:
  10. --*/
  11. #include "private.h"
  12. #include "ctffunc.h"
  13. #include "editses.h"
  14. #include "globals.h"
  15. #include "resource.h"
  16. #include "candpos.h"
  17. #include "proputil.h"
  18. /////////////////////////////////////////////////////////////////////////////
  19. // ImmIfEditSessionCallBack
  20. HRESULT
  21. ImmIfEditSessionCallBack::GetAllTextRange(
  22. TfEditCookie ec,
  23. Interface_Attach<ITfContext>& ic,
  24. Interface<ITfRange>* range,
  25. LONG* lpTextLength,
  26. TF_HALTCOND* lpHaltCond
  27. )
  28. {
  29. ITfRange *rangeFull = NULL;
  30. HRESULT hr;
  31. BOOL fFound = FALSE;
  32. BOOL fIsReadOnlyRange = FALSE;
  33. ITfProperty *prop;
  34. ITfRange *rangeTmp;
  35. LONG cch;
  36. //
  37. // init lpTextLength first.
  38. //
  39. *lpTextLength = 0;
  40. //
  41. // Create the range that covers all the text.
  42. //
  43. if (FAILED(hr=ic->GetStart(ec, &rangeFull)))
  44. return hr;
  45. if (FAILED(hr=rangeFull->ShiftEnd(ec, LONG_MAX, &cch, lpHaltCond)))
  46. return hr;
  47. //
  48. // find the first non readonly range in the text store.
  49. //
  50. if (SUCCEEDED(ic->GetProperty(GUID_PROP_MSIMTF_READONLY, &prop)))
  51. {
  52. IEnumTfRanges *enumranges;
  53. if (SUCCEEDED(prop->EnumRanges(ec, &enumranges, rangeFull)))
  54. {
  55. while(!fFound && (enumranges->Next(1, &rangeTmp, NULL) == S_OK))
  56. {
  57. VARIANT var;
  58. QuickVariantInit(&var);
  59. prop->GetValue(ec, rangeTmp, &var);
  60. if ((var.vt == VT_EMPTY) || (var.lVal == 0))
  61. {
  62. fFound = TRUE;
  63. hr = rangeTmp->Clone(*range);
  64. rangeTmp->Release();
  65. break;
  66. }
  67. fIsReadOnlyRange = TRUE;
  68. rangeTmp->Release();
  69. }
  70. enumranges->Release();
  71. }
  72. prop->Release();
  73. }
  74. if (FAILED(hr))
  75. return hr;
  76. if (!fFound)
  77. {
  78. if (fIsReadOnlyRange)
  79. {
  80. //
  81. // all text store is readonly. So we just return an empty range.
  82. //
  83. if (FAILED(hr = GetSelectionSimple(ec, ic.GetPtr(), *range)))
  84. return hr;
  85. if (FAILED(hr = (*range)->Collapse(ec, TF_ANCHOR_START)))
  86. return hr;
  87. }
  88. else
  89. {
  90. if (FAILED(hr = rangeFull->Clone(*range)))
  91. return hr;
  92. *lpTextLength = cch;
  93. }
  94. }
  95. else
  96. {
  97. *lpTextLength = 0;
  98. if (SUCCEEDED((*range)->Clone(&rangeTmp)))
  99. {
  100. BOOL fEmpty;
  101. WCHAR wstr[256 + 1];
  102. ULONG ul = 0;
  103. while (rangeTmp->IsEmpty(ec, &fEmpty) == S_OK && !fEmpty)
  104. {
  105. ULONG ulcch;
  106. rangeTmp->GetText(ec,
  107. TF_TF_MOVESTART,
  108. wstr,
  109. ARRAYSIZE(wstr) - 1,
  110. &ulcch);
  111. ul += ulcch;
  112. }
  113. rangeTmp->Release();
  114. *lpTextLength = (LONG)ul;
  115. }
  116. }
  117. SafeRelease(rangeFull);
  118. return S_OK;
  119. }
  120. HRESULT
  121. ImmIfEditSessionCallBack::SetTextInRange(
  122. TfEditCookie ec,
  123. ITfRange* range,
  124. LPWSTR psz,
  125. DWORD len,
  126. CAImeContext* pAImeContext
  127. )
  128. {
  129. pAImeContext->_fModifyingDoc = TRUE;
  130. //
  131. // Set the text in Cicero TOM
  132. //
  133. HRESULT hr = range->SetText(ec, 0, psz, len);
  134. pAImeContext->_fModifyingDoc = FALSE;
  135. return hr;
  136. }
  137. HRESULT
  138. ImmIfEditSessionCallBack::ClearTextInRange(
  139. TfEditCookie ec,
  140. ITfRange* range,
  141. CAImeContext* pAImeContext
  142. )
  143. {
  144. //
  145. // Clear the text in Cicero TOM
  146. //
  147. return SetTextInRange(ec, range, NULL, 0, pAImeContext);
  148. }
  149. HRESULT
  150. ImmIfEditSessionCallBack::GetReadingString(
  151. TfEditCookie ec,
  152. Interface_Attach<ITfContext>& ic,
  153. CWCompString& reading_string,
  154. CWCompClause& reading_clause
  155. )
  156. {
  157. HRESULT hr;
  158. Interface<ITfRange> range;
  159. LONG l;
  160. if (FAILED(hr=GetAllTextRange(ec, ic, &range, &l)))
  161. return hr;
  162. return GetReadingString(ec, ic, range, reading_string, reading_clause);
  163. }
  164. HRESULT
  165. ImmIfEditSessionCallBack::GetReadingString(
  166. TfEditCookie ec,
  167. Interface_Attach<ITfContext>& ic,
  168. ITfRange* range,
  169. CWCompString& reading_string,
  170. CWCompClause& reading_clause
  171. )
  172. {
  173. HRESULT hr;
  174. EnumReadingPropertyArgs args;
  175. if (FAILED(hr=ic->GetProperty(GUID_PROP_READING, args.Property)))
  176. return hr;
  177. Interface<IEnumTfRanges> EnumReadingProperty;
  178. hr = args.Property->EnumRanges(ec, EnumReadingProperty, range);
  179. if (FAILED(hr))
  180. return hr;
  181. args.ec = ec;
  182. args.reading_string = &reading_string;
  183. args.reading_clause = &reading_clause;
  184. args.ulClausePos = (reading_clause.GetSize() > 0 ? reading_clause[ reading_clause.GetSize() - 1]
  185. : 0);
  186. CEnumrateInterface<IEnumTfRanges,
  187. ITfRange,
  188. EnumReadingPropertyArgs> Enumrate(EnumReadingProperty,
  189. EnumReadingPropertyCallback,
  190. &args); // Argument of callback func.
  191. Enumrate.DoEnumrate();
  192. return S_OK;
  193. }
  194. //
  195. // Enumrate callbacks
  196. //
  197. /* static */
  198. ENUM_RET
  199. ImmIfEditSessionCallBack::EnumReadingPropertyCallback(
  200. ITfRange* pRange,
  201. EnumReadingPropertyArgs *pargs
  202. )
  203. {
  204. ENUM_RET ret = ENUM_CONTINUE;
  205. VARIANT var;
  206. QuickVariantInit(&var);
  207. HRESULT hr = pargs->Property->GetValue(pargs->ec, pRange, &var);
  208. if (SUCCEEDED(hr)) {
  209. if (V_VT(&var) == VT_BSTR) {
  210. BSTR bstr = V_BSTR(&var);
  211. LONG cch = SysStringLen(bstr);
  212. pargs->reading_string->AddCompData(bstr, cch);
  213. if (pargs->reading_clause->GetSize() == 0)
  214. pargs->reading_clause->Add(0);
  215. pargs->reading_clause->Add( pargs->ulClausePos += cch );
  216. }
  217. VariantClear(&var);
  218. }
  219. return ret;
  220. }
  221. HRESULT
  222. ImmIfEditSessionCallBack::CompClauseToResultClause(
  223. IMCLock& imc,
  224. CWCompClause& result_clause,
  225. UINT cch
  226. )
  227. {
  228. LONG num_of_written;
  229. IMTLS *ptls = IMTLS_GetOrAlloc();
  230. if (ptls && ptls->pAImm) {
  231. // Check GCS_COMPCLAUSE office set
  232. IMCCLock<COMPOSITIONSTRING> lpCompStr(imc->hCompStr);
  233. if (lpCompStr.Invalid())
  234. return E_FAIL;
  235. if (lpCompStr->dwCompClauseOffset > lpCompStr->dwSize)
  236. return E_FAIL;
  237. if (lpCompStr->dwCompClauseOffset + lpCompStr->dwCompClauseLen > lpCompStr->dwSize)
  238. return E_FAIL;
  239. if (SUCCEEDED(ptls->pAImm->GetCompositionStringW((HIMC)imc,
  240. GCS_COMPCLAUSE,
  241. 0, &num_of_written, NULL))) {
  242. DWORD* buffer = new DWORD[ num_of_written / sizeof(DWORD) ];
  243. if (buffer != NULL) {
  244. ptls->pAImm->GetCompositionStringW((HIMC)imc,
  245. GCS_COMPCLAUSE,
  246. num_of_written, &num_of_written, buffer);
  247. int idx = num_of_written / sizeof(DWORD);
  248. if (idx > 1)
  249. {
  250. idx -= 1;
  251. if (buffer[idx] == cch)
  252. {
  253. result_clause.WriteCompData(buffer, num_of_written / sizeof(DWORD));
  254. }
  255. else
  256. {
  257. // this is the case comp clause is corrupted
  258. // it is the least we can do for the failure case
  259. buffer[0] = 0;
  260. buffer[1] = cch;
  261. result_clause.WriteCompData(buffer, 2);
  262. }
  263. }
  264. delete [] buffer;
  265. }
  266. }
  267. }
  268. return S_OK;
  269. }
  270. //
  271. // Get cursor position
  272. //
  273. HRESULT
  274. ImmIfEditSessionCallBack::_GetCursorPosition(
  275. TfEditCookie ec,
  276. IMCLock& imc,
  277. Interface_Attach<ITfContext>& ic,
  278. CWCompCursorPos& CompCursorPos,
  279. CWCompAttribute& CompAttr
  280. )
  281. {
  282. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  283. if (_pAImeContext == NULL)
  284. return E_FAIL;
  285. CAImeContext::IME_QUERY_POS qpos = CAImeContext::IME_QUERY_POS_UNKNOWN;
  286. if (_pAImeContext->m_fStartComposition) {
  287. //
  288. // This method should not call before sending WM_IME_STARTCOMPOSITION
  289. // because some apps confusing to receive QUERYCHARPOSITION due to
  290. // no composing.
  291. //
  292. _pAImeContext->InquireIMECharPosition(imc, &qpos);
  293. }
  294. //
  295. // Is apps support "query positioning" ?
  296. //
  297. if ((g_fInLegacyClsid || g_fAIMM12Trident) &&
  298. qpos != CAImeContext::IME_QUERY_POS_YES) {
  299. //
  300. // IE5.0 candidate window positioning code.
  301. // They except of it position from COMPOSITIONSTRING.dwCursorPos.
  302. //
  303. INT_PTR ich = 0;
  304. INT_PTR attr_size;
  305. if (attr_size = CompAttr.GetSize()) {
  306. while (ich < attr_size && CompAttr[ich] != ATTR_TARGET_CONVERTED)
  307. ich++;
  308. if (ich < attr_size) {
  309. CompCursorPos.Set((DWORD)ich);
  310. return S_OK;
  311. }
  312. }
  313. }
  314. HRESULT hr;
  315. Interface_TFSELECTION sel;
  316. ULONG cFetched;
  317. if (SUCCEEDED(hr = ic->GetSelection(ec, TF_DEFAULT_SELECTION, 1, sel, &cFetched))) {
  318. Interface<ITfRange> start;
  319. LONG ich;
  320. TF_HALTCOND hc;
  321. hc.pHaltRange = sel->range;
  322. hc.aHaltPos = (sel->style.ase == TF_AE_START) ? TF_ANCHOR_START : TF_ANCHOR_END;
  323. hc.dwFlags = 0;
  324. if (SUCCEEDED(hr=GetAllTextRange(ec, ic, &start, &ich, &hc))) {
  325. CompCursorPos.Set(ich);
  326. }
  327. }
  328. return hr;
  329. }
  330. //
  331. // Get text and attribute in given range
  332. //
  333. // ITfRange::range
  334. // TF_ANCHOR_START
  335. // |======================================================================|
  336. // +--------------------+ #+----------+
  337. // |ITfRange::pPropRange| #|pPropRange|
  338. // +--------------------+ #+----------+
  339. // | GUID_ATOM | #
  340. // +--------------------+ #
  341. // ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^#
  342. // ITfRange::gap_range gap_range #
  343. // #
  344. // V
  345. // ITfRange::no_display_attribute_range
  346. // result_comp
  347. // +1 <- 0 -> -1
  348. //
  349. HRESULT
  350. ImmIfEditSessionCallBack::_GetTextAndAttribute(
  351. LIBTHREAD *pLibTLS,
  352. TfEditCookie ec,
  353. IMCLock& imc,
  354. Interface_Attach<ITfContext>& ic,
  355. Interface<ITfRange>& rangeIn,
  356. CWCompString& CompStr,
  357. CWCompAttribute& CompAttr,
  358. CWCompClause& CompClause,
  359. CWCompTfGuidAtom& CompGuid,
  360. CWCompString& CompReadStr,
  361. CWCompClause& CompReadClause,
  362. CWCompString& ResultStr,
  363. CWCompClause& ResultClause,
  364. CWCompString& ResultReadStr,
  365. CWCompClause& ResultReadClause,
  366. BOOL bInWriteSession
  367. )
  368. {
  369. //
  370. // Get no display attribute range if there exist.
  371. // Otherwise, result range is the same to input range.
  372. //
  373. LONG result_comp;
  374. Interface<ITfRange> no_display_attribute_range;
  375. if (FAILED(rangeIn->Clone(no_display_attribute_range)))
  376. return E_FAIL;
  377. if (FAILED(_GetNoDisplayAttributeRange(pLibTLS,
  378. ec,
  379. ic,
  380. rangeIn,
  381. no_display_attribute_range)))
  382. return E_FAIL;
  383. Interface<ITfProperty> propComp;
  384. Interface<IEnumTfRanges> enumComp;
  385. VARIANT var;
  386. HRESULT hr;
  387. if (FAILED(hr = ic->GetProperty(GUID_PROP_COMPOSING, propComp)))
  388. return hr;
  389. if (FAILED(hr = propComp->EnumRanges(ec, enumComp, rangeIn)))
  390. return hr;
  391. CompClause.Add(0); // setup composition clause at 0
  392. ResultClause.Add(0); // setup result clause at 0
  393. Interface<ITfRange> range;
  394. while(enumComp->Next(1, range, NULL) == S_OK)
  395. {
  396. BOOL fCompExist = FALSE;
  397. hr = propComp->GetValue(ec, range, &var);
  398. if (S_OK == hr)
  399. {
  400. if (var.vt == VT_I4 && var.lVal != 0)
  401. fCompExist = TRUE;
  402. }
  403. ULONG ulNumProp;
  404. //
  405. // Get display attribute track property range
  406. //
  407. Interface<IEnumTfRanges> enumProp;
  408. Interface<ITfReadOnlyProperty> prop;
  409. if (FAILED(GetDisplayAttributeTrackPropertyRange(ec, ic.GetPtr(), range, prop, enumProp, &ulNumProp))) {
  410. return E_FAIL;
  411. }
  412. // use text range for get text
  413. Interface<ITfRange> textRange;
  414. if (FAILED(range->Clone(textRange)))
  415. return E_FAIL;
  416. // use text range for gap text (no property range).
  417. Interface<ITfRange> gap_range;
  418. if (FAILED(range->Clone(gap_range)))
  419. return E_FAIL;
  420. ITfRange* pPropRange = NULL;
  421. while (enumProp->Next(1, &pPropRange, NULL) == S_OK) {
  422. // pick up the gap up to the next property
  423. gap_range->ShiftEndToRange(ec, pPropRange, TF_ANCHOR_START);
  424. //
  425. // GAP range
  426. //
  427. no_display_attribute_range->CompareStart(ec,
  428. gap_range,
  429. TF_ANCHOR_START,
  430. &result_comp);
  431. _GetTextAndAttributeGapRange(pLibTLS,
  432. ec,
  433. imc,
  434. gap_range,
  435. result_comp,
  436. CompStr, CompAttr, CompClause, CompGuid,
  437. ResultStr, ResultClause);
  438. //
  439. // Get display attribute data if some GUID_ATOM exist.
  440. //
  441. TF_DISPLAYATTRIBUTE da;
  442. TfGuidAtom guidatom = TF_INVALID_GUIDATOM;
  443. GetDisplayAttributeData(pLibTLS, ec, prop, pPropRange, &da, &guidatom, ulNumProp);
  444. //
  445. // Property range
  446. //
  447. no_display_attribute_range->CompareStart(ec,
  448. pPropRange,
  449. TF_ANCHOR_START,
  450. &result_comp);
  451. // Adjust GAP range's start anchor to the end of proprty range.
  452. gap_range->ShiftStartToRange(ec, pPropRange, TF_ANCHOR_END);
  453. //
  454. // Get reading string from property.
  455. //
  456. if (fCompExist == TRUE && result_comp <= 0)
  457. GetReadingString(ec, ic, pPropRange, CompReadStr, CompReadClause);
  458. else
  459. GetReadingString(ec, ic, pPropRange, ResultReadStr, ResultReadClause);
  460. //
  461. // Get property text
  462. //
  463. _GetTextAndAttributePropertyRange(pLibTLS,
  464. ec,
  465. imc,
  466. pPropRange,
  467. fCompExist,
  468. result_comp,
  469. bInWriteSession,
  470. da,
  471. guidatom,
  472. CompStr, CompAttr, CompClause, CompGuid,
  473. ResultStr, ResultClause);
  474. SafeReleaseClear(pPropRange);
  475. } // while
  476. // the last non-attr
  477. textRange->ShiftStartToRange(ec, gap_range, TF_ANCHOR_START);
  478. textRange->ShiftEndToRange(ec, range, TF_ANCHOR_END);
  479. LONG ulClausePos = 0;
  480. BOOL fEmpty;
  481. while (textRange->IsEmpty(ec, &fEmpty) == S_OK && !fEmpty)
  482. {
  483. WCHAR wstr0[256 + 1];
  484. ULONG ulcch0 = ARRAYSIZE(wstr0) - 1;
  485. textRange->GetText(ec, TF_TF_MOVESTART, wstr0, ulcch0, &ulcch0);
  486. TfGuidAtom guidatom;
  487. guidatom = TF_INVALID_GUIDATOM;
  488. TF_DISPLAYATTRIBUTE da;
  489. da.bAttr = TF_ATTR_INPUT;
  490. CompGuid.AddCompData(guidatom, ulcch0);
  491. CompAttr.AddCompData(_ConvertAttributeToImm32(da.bAttr), ulcch0);
  492. CompStr.AddCompData(wstr0, ulcch0);
  493. ulClausePos += ulcch0;
  494. }
  495. if (ulClausePos) {
  496. DWORD last_clause;
  497. if (CompClause.GetSize() > 0) {
  498. last_clause = CompClause[ CompClause.GetSize() - 1 ];
  499. CompClause.Add( last_clause + ulClausePos );
  500. }
  501. }
  502. textRange->Collapse(ec, TF_ANCHOR_END);
  503. range->Release();
  504. *(ITfRange **)(range) = NULL;
  505. } // out-most while for GUID_PROP_COMPOSING
  506. //
  507. // Fix up empty clause
  508. //
  509. if (CompClause.GetSize() <= 1)
  510. CompClause.RemoveAll();
  511. if (ResultClause.GetSize() <= 1)
  512. ResultClause.RemoveAll();
  513. return S_OK;
  514. }
  515. //
  516. // Retrieve text from gap range
  517. //
  518. HRESULT
  519. ImmIfEditSessionCallBack::_GetTextAndAttributeGapRange(
  520. LIBTHREAD *pLibTLS,
  521. TfEditCookie ec,
  522. IMCLock& imc,
  523. Interface<ITfRange>& gap_range,
  524. LONG result_comp,
  525. CWCompString& CompStr,
  526. CWCompAttribute& CompAttr,
  527. CWCompClause& CompClause,
  528. CWCompTfGuidAtom& CompGuid,
  529. CWCompString& ResultStr,
  530. CWCompClause& ResultClause
  531. )
  532. {
  533. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  534. ASSERT(_pAImeContext != NULL);
  535. TfGuidAtom guidatom;
  536. guidatom = TF_INVALID_GUIDATOM;
  537. TF_DISPLAYATTRIBUTE da;
  538. da.bAttr = TF_ATTR_INPUT;
  539. ULONG ulClausePos = 0;
  540. BOOL fEmpty;
  541. WCHAR wstr0[256 + 1];
  542. ULONG ulcch0;
  543. while (gap_range->IsEmpty(ec, &fEmpty) == S_OK && !fEmpty)
  544. {
  545. Interface<ITfRange> backup_range;
  546. if (FAILED(gap_range->Clone(backup_range)))
  547. return E_FAIL;
  548. //
  549. // Retrieve gap text if there exist.
  550. //
  551. ulcch0 = ARRAYSIZE(wstr0) - 1;
  552. if (FAILED(gap_range->GetText(ec,
  553. TF_TF_MOVESTART, // Move range to next after get text.
  554. wstr0,
  555. ulcch0, &ulcch0)))
  556. return E_FAIL;
  557. ulClausePos += ulcch0;
  558. if (result_comp <= 0) {
  559. CompGuid.AddCompData(guidatom, ulcch0);
  560. CompAttr.AddCompData(_ConvertAttributeToImm32(da.bAttr), ulcch0);
  561. CompStr.AddCompData(wstr0, ulcch0);
  562. }
  563. else {
  564. ResultStr.AddCompData(wstr0, ulcch0);
  565. if (_pAImeContext)
  566. ClearTextInRange(ec, backup_range, _pAImeContext);
  567. }
  568. }
  569. if (ulClausePos) {
  570. DWORD last_clause;
  571. if (result_comp <= 0) {
  572. if (CompClause.GetSize() > 0) {
  573. last_clause = CompClause[ CompClause.GetSize() - 1 ];
  574. CompClause.Add( last_clause + ulClausePos );
  575. }
  576. }
  577. else {
  578. if (ResultClause.GetSize() > 0) {
  579. last_clause = ResultClause[ ResultClause.GetSize() - 1 ];
  580. ResultClause.Add( last_clause + ulClausePos );
  581. }
  582. }
  583. }
  584. return S_OK;
  585. }
  586. //
  587. // Retrieve text from property range
  588. //
  589. HRESULT
  590. ImmIfEditSessionCallBack::_GetTextAndAttributePropertyRange(
  591. LIBTHREAD *pLibTLS,
  592. TfEditCookie ec,
  593. IMCLock& imc,
  594. ITfRange* pPropRange,
  595. BOOL fCompExist,
  596. LONG result_comp,
  597. BOOL bInWriteSession,
  598. TF_DISPLAYATTRIBUTE da,
  599. TfGuidAtom guidatom,
  600. CWCompString& CompStr,
  601. CWCompAttribute& CompAttr,
  602. CWCompClause& CompClause,
  603. CWCompTfGuidAtom& CompGuid,
  604. CWCompString& ResultStr,
  605. CWCompClause& ResultClause
  606. )
  607. {
  608. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  609. ASSERT(_pAImeContext != NULL);
  610. ULONG ulClausePos = 0;
  611. BOOL fEmpty;
  612. WCHAR wstr0[256 + 1];
  613. ULONG ulcch0;
  614. while (pPropRange->IsEmpty(ec, &fEmpty) == S_OK && !fEmpty)
  615. {
  616. Interface<ITfRange> backup_range;
  617. if (FAILED(pPropRange->Clone(backup_range)))
  618. return E_FAIL;
  619. //
  620. // Retrieve property text if there exist.
  621. //
  622. ulcch0 = ARRAYSIZE(wstr0) - 1;
  623. if (FAILED(pPropRange->GetText(ec,
  624. TF_TF_MOVESTART, // Move range to next after get text.
  625. wstr0,
  626. ulcch0, &ulcch0)))
  627. return E_FAIL;
  628. ulClausePos += ulcch0; // we only need to addup the char position for clause info
  629. // see if there is a valid disp attribute
  630. if (fCompExist == TRUE && result_comp <= 0)
  631. {
  632. if (guidatom == TF_INVALID_GUIDATOM) {
  633. da.bAttr = TF_ATTR_INPUT;
  634. }
  635. CompGuid.AddCompData(guidatom, ulcch0);
  636. CompAttr.AddCompData(_ConvertAttributeToImm32(da.bAttr), ulcch0);
  637. CompStr.AddCompData(wstr0, ulcch0);
  638. }
  639. else if (bInWriteSession)
  640. {
  641. // if there's no disp attribute attached, it probably means
  642. // the part of string is finalized.
  643. //
  644. ResultStr.AddCompData(wstr0, ulcch0);
  645. // it was a 'determined' string
  646. // so the doc has to shrink
  647. //
  648. if (_pAImeContext)
  649. ClearTextInRange(ec, backup_range, _pAImeContext);
  650. }
  651. else
  652. {
  653. //
  654. // Prevent infinite loop
  655. //
  656. break;
  657. }
  658. }
  659. if (ulClausePos) {
  660. DWORD last_clause;
  661. if (fCompExist == TRUE && result_comp <= 0) {
  662. if (CompClause.GetSize() > 0) {
  663. last_clause = CompClause[ CompClause.GetSize() - 1 ];
  664. CompClause.Add( last_clause + ulClausePos );
  665. }
  666. }
  667. else if (result_comp == 0) {
  668. //
  669. // Copy CompClause data to ResultClause
  670. //
  671. CompClauseToResultClause(imc, ResultClause, ulcch0);
  672. }
  673. else {
  674. if (ResultClause.GetSize() > 0) {
  675. last_clause = ResultClause[ ResultClause.GetSize() - 1 ];
  676. ResultClause.Add( last_clause + ulClausePos );
  677. }
  678. }
  679. }
  680. return S_OK;
  681. }
  682. HRESULT
  683. ImmIfEditSessionCallBack::_GetNoDisplayAttributeRange(
  684. LIBTHREAD *pLibTLS,
  685. TfEditCookie ec,
  686. Interface_Attach<ITfContext>& ic,
  687. Interface<ITfRange>& rangeIn,
  688. Interface<ITfRange>& no_display_attribute_range
  689. )
  690. {
  691. Interface<ITfProperty> propComp;
  692. Interface<IEnumTfRanges> enumComp;
  693. VARIANT var;
  694. HRESULT hr = ic->GetProperty(GUID_PROP_COMPOSING, propComp);
  695. if (S_OK == hr)
  696. {
  697. hr = propComp->EnumRanges(ec, enumComp, rangeIn);
  698. }
  699. else
  700. return hr;
  701. ITfRange *pRange;
  702. while(enumComp->Next(1, &pRange, NULL) == S_OK)
  703. {
  704. BOOL fCompExist = FALSE;
  705. hr = propComp->GetValue(ec, pRange, &var);
  706. if (S_OK == hr)
  707. {
  708. if (var.vt == VT_I4 && var.lVal != 0)
  709. fCompExist = TRUE;
  710. }
  711. if (!fCompExist) {
  712. // Adjust GAP range's start anchor to the end of proprty range.
  713. no_display_attribute_range->ShiftStartToRange(ec, pRange, TF_ANCHOR_START);
  714. }
  715. pRange->Release();
  716. }
  717. return S_OK;
  718. }
  719. /////////////////////////////////////////////////////////////////////////////
  720. // ImmIfEditSession
  721. ImmIfEditSession::ImmIfEditSession(
  722. ESCB escb,
  723. TfClientId tid,
  724. Interface_Attach<ImmIfIME> ImmIfIme,
  725. IMCLock& imc
  726. ) : m_ImmIfIme(ImmIfIme), m_ic(ImmIfIme->GetInputContext(imc)), m_tid(tid),
  727. m_state((HIMC)imc)
  728. {
  729. _Init(escb);
  730. }
  731. ImmIfEditSession::ImmIfEditSession(
  732. ESCB escb,
  733. TfClientId tid,
  734. Interface_Attach<ImmIfIME> ImmIfIme,
  735. IMCLock& imc,
  736. Interface_Attach<ITfContext> pic
  737. ) : m_ImmIfIme(ImmIfIme), m_ic(pic), m_tid(tid),
  738. m_state((HIMC)imc)
  739. {
  740. _Init(escb);
  741. }
  742. void
  743. ImmIfEditSession::_Init(
  744. ESCB escb
  745. )
  746. {
  747. m_pfnCallback = EditSessionCallBack;
  748. m_cRef = 1;
  749. m_ImmIfCallBack = NULL;
  750. switch(escb) {
  751. case ESCB_HANDLETHISKEY:
  752. m_ImmIfCallBack = new ImmIfHandleThisKey;
  753. break;
  754. case ESCB_COMPCOMPLETE:
  755. m_ImmIfCallBack = new ImmIfCompositionComplete;
  756. break;
  757. case ESCB_COMPCANCEL:
  758. m_ImmIfCallBack = new ImmIfCompositionCancel;
  759. break;
  760. case ESCB_UPDATECOMPOSITIONSTRING:
  761. m_ImmIfCallBack = new ImmIfUpdateCompositionString;
  762. break;
  763. case ESCB_REPLACEWHOLETEXT:
  764. m_ImmIfCallBack = new ImmIfReplaceWholeText;
  765. break;
  766. case ESCB_RECONVERTSTRING:
  767. m_ImmIfCallBack = new ImmIfReconvertString;
  768. break;
  769. case ESCB_CLEARDOCFEEDBUFFER:
  770. m_ImmIfCallBack = new ImmIfClearDocFeedBuffer;
  771. break;
  772. case ESCB_GETTEXTANDATTRIBUTE:
  773. m_ImmIfCallBack = new ImmIfGetTextAndAttribute;
  774. break;
  775. case ESCB_QUERYRECONVERTSTRING:
  776. m_ImmIfCallBack = new ImmIfQueryReconvertString;
  777. break;
  778. case ESCB_CALCRANGEPOS:
  779. m_ImmIfCallBack = new ImmIfCalcRangePos;
  780. break;
  781. case ESCB_GETSELECTION:
  782. m_ImmIfCallBack = new ImmIfGetSelection;
  783. break;
  784. case ESCB_GET_READONLY_PROP_MARGIN:
  785. m_ImmIfCallBack = new ImmIfGetReadOnlyPropMargin;
  786. break;
  787. case ESCB_GET_CURSOR_POSITION:
  788. m_ImmIfCallBack = new ImmIfGetCursorPosition;
  789. break;
  790. case ESCB_GET_ALL_TEXT_RANGE:
  791. m_ImmIfCallBack = new ImmIfGetAllTextRange;
  792. break;
  793. }
  794. }
  795. ImmIfEditSession::~ImmIfEditSession(
  796. )
  797. {
  798. if (m_ImmIfCallBack)
  799. delete m_ImmIfCallBack;
  800. }
  801. bool
  802. ImmIfEditSession::Valid(
  803. )
  804. {
  805. return (m_ImmIfIme.Valid() && m_ic.Valid()) ? true : false;
  806. }
  807. // ImmIfEditSession::ITfEditCallback method
  808. STDAPI
  809. ImmIfEditSession::DoEditSession(
  810. TfEditCookie ec
  811. )
  812. {
  813. return m_pfnCallback(ec, this);
  814. }
  815. // ImmIfEditSession::IUnknown
  816. STDAPI
  817. ImmIfEditSession::QueryInterface(
  818. REFIID riid,
  819. void** ppvObj
  820. )
  821. {
  822. *ppvObj = NULL;
  823. if (IsEqualIID(riid, IID_IUnknown) ||
  824. IsEqualIID(riid, IID_ITfEditSession)) {
  825. *ppvObj = SAFECAST(this, ImmIfEditSession*);
  826. }
  827. if (*ppvObj) {
  828. AddRef();
  829. return S_OK;
  830. }
  831. return E_NOINTERFACE;
  832. }
  833. STDAPI_(ULONG)
  834. ImmIfEditSession::AddRef(
  835. )
  836. {
  837. return ++m_cRef;
  838. }
  839. STDAPI_(ULONG)
  840. ImmIfEditSession::Release(
  841. )
  842. {
  843. long cr;
  844. cr = --m_cRef;
  845. Assert(cr >= 0);
  846. if (cr == 0) {
  847. delete this;
  848. }
  849. return cr;
  850. }
  851. /////////////////////////////////////////////////////////////////////////////
  852. // ImmIfHandleThisKey
  853. HRESULT
  854. ImmIfHandleThisKey::HandleThisKey(
  855. TfEditCookie ec,
  856. UINT uVKey,
  857. HIMC hIMC,
  858. Interface_Attach<ITfContext> ic,
  859. Interface_Attach<ImmIfIME> ImmIfIme
  860. )
  861. {
  862. Interface_TFSELECTION sel;
  863. BOOL fEmpty;
  864. ULONG cFetched;
  865. HRESULT hr;
  866. IMCLock imc(hIMC);
  867. if (FAILED(hr=imc.GetResult()))
  868. return hr;
  869. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  870. ASSERT(_pAImeContext != NULL);
  871. //
  872. // Finalize the composition string
  873. //
  874. if (_pAImeContext &&
  875. _pAImeContext->IsVKeyInKeyList(uVKey, EDIT_ID_FINALIZE)) {
  876. return ImmIfIme->_CompComplete(imc);
  877. }
  878. //
  879. // Keys that change its behavior on selection
  880. //
  881. if (ic->GetSelection(ec, TF_DEFAULT_SELECTION, 1, sel, &cFetched) != S_OK)
  882. return E_FAIL;
  883. sel->range->IsEmpty(ec, &fEmpty);
  884. if (!fEmpty) {
  885. //
  886. // Selection is not empty.
  887. //
  888. switch (uVKey) {
  889. case VK_BACK:
  890. case VK_DELETE:
  891. //
  892. // Delete the selection
  893. //
  894. ClearTextInRange(ec, sel->range, _pAImeContext);
  895. return ImmIfIme->_UpdateCompositionString();
  896. }
  897. }
  898. switch (uVKey) {
  899. case VK_BACK:
  900. // Make selection
  901. if (SUCCEEDED(ShiftSelectionToLeft(ec, sel->range, false))) {
  902. // Clear the current selection
  903. if (SUCCEEDED(ClearTextInRange(ec, sel->range, _pAImeContext))) {
  904. return ImmIfIme->_UpdateCompositionString();
  905. }
  906. }
  907. break;
  908. case VK_DELETE:
  909. if (SUCCEEDED(ShiftSelectionToRight(ec, sel->range, false))) {
  910. if (SUCCEEDED(ClearTextInRange(ec, sel->range, _pAImeContext))) {
  911. return ImmIfIme->_UpdateCompositionString();
  912. }
  913. }
  914. break;
  915. case VK_LEFT:
  916. sel->style.ase = TF_AE_START;
  917. if (::GetKeyState(VK_SHIFT) >= 0 &&
  918. ::GetKeyState(VK_CONTROL) >= 0) {
  919. if (SUCCEEDED(ShiftSelectionToLeft(ec, sel->range)) &&
  920. SUCCEEDED(ic->SetSelection(ec, 1, sel))) {
  921. return ImmIfIme->_UpdateCompositionString();
  922. }
  923. }
  924. break;
  925. case VK_RIGHT:
  926. sel->style.ase = TF_AE_END;
  927. if (::GetKeyState(VK_SHIFT) >= 0 &&
  928. ::GetKeyState(VK_CONTROL) >= 0) {
  929. if (SUCCEEDED(ShiftSelectionToRight(ec, sel->range)) &&
  930. SUCCEEDED(ic->SetSelection(ec, 1, sel))) {
  931. return ImmIfIme->_UpdateCompositionString();
  932. }
  933. }
  934. break;
  935. }
  936. return E_FAIL;
  937. }
  938. HRESULT
  939. ImmIfHandleThisKey::ShiftSelectionToLeft(
  940. TfEditCookie ec,
  941. ITfRange *range,
  942. bool fShiftEnd
  943. )
  944. {
  945. LONG cch;
  946. if (SUCCEEDED(range->ShiftStart(ec, -1, &cch, NULL))) {
  947. HRESULT hr = S_OK;
  948. if (fShiftEnd) {
  949. hr = range->Collapse(ec, TF_ANCHOR_START);
  950. }
  951. return hr;
  952. }
  953. return E_FAIL;
  954. }
  955. HRESULT
  956. ImmIfHandleThisKey::ShiftSelectionToRight(
  957. TfEditCookie ec,
  958. ITfRange *range,
  959. bool fShiftStart
  960. )
  961. {
  962. LONG cch;
  963. if (SUCCEEDED(range->ShiftEnd(ec, 1, &cch, NULL))) {
  964. HRESULT hr = S_OK;
  965. if (fShiftStart) {
  966. hr = range->Collapse(ec, TF_ANCHOR_END);
  967. }
  968. return hr;
  969. }
  970. return E_FAIL;
  971. }
  972. /////////////////////////////////////////////////////////////////////////////
  973. // ImmIfCompositionComplete
  974. HRESULT
  975. ImmIfCompositionComplete::CompComplete(
  976. TfEditCookie ec,
  977. HIMC hIMC,
  978. BOOL fTerminateComp,
  979. Interface_Attach<ITfContext> ic,
  980. Interface_Attach<ImmIfIME> ImmIfIme
  981. )
  982. {
  983. HRESULT hr;
  984. if (fTerminateComp == TRUE)
  985. {
  986. Interface<ITfContextOwnerCompositionServices> icocs;
  987. hr = ic->QueryInterface(IID_ITfContextOwnerCompositionServices, (void **)icocs);
  988. if (S_OK == hr)
  989. {
  990. icocs->TerminateComposition(NULL);
  991. }
  992. }
  993. IMCLock imc(hIMC);
  994. if (FAILED(hr = imc.GetResult()))
  995. return hr;
  996. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  997. if (_pAImeContext == NULL)
  998. return E_FAIL;
  999. ASSERT(_pAImeContext != NULL);
  1000. //
  1001. // Get the whole text, finalize it, and set empty string in TOM
  1002. //
  1003. Interface<ITfRange> start;
  1004. LONG cch;
  1005. if (SUCCEEDED(hr=GetAllTextRange(ec, ic, &start, &cch))) {
  1006. //
  1007. // If there is no string in TextStore and we havenot sent
  1008. // WM_IME_STARTCOMPOSITION, we don't have to do anything.
  1009. //
  1010. if (!cch) {
  1011. if (_pAImeContext && !(_pAImeContext->m_fStartComposition))
  1012. return S_OK;
  1013. }
  1014. LPWSTR wstr = new WCHAR[ cch + 1 ];
  1015. Interface<ITfProperty> prop;
  1016. //
  1017. // Get the whole text, finalize it, and erase the whole text.
  1018. //
  1019. if (SUCCEEDED(start->GetText(ec, TF_TF_IGNOREEND, wstr, (ULONG)cch, (ULONG*)&cch))) {
  1020. //
  1021. // Make Result String.
  1022. //
  1023. UINT cp = CP_ACP;
  1024. ImmIfIme->GetCodePageA(&cp);
  1025. CWCompString ResultStr(cp, hIMC, wstr, cch);
  1026. CWCompString ResultReadStr;
  1027. CWCompClause ResultReadClause;
  1028. CWCompClause ResultClause;
  1029. if (cch) {
  1030. //
  1031. // Get reading string from property.
  1032. //
  1033. GetReadingString(ec, ic, ResultReadStr, ResultReadClause);
  1034. //
  1035. // Copy CompClause data to ResultClause
  1036. //
  1037. CompClauseToResultClause(imc, ResultClause, cch);
  1038. }
  1039. #ifdef CICERO_4732
  1040. if (_pAImeContext && ! _pAImeContext->m_fInCompComplete)
  1041. {
  1042. //
  1043. // Prevent reentrance call of CPS_COMPLETE.
  1044. //
  1045. _pAImeContext->m_fInCompComplete = TRUE;
  1046. #endif
  1047. //
  1048. // set composition string
  1049. //
  1050. hr = _SetCompositionString(imc,
  1051. &ResultStr, &ResultClause,
  1052. &ResultReadStr, &ResultReadClause);
  1053. #ifdef CICERO_4732
  1054. _pAImeContext->m_fInCompComplete = FALSE;
  1055. }
  1056. #endif
  1057. //
  1058. // Clear the TOM
  1059. //
  1060. if (SUCCEEDED(hr))
  1061. {
  1062. if (_pAImeContext)
  1063. hr = ClearTextInRange(ec, start, _pAImeContext);
  1064. }
  1065. }
  1066. delete [] wstr;
  1067. }
  1068. else {
  1069. ImmIfIme->_CompCancel(imc);
  1070. }
  1071. return hr;
  1072. }
  1073. /////////////////////////////////////////////////////////////////////////////
  1074. // ImmIfCompositionCancel
  1075. HRESULT
  1076. ImmIfCompositionCancel::CompCancel(
  1077. TfEditCookie ec,
  1078. HIMC hIMC,
  1079. Interface_Attach<ITfContext> ic
  1080. )
  1081. {
  1082. HRESULT hr;
  1083. IMCLock imc(hIMC);
  1084. if (FAILED(hr = imc.GetResult()))
  1085. return hr;
  1086. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  1087. if (_pAImeContext == NULL)
  1088. return E_FAIL;
  1089. ASSERT(_pAImeContext != NULL);
  1090. if (_pAImeContext &&
  1091. _pAImeContext->m_fStartComposition) {
  1092. IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
  1093. if (SUCCEEDED(hr = comp.GetResult())) {
  1094. TRANSMSG msg;
  1095. msg.message = WM_IME_COMPOSITION;
  1096. msg.wParam = (WPARAM)VK_ESCAPE;
  1097. msg.lParam = (LPARAM)(GCS_COMPREAD | GCS_COMP | GCS_CURSORPOS | GCS_DELTASTART);
  1098. if (_pAImeContext->m_pMessageBuffer)
  1099. _pAImeContext->m_pMessageBuffer->SetData(msg);
  1100. _pAImeContext->m_fStartComposition = FALSE;
  1101. msg.message = WM_IME_ENDCOMPOSITION;
  1102. msg.wParam = (WPARAM) 0;
  1103. msg.lParam = (LPARAM) 0;
  1104. if (_pAImeContext->m_pMessageBuffer)
  1105. _pAImeContext->m_pMessageBuffer->SetData(msg);
  1106. //
  1107. // Clear the text in Cicero TOM
  1108. //
  1109. Interface<ITfRange> range;
  1110. LONG l;
  1111. if (SUCCEEDED(GetAllTextRange(ec, ic, &range, &l))) {
  1112. hr = ClearTextInRange(ec, range, _pAImeContext);
  1113. }
  1114. }
  1115. imc.GenerateMessage();
  1116. }
  1117. return hr;
  1118. }
  1119. /////////////////////////////////////////////////////////////////////////////
  1120. // ImmIfUpdateCompositionString
  1121. HRESULT
  1122. ImmIfUpdateCompositionString::UpdateCompositionString(
  1123. TfEditCookie ec,
  1124. HIMC hIMC,
  1125. Interface_Attach<ITfContext> ic,
  1126. DWORD dwDeltaStart,
  1127. Interface_Attach<ImmIfIME> ImmIfIme
  1128. )
  1129. {
  1130. HRESULT hr;
  1131. IMCLock imc(hIMC);
  1132. if (FAILED(hr = imc.GetResult()))
  1133. return hr;
  1134. BOOL bInWriteSession;
  1135. if (FAILED(hr = ic->InWriteSession(ImmIfIme->GetClientId(), &bInWriteSession)))
  1136. return hr;
  1137. Interface<ITfRange> FullTextRange;
  1138. LONG lTextLength;
  1139. if (FAILED(hr=GetAllTextRange(ec, ic, &FullTextRange, &lTextLength)))
  1140. return hr;
  1141. Interface<ITfRange> InterimRange;
  1142. BOOL fInterim = FALSE;
  1143. if (FAILED(hr = _IsInterimSelection(ec, ic, &InterimRange, &fInterim)))
  1144. return hr;
  1145. if (fInterim) {
  1146. UINT cp = CP_ACP;
  1147. ImmIfIme->GetCodePageA(&cp);
  1148. return _MakeInterimString(ImmIfIme->_GetLibTLS(),
  1149. ec, imc, ic, FullTextRange,
  1150. InterimRange, lTextLength, cp,
  1151. bInWriteSession);
  1152. }
  1153. else {
  1154. return _MakeCompositionString(ImmIfIme->_GetLibTLS(),
  1155. ec, imc, ic, FullTextRange,
  1156. dwDeltaStart,
  1157. bInWriteSession);
  1158. }
  1159. }
  1160. HRESULT
  1161. ImmIfUpdateCompositionString::_IsInterimSelection(
  1162. TfEditCookie ec,
  1163. Interface_Attach<ITfContext>& ic,
  1164. Interface<ITfRange>* pInterimRange,
  1165. BOOL *pfInterim
  1166. )
  1167. {
  1168. Interface_TFSELECTION sel;
  1169. ULONG cFetched;
  1170. *pfInterim = FALSE;
  1171. if (ic->GetSelection(ec, TF_DEFAULT_SELECTION, 1, sel, &cFetched) != S_OK)
  1172. {
  1173. // no selection. we can return S_OK.
  1174. return S_OK;
  1175. }
  1176. if (sel->style.fInterimChar) {
  1177. HRESULT hr;
  1178. if (FAILED(hr = sel->range->Clone(*pInterimRange)))
  1179. return hr;
  1180. *pfInterim = TRUE;
  1181. }
  1182. return S_OK;
  1183. }
  1184. HRESULT
  1185. ImmIfUpdateCompositionString::_MakeCompositionString(
  1186. LIBTHREAD *pLibTLS,
  1187. TfEditCookie ec,
  1188. IMCLock& imc,
  1189. Interface_Attach<ITfContext>& ic,
  1190. Interface<ITfRange>& FullTextRange,
  1191. DWORD dwDeltaStart,
  1192. BOOL bInWriteSession
  1193. )
  1194. {
  1195. HRESULT hr;
  1196. CWCompString CompStr;
  1197. CWCompAttribute CompAttr;
  1198. CWCompClause CompClause;
  1199. CWCompTfGuidAtom CompGuid;
  1200. CWCompCursorPos CompCursorPos;
  1201. CWCompDeltaStart CompDeltaStart;
  1202. CWCompString CompReadStr;
  1203. CWCompClause CompReadClause;
  1204. CWCompString ResultStr;
  1205. CWCompClause ResultClause;
  1206. CWCompString ResultReadStr;
  1207. CWCompClause ResultReadClause;
  1208. if (FAILED(hr = _GetTextAndAttribute(pLibTLS, ec, imc, ic, FullTextRange,
  1209. CompStr, CompAttr, CompClause,
  1210. CompGuid,
  1211. CompReadStr, CompReadClause,
  1212. ResultStr, ResultClause,
  1213. ResultReadStr, ResultReadClause,
  1214. bInWriteSession
  1215. ))) {
  1216. return hr;
  1217. }
  1218. if (FAILED(hr = _GetCursorPosition(ec, imc, ic, CompCursorPos, CompAttr))) {
  1219. return hr;
  1220. }
  1221. if (FAILED(hr = _GetDeltaStart(CompDeltaStart, CompStr, dwDeltaStart))) {
  1222. return hr;
  1223. }
  1224. //
  1225. // Clear the GUID attribute map array
  1226. //
  1227. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  1228. if (_pAImeContext == NULL)
  1229. return E_FAIL;
  1230. ASSERT(_pAImeContext != NULL);
  1231. _pAImeContext->usGuidMapSize = 0;
  1232. memset(&_pAImeContext->aGuidMap, 0, sizeof _pAImeContext->aGuidMap);
  1233. BOOL bBufferOverflow = FALSE;
  1234. // handle result string
  1235. hr = _SetCompositionString(imc,
  1236. &CompStr, &CompAttr, &CompClause,
  1237. &CompCursorPos, &CompDeltaStart,
  1238. &CompGuid,
  1239. &bBufferOverflow,
  1240. &CompReadStr,
  1241. &ResultStr, &ResultClause,
  1242. &ResultReadStr, &ResultReadClause);
  1243. if (SUCCEEDED(hr) && bBufferOverflow) {
  1244. //
  1245. // Buffer overflow in COMPOSITIONSTRING.compstr[NMAXKEY],
  1246. // Then, Clear the TOM
  1247. //
  1248. //
  1249. // Get the whole text, finalize it, and set empty string in TOM
  1250. //
  1251. Interface<ITfRange> start;
  1252. LONG cch;
  1253. if (SUCCEEDED(hr=GetAllTextRange(ec, ic, &start, &cch))) {
  1254. hr = ClearTextInRange(ec, start, _pAImeContext);
  1255. }
  1256. }
  1257. return hr;
  1258. }
  1259. HRESULT
  1260. ImmIfUpdateCompositionString::_MakeInterimString(
  1261. LIBTHREAD *pLibTLS,
  1262. TfEditCookie ec,
  1263. IMCLock& imc,
  1264. Interface_Attach<ITfContext>& ic,
  1265. Interface<ITfRange>& FullTextRange,
  1266. Interface<ITfRange>& InterimRange,
  1267. LONG lTextLength,
  1268. UINT cp,
  1269. BOOL bInWriteSession
  1270. )
  1271. {
  1272. LONG lStartResult;
  1273. LONG lEndResult;
  1274. FullTextRange->CompareStart(ec, InterimRange, TF_ANCHOR_START, &lStartResult);
  1275. if (lStartResult > 0) {
  1276. return E_FAIL;
  1277. }
  1278. FullTextRange->CompareEnd(ec, InterimRange, TF_ANCHOR_END, &lEndResult);
  1279. if (lEndResult < 0) {
  1280. return E_FAIL;
  1281. }
  1282. if (lEndResult > 1) {
  1283. return E_FAIL;
  1284. }
  1285. HRESULT hr = S_OK;
  1286. CWInterimString InterimStr(cp, (HIMC)imc);
  1287. if (lStartResult < 0) {
  1288. //
  1289. // Make result string.
  1290. //
  1291. #if 0
  1292. BOOL fEqual;
  1293. do {
  1294. LONG cch;
  1295. FullTextRange->ShiftEnd(ec, -1, &cch, NULL);
  1296. if (cch == 0) {
  1297. return E_FAIL;
  1298. }
  1299. lTextLength -= abs(cch);
  1300. FullTextRange->IsEqualEnd(ec, InterimRange, TF_ANCHOR_START, &fEqual);
  1301. } while(! fEqual);
  1302. #endif
  1303. if (FAILED(hr=FullTextRange->ShiftEndToRange(ec, InterimRange, TF_ANCHOR_START)))
  1304. return hr;
  1305. //
  1306. // Interim char assume 1 char length.
  1307. // Full text length - 1 means result string length.
  1308. //
  1309. lTextLength --;
  1310. ASSERT(lTextLength > 0);
  1311. if (lTextLength > 0) {
  1312. LPWSTR wstr = new WCHAR[ lTextLength + 1 ];
  1313. //
  1314. // Get the result text, finalize it, and erase the result text.
  1315. //
  1316. if (SUCCEEDED(FullTextRange->GetText(ec, TF_TF_IGNOREEND, wstr, (ULONG)lTextLength, (ULONG*)&lTextLength))) {
  1317. //
  1318. // Clear the TOM
  1319. //
  1320. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  1321. ASSERT(_pAImeContext != NULL);
  1322. if (_pAImeContext) {
  1323. if (SUCCEEDED(hr = ClearTextInRange(ec, FullTextRange, _pAImeContext))) {
  1324. InterimStr.WriteCompData(wstr, lTextLength);
  1325. }
  1326. }
  1327. }
  1328. delete [] wstr;
  1329. }
  1330. }
  1331. //
  1332. // Make interim character
  1333. //
  1334. CWCompString CompStr;
  1335. CWCompAttribute CompAttr;
  1336. CWCompClause CompClause;
  1337. CWCompTfGuidAtom CompGuid;
  1338. CWCompString CompReadStr;
  1339. CWCompClause CompReadClause;
  1340. CWCompString ResultStr;
  1341. CWCompClause ResultClause;
  1342. CWCompString ResultReadStr;
  1343. CWCompClause ResultReadClause;
  1344. if (FAILED(hr = _GetTextAndAttribute(pLibTLS, ec, imc, ic, InterimRange,
  1345. CompStr, CompAttr, CompClause,
  1346. CompGuid,
  1347. CompReadStr, CompReadClause,
  1348. ResultStr, ResultClause,
  1349. ResultReadStr, ResultReadClause,
  1350. bInWriteSession
  1351. ))) {
  1352. return hr;
  1353. }
  1354. WCHAR ch = L'\0';
  1355. BYTE attr = 0;
  1356. if (CompStr.GetSize() > 0) {
  1357. CompStr.ReadCompData(&ch, 1);
  1358. }
  1359. if (CompAttr.GetSize() > 0) {
  1360. CompAttr.ReadCompData(&attr, 1);
  1361. }
  1362. InterimStr.WriteInterimChar(ch, attr);
  1363. hr = _SetCompositionString(imc, &InterimStr);
  1364. return hr;
  1365. }
  1366. //
  1367. // Get delta start
  1368. //
  1369. HRESULT
  1370. ImmIfUpdateCompositionString::_GetDeltaStart(
  1371. CWCompDeltaStart& CompDeltaStart,
  1372. CWCompString& CompStr,
  1373. DWORD dwDeltaStart
  1374. )
  1375. {
  1376. if (dwDeltaStart < (DWORD)CompStr.GetSize())
  1377. CompDeltaStart.Set(dwDeltaStart); // Set COMPOSITIONSTRING.dwDeltaStart.
  1378. else
  1379. CompDeltaStart.Set(0);
  1380. return S_OK;
  1381. }
  1382. /////////////////////////////////////////////////////////////////////////////
  1383. // ImmIfReplaceWholeText
  1384. HRESULT
  1385. ImmIfReplaceWholeText::ReplaceWholeText(
  1386. TfEditCookie ec,
  1387. HIMC hIMC,
  1388. Interface_Attach<ITfContext> ic,
  1389. CWCompString* lpwCompStr
  1390. )
  1391. {
  1392. HRESULT hr;
  1393. IMCLock imc(hIMC);
  1394. if (FAILED(hr = imc.GetResult()))
  1395. return hr;
  1396. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  1397. ASSERT(_pAImeContext != NULL);
  1398. DWORD dwSize = (DWORD)lpwCompStr->GetSize();
  1399. LPWSTR lpszComp = new WCHAR[dwSize + 1];
  1400. if (!lpszComp)
  1401. return hr;
  1402. lpwCompStr->ReadCompData(lpszComp, dwSize + 1);
  1403. lpszComp[dwSize] = L'\0';
  1404. Interface<ITfRange> whole;
  1405. LONG cch;
  1406. if (SUCCEEDED(hr=GetAllTextRange(ec, ic, &whole, &cch))) {
  1407. if (_pAImeContext)
  1408. hr = SetTextInRange(ec, whole, lpszComp, 0, _pAImeContext);
  1409. }
  1410. delete [] lpszComp;
  1411. return hr;
  1412. }
  1413. void SetReadOnlyRange(TfEditCookie ec,
  1414. Interface_Attach<ITfContext> ic,
  1415. ITfRange *range,
  1416. BOOL fSet)
  1417. {
  1418. ITfProperty *prop;
  1419. if (SUCCEEDED(ic->GetProperty(GUID_PROP_MSIMTF_READONLY, &prop)))
  1420. {
  1421. if (fSet)
  1422. {
  1423. VARIANT var;
  1424. var.vt = VT_I4;
  1425. var.lVal = 1;
  1426. prop->SetValue(ec, range, &var);
  1427. }
  1428. else
  1429. {
  1430. prop->Clear(ec, range);
  1431. }
  1432. prop->Release();
  1433. }
  1434. }
  1435. /////////////////////////////////////////////////////////////////////////////
  1436. // ImmIfReconvertString
  1437. HRESULT
  1438. ImmIfReconvertString::ReconvertString(
  1439. TfEditCookie ec,
  1440. HIMC hIMC,
  1441. Interface_Attach<ITfContext> ic,
  1442. Interface<ITfRange>* rangeSrc,
  1443. BOOL fDocFeedOnly,
  1444. CWReconvertString* lpwReconvStr,
  1445. Interface_Attach<ImmIfIME> ImmIfIme
  1446. )
  1447. /*+++
  1448. LPRECONVERTSTRING structure:
  1449. +00 DWORD dwSize // Sizeof data (include this structure size) with byte count.
  1450. +04 DWORD dwVersion
  1451. +08 DWORD dwStrLen // String length with character count.
  1452. +0C DWORD dwStrOffset // Offset from start of this structure with byte count.
  1453. +10 DWORD dwCompStrLen // Comp Str length with character count.
  1454. +14 DWORD dwCompStrOffset // Offset from this->dwStrOffset with byte count.
  1455. +18 DWORD dwTargetStrLen // Target Str length with character count.
  1456. +1C DWORD dwTargetStrOffset // Offset from this->dwStrOffset with byte count.
  1457. +20
  1458. ---*/
  1459. {
  1460. HRESULT hr = E_FAIL;
  1461. IMCLock imc(hIMC);
  1462. if (FAILED(hr = imc.GetResult()))
  1463. return hr;
  1464. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  1465. if (_pAImeContext == NULL)
  1466. return E_FAIL;
  1467. DWORD dwLen;
  1468. dwLen = lpwReconvStr->ReadCompData();
  1469. if (dwLen) {
  1470. LPRECONVERTSTRING lpReconvertString;
  1471. lpReconvertString = (LPRECONVERTSTRING) new BYTE[ dwLen ];
  1472. if (lpReconvertString == NULL)
  1473. return hr;
  1474. lpwReconvStr->ReadCompData(lpReconvertString, dwLen);
  1475. if (lpReconvertString->dwStrLen) {
  1476. hr = ic->GetStart(ec, *rangeSrc);
  1477. if (SUCCEEDED(hr)) {
  1478. LONG cch;
  1479. hr = (*rangeSrc)->ShiftEnd(ec, LONG_MAX, &cch, NULL);
  1480. SetReadOnlyRange(ec, ic, *rangeSrc, FALSE);
  1481. BOOL fSkipSetText = FALSE;
  1482. if (SUCCEEDED(hr)) {
  1483. Interface<ITfRange> rangeOrgSelection;
  1484. if (lpReconvertString->dwCompStrLen)
  1485. {
  1486. WCHAR *pwstr = NULL;
  1487. ULONG ul = 0;
  1488. Interface<ITfRange> rangeTmp;
  1489. if (SUCCEEDED((*rangeSrc)->Clone(rangeTmp)))
  1490. {
  1491. UINT uSize = lpReconvertString->dwCompStrLen + 2;
  1492. pwstr = new WCHAR[uSize + 1];
  1493. if (pwstr)
  1494. {
  1495. ULONG ulcch;
  1496. rangeTmp->GetText(ec, 0, pwstr, uSize, &ulcch);
  1497. if ((lpReconvertString->dwCompStrLen == ulcch) &&
  1498. !memcmp(((LPBYTE)lpReconvertString +
  1499. lpReconvertString->dwStrOffset +
  1500. lpReconvertString->dwCompStrOffset),
  1501. pwstr,
  1502. lpReconvertString->dwCompStrLen * sizeof(WCHAR)))
  1503. fSkipSetText = TRUE;
  1504. delete [] pwstr;
  1505. }
  1506. }
  1507. if (!fSkipSetText && fDocFeedOnly)
  1508. {
  1509. TraceMsg(TF_WARNING, "ImmIfReconvertString::ReconvertString the current text store does not match with the string from App.");
  1510. goto Exit;
  1511. }
  1512. if (!fSkipSetText)
  1513. hr = SetTextInRange(ec,
  1514. *rangeSrc,
  1515. (LPWSTR)((LPBYTE)lpReconvertString +
  1516. lpReconvertString->dwStrOffset +
  1517. lpReconvertString->dwCompStrOffset),
  1518. lpReconvertString->dwCompStrLen,
  1519. _pAImeContext);
  1520. else
  1521. {
  1522. GetSelectionSimple(ec, ic.GetPtr(), rangeOrgSelection);
  1523. hr = S_OK;
  1524. }
  1525. #if 0
  1526. //
  1527. // set disp attribute for the reconvert
  1528. //
  1529. if (S_OK == hr)
  1530. {
  1531. ITfProperty *pProp = NULL;
  1532. hr = ic->GetProperty(GUID_PROP_ATTRIBUTE, &pProp);
  1533. if (S_OK == hr)
  1534. {
  1535. SetAttrPropertyData(ImmIfIme->_GetLibTLS(),
  1536. ec,
  1537. pProp,
  1538. *rangeSrc,
  1539. GUID_ATTR_MSIMTF_INPUT);
  1540. }
  1541. pProp->Release();
  1542. }
  1543. #endif
  1544. }
  1545. else
  1546. {
  1547. BOOL fEmpty;
  1548. if (SUCCEEDED((*rangeSrc)->IsEmpty(ec, &fEmpty)) && !fEmpty)
  1549. {
  1550. if (fDocFeedOnly)
  1551. {
  1552. TraceMsg(TF_WARNING, "ImmIfReconvertString::ReconvertString the current text store does not match with the string from App.");
  1553. goto Exit;
  1554. }
  1555. hr = ClearTextInRange(ec, *rangeSrc, _pAImeContext);
  1556. }
  1557. }
  1558. //
  1559. // set read only string
  1560. //
  1561. if (lpReconvertString->dwCompStrOffset)
  1562. {
  1563. //
  1564. // keep rangeSrc and rangeOrgSelection
  1565. //
  1566. (*rangeSrc)->SetGravity(ec,
  1567. TF_GRAVITY_FORWARD,
  1568. TF_GRAVITY_FORWARD);
  1569. if (rangeOrgSelection.Valid())
  1570. rangeOrgSelection->SetGravity(ec,
  1571. TF_GRAVITY_FORWARD,
  1572. TF_GRAVITY_FORWARD);
  1573. Interface<ITfRange> rangeStart;
  1574. if (SUCCEEDED((*rangeSrc)->Clone(rangeStart)))
  1575. {
  1576. if (SUCCEEDED(rangeStart->Collapse(ec, TF_ANCHOR_START)))
  1577. {
  1578. rangeStart->SetGravity(ec,
  1579. TF_GRAVITY_BACKWARD,
  1580. TF_GRAVITY_FORWARD);
  1581. hr = SetTextInRange(ec,
  1582. rangeStart,
  1583. (LPWSTR)((LPBYTE)lpReconvertString +
  1584. lpReconvertString->dwStrOffset),
  1585. lpReconvertString->dwCompStrOffset / sizeof(WCHAR),
  1586. _pAImeContext);
  1587. if (SUCCEEDED(hr))
  1588. SetReadOnlyRange(ec, ic, rangeStart, TRUE);
  1589. }
  1590. }
  1591. }
  1592. if ((lpReconvertString->dwCompStrOffset + lpReconvertString->dwCompStrLen * sizeof(WCHAR)) < lpReconvertString->dwStrLen * sizeof(WCHAR))
  1593. {
  1594. //
  1595. // keep rangeSrc and rangeOrgSelection
  1596. //
  1597. (*rangeSrc)->SetGravity(ec,
  1598. TF_GRAVITY_BACKWARD,
  1599. TF_GRAVITY_BACKWARD);
  1600. if (rangeOrgSelection.Valid())
  1601. rangeOrgSelection->SetGravity(ec,
  1602. TF_GRAVITY_BACKWARD,
  1603. TF_GRAVITY_BACKWARD);
  1604. Interface<ITfRange> rangeEnd;
  1605. if (SUCCEEDED((*rangeSrc)->Clone(rangeEnd)))
  1606. {
  1607. if (SUCCEEDED(rangeEnd->Collapse(ec, TF_ANCHOR_END)))
  1608. {
  1609. rangeEnd->SetGravity(ec,
  1610. TF_GRAVITY_BACKWARD,
  1611. TF_GRAVITY_FORWARD);
  1612. hr = SetTextInRange(ec,
  1613. rangeEnd,
  1614. (LPWSTR)((LPBYTE)lpReconvertString +
  1615. lpReconvertString->dwStrOffset +
  1616. lpReconvertString->dwCompStrOffset +
  1617. (lpReconvertString->dwCompStrLen * sizeof(WCHAR))),
  1618. ((lpReconvertString->dwStrLen * sizeof(WCHAR)) -
  1619. (lpReconvertString->dwCompStrOffset +
  1620. (lpReconvertString->dwCompStrLen * sizeof(WCHAR)))) / sizeof(WCHAR),
  1621. _pAImeContext);
  1622. if (SUCCEEDED(hr))
  1623. SetReadOnlyRange(ec, ic, rangeEnd, TRUE);
  1624. }
  1625. }
  1626. }
  1627. (*rangeSrc)->SetGravity(ec,
  1628. TF_GRAVITY_FORWARD,
  1629. TF_GRAVITY_BACKWARD);
  1630. //
  1631. // we just set a selection to the target string.
  1632. //
  1633. Interface<ITfRange> range;
  1634. if (fSkipSetText)
  1635. {
  1636. if (rangeOrgSelection.Valid())
  1637. {
  1638. //
  1639. //
  1640. //
  1641. TF_SELECTION sel;
  1642. sel.range = rangeOrgSelection;
  1643. sel.style.ase = TF_AE_NONE;
  1644. sel.style.fInterimChar = FALSE;
  1645. ic->SetSelection(ec, 1, &sel);
  1646. }
  1647. }
  1648. else if (SUCCEEDED((*rangeSrc)->Clone(range)))
  1649. {
  1650. LONG cchStart;
  1651. LONG cchEnd;
  1652. if (lpReconvertString->dwTargetStrOffset == 0 &&
  1653. lpReconvertString->dwTargetStrLen == 0 ) {
  1654. cchStart = lpReconvertString->dwCompStrOffset / sizeof(WCHAR);
  1655. cchEnd = lpReconvertString->dwCompStrOffset / sizeof(WCHAR) + lpReconvertString->dwCompStrLen;
  1656. }
  1657. else {
  1658. cchStart = (lpReconvertString->dwTargetStrOffset - lpReconvertString->dwCompStrOffset) / sizeof(WCHAR);
  1659. cchEnd = (lpReconvertString->dwTargetStrOffset - lpReconvertString->dwCompStrOffset) / sizeof(WCHAR) + lpReconvertString->dwTargetStrLen;
  1660. // cchStart = (lpReconvertString->dwTargetStrOffset) / sizeof(WCHAR);
  1661. // cchEnd = (lpReconvertString->dwTargetStrOffset) / sizeof(WCHAR) + lpReconvertString->dwTargetStrLen;
  1662. }
  1663. range->Collapse(ec, TF_ANCHOR_START);
  1664. //
  1665. // shift end first then shift start.
  1666. //
  1667. if ((SUCCEEDED(range->ShiftEnd(ec,
  1668. cchEnd,
  1669. &cch,
  1670. NULL))) &&
  1671. (SUCCEEDED(range->ShiftStart(ec,
  1672. cchStart,
  1673. &cch,
  1674. NULL))))
  1675. {
  1676. //
  1677. //
  1678. //
  1679. TF_SELECTION sel;
  1680. sel.range = range;
  1681. sel.style.ase = TF_AE_NONE;
  1682. sel.style.fInterimChar = FALSE;
  1683. ic->SetSelection(ec, 1, &sel);
  1684. }
  1685. }
  1686. //
  1687. // it's time to generate WM_IME_COMPOSITION.
  1688. //
  1689. ImmIfIme->_UpdateCompositionString();
  1690. }
  1691. }
  1692. }
  1693. Exit:
  1694. delete [] lpReconvertString;
  1695. }
  1696. return hr;
  1697. }
  1698. /////////////////////////////////////////////////////////////////////////////
  1699. // ImmIfClearDocFeedBuffer
  1700. HRESULT
  1701. ImmIfClearDocFeedBuffer::ClearDocFeedBuffer(
  1702. TfEditCookie ec,
  1703. HIMC hIMC,
  1704. Interface_Attach<ITfContext> ic,
  1705. Interface_Attach<ImmIfIME> ImmIfIme
  1706. )
  1707. {
  1708. HRESULT hr = E_FAIL;
  1709. IMCLock imc(hIMC);
  1710. if (FAILED(hr = imc.GetResult()))
  1711. return hr;
  1712. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  1713. if (_pAImeContext == NULL)
  1714. return E_FAIL;
  1715. ITfRange *rangeFull = NULL;
  1716. ITfProperty *prop;
  1717. ITfRange *rangeTmp;
  1718. LONG cch;
  1719. //
  1720. // Create the range that covers all the text.
  1721. //
  1722. if (FAILED(hr=ic->GetStart(ec, &rangeFull)))
  1723. return hr;
  1724. if (FAILED(hr=rangeFull->ShiftEnd(ec, LONG_MAX, &cch, NULL)))
  1725. return hr;
  1726. //
  1727. // find the first non readonly range in the text store.
  1728. //
  1729. if (SUCCEEDED(ic->GetProperty(GUID_PROP_MSIMTF_READONLY, &prop)))
  1730. {
  1731. IEnumTfRanges *enumranges;
  1732. if (SUCCEEDED(prop->EnumRanges(ec, &enumranges, rangeFull)))
  1733. {
  1734. while (enumranges->Next(1, &rangeTmp, NULL) == S_OK)
  1735. {
  1736. VARIANT var;
  1737. QuickVariantInit(&var);
  1738. prop->GetValue(ec, rangeTmp, &var);
  1739. if ((var.vt == VT_I4) && (var.lVal != 0))
  1740. {
  1741. prop->Clear(ec, rangeTmp);
  1742. ClearTextInRange(ec, rangeTmp, _pAImeContext);
  1743. }
  1744. rangeTmp->Release();
  1745. }
  1746. enumranges->Release();
  1747. }
  1748. prop->Release();
  1749. }
  1750. rangeFull->Release();
  1751. return S_OK;
  1752. }
  1753. /////////////////////////////////////////////////////////////////////////////
  1754. // ImmIfGetTextAndAttribute
  1755. HRESULT
  1756. ImmIfGetTextAndAttribute::GetTextAndAttribute(
  1757. TfEditCookie ec,
  1758. HIMC hIMC,
  1759. Interface_Attach<ITfContext> ic,
  1760. CWCompString* lpwCompString,
  1761. CWCompAttribute* lpwCompAttribute,
  1762. Interface_Attach<ImmIfIME> ImmIfIme
  1763. )
  1764. {
  1765. HRESULT hr;
  1766. LIBTHREAD *pLibTLS = ImmIfIme->_GetLibTLS();
  1767. IMCLock imc(hIMC);
  1768. if (FAILED(hr = imc.GetResult()))
  1769. return hr;
  1770. BOOL bInWriteSession;
  1771. if (FAILED(hr = ic->InWriteSession(ImmIfIme->GetClientId(), &bInWriteSession)))
  1772. return hr;
  1773. Interface<ITfRange> FullTextRange;
  1774. LONG lTextLength;
  1775. if (FAILED(hr=GetAllTextRange(ec, ic, &FullTextRange, &lTextLength)))
  1776. return hr;
  1777. if (FAILED(hr = _GetTextAndAttribute(pLibTLS, ec, imc, ic,
  1778. FullTextRange,
  1779. *lpwCompString,
  1780. *lpwCompAttribute,
  1781. bInWriteSession))) {
  1782. return hr;
  1783. }
  1784. return hr;
  1785. }
  1786. /////////////////////////////////////////////////////////////////////////////
  1787. // ImmIfQueryReconvertString
  1788. HRESULT
  1789. ImmIfQueryReconvertString::QueryReconvertString(
  1790. TfEditCookie ec,
  1791. HIMC hIMC,
  1792. Interface_Attach<ITfContext> ic,
  1793. Interface<ITfRange>* rangeQuery,
  1794. CWReconvertString* lpwReconvStr,
  1795. Interface_Attach<ImmIfIME> ImmIfIme
  1796. )
  1797. /*+++
  1798. LPRECONVERTSTRING structure:
  1799. +00 DWORD dwSize // Sizeof data (include this structure size) with byte count.
  1800. +04 DWORD dwVersion
  1801. +08 DWORD dwStrLen // String length with character count.
  1802. +0C DWORD dwStrOffset // Offset from start of this structure with byte count.
  1803. +10 DWORD dwCompStrLen // Comp Str length with character count.
  1804. +14 DWORD dwCompStrOffset // Offset from this->dwStrOffset with byte count.
  1805. +18 DWORD dwTargetStrLen // Target Str length with character count.
  1806. +1C DWORD dwTargetStrOffset // Offset from this->dwStrOffset with byte count.
  1807. +20
  1808. ---*/
  1809. {
  1810. HRESULT hr = E_FAIL;
  1811. IMCLock imc(hIMC);
  1812. if (FAILED(hr = imc.GetResult()))
  1813. return hr;
  1814. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  1815. if (_pAImeContext == NULL)
  1816. return E_FAIL;
  1817. DWORD dwLen;
  1818. dwLen = lpwReconvStr->ReadCompData();
  1819. if (dwLen) {
  1820. LPRECONVERTSTRING lpReconvertString;
  1821. lpReconvertString = (LPRECONVERTSTRING) new BYTE[ dwLen ];
  1822. if (lpReconvertString == NULL)
  1823. return hr;
  1824. lpwReconvStr->ReadCompData(lpReconvertString, dwLen);
  1825. if (lpReconvertString->dwStrLen) {
  1826. Interface<ITfRange> rangeSrc;
  1827. hr = ic->GetStart(ec, rangeSrc);
  1828. if (SUCCEEDED(hr)) {
  1829. LONG cch;
  1830. hr = rangeSrc->ShiftEnd(ec, LONG_MAX, &cch, NULL);
  1831. if (SUCCEEDED(hr)) {
  1832. hr = SetTextInRange(ec,
  1833. rangeSrc,
  1834. (LPWSTR)((LPBYTE)lpReconvertString +
  1835. lpReconvertString->dwStrOffset),
  1836. lpReconvertString->dwStrLen,
  1837. _pAImeContext);
  1838. #if 0
  1839. //
  1840. // set disp attribute for the query reconvert
  1841. //
  1842. if (S_OK == hr)
  1843. {
  1844. ITfProperty *pProp = NULL;
  1845. hr = ic->GetProperty(GUID_PROP_ATTRIBUTE, &pProp);
  1846. if (S_OK == hr)
  1847. {
  1848. SetAttrPropertyData(ImmIfIme->_GetLibTLS(),
  1849. ec,
  1850. pProp,
  1851. rangeSrc,
  1852. GUID_ATTR_MSIMTF_INPUT);
  1853. }
  1854. pProp->Release();
  1855. }
  1856. else
  1857. {
  1858. BOOL fEmpty;
  1859. if (SUCCEEDED(rangeSrc->IsEmpty(ec, &fEmpty)) && !fEmpty)
  1860. {
  1861. hr = ClearTextInRange(ec, rangeSrc, _pAImeContext);
  1862. }
  1863. }
  1864. #endif
  1865. //
  1866. // we just set a selection to the target string.
  1867. //
  1868. Interface<ITfRange> range;
  1869. if (SUCCEEDED(rangeSrc->Clone(range)))
  1870. {
  1871. LONG cchStart;
  1872. LONG cchEnd;
  1873. if (lpReconvertString->dwTargetStrOffset == 0 &&
  1874. lpReconvertString->dwTargetStrLen == 0 ) {
  1875. cchStart = lpReconvertString->dwCompStrOffset / sizeof(WCHAR);
  1876. cchEnd = lpReconvertString->dwCompStrOffset / sizeof(WCHAR) + lpReconvertString->dwCompStrLen;
  1877. }
  1878. else {
  1879. cchStart = lpReconvertString->dwTargetStrOffset / sizeof(WCHAR);
  1880. cchEnd = lpReconvertString->dwTargetStrOffset / sizeof(WCHAR) + lpReconvertString->dwTargetStrLen;
  1881. }
  1882. range->Collapse(ec, TF_ANCHOR_START);
  1883. //
  1884. // shift end first then shift start.
  1885. //
  1886. if ((SUCCEEDED(range->ShiftEnd(ec,
  1887. cchEnd,
  1888. &cch,
  1889. NULL))) &&
  1890. (SUCCEEDED(range->ShiftStart(ec,
  1891. cchStart,
  1892. &cch,
  1893. NULL))))
  1894. {
  1895. //
  1896. //
  1897. //
  1898. TF_SELECTION sel;
  1899. sel.range = range;
  1900. sel.style.ase = TF_AE_NONE;
  1901. sel.style.fInterimChar = FALSE;
  1902. ic->SetSelection(ec, 1, &sel);
  1903. hr = range->Clone(*rangeQuery);
  1904. }
  1905. }
  1906. }
  1907. }
  1908. }
  1909. delete [] lpReconvertString;
  1910. }
  1911. return hr;
  1912. }
  1913. /////////////////////////////////////////////////////////////////////////////
  1914. // ImmIfCalcRangePos
  1915. HRESULT
  1916. ImmIfCalcRangePos::CalcRangePos(
  1917. TfEditCookie ec,
  1918. Interface_Attach<ITfContext> ic,
  1919. Interface<ITfRange>* rangeSrc,
  1920. CWReconvertString* lpwReconvStr,
  1921. Interface_Attach<ImmIfIME> ImmIfIme
  1922. )
  1923. {
  1924. HRESULT hr;
  1925. Interface<ITfRange> pFullRange;
  1926. hr = ic->GetStart(ec, pFullRange);
  1927. if (SUCCEEDED(hr)) {
  1928. lpwReconvStr->m_CompStrIndex = 0;
  1929. lpwReconvStr->m_TargetStrIndex = 0;
  1930. BOOL equal = FALSE;
  1931. while (SUCCEEDED(hr=(*rangeSrc)->IsEqualStart(ec, pFullRange, TF_ANCHOR_START, &equal)) &&
  1932. ! equal) {
  1933. LONG cch;
  1934. hr = pFullRange->ShiftStart(ec, 1, &cch, NULL);
  1935. if (FAILED(hr))
  1936. break;
  1937. lpwReconvStr->m_CompStrIndex++;
  1938. lpwReconvStr->m_TargetStrIndex++;
  1939. }
  1940. if (S_OK == hr) {
  1941. lpwReconvStr->m_CompStrLen = 0;
  1942. lpwReconvStr->m_TargetStrLen = 0;
  1943. Interface<ITfRange> rangeTmp;
  1944. if (SUCCEEDED(hr=(*rangeSrc)->Clone(rangeTmp)))
  1945. {
  1946. BOOL fEmpty;
  1947. WCHAR wstr[256 + 1];
  1948. ULONG ul = 0;
  1949. while (rangeTmp->IsEmpty(ec, &fEmpty) == S_OK && !fEmpty)
  1950. {
  1951. ULONG ulcch;
  1952. rangeTmp->GetText(ec,
  1953. TF_TF_MOVESTART,
  1954. wstr,
  1955. ARRAYSIZE(wstr) - 1,
  1956. &ulcch);
  1957. ul += ulcch;
  1958. }
  1959. //
  1960. // Hack for Satori
  1961. // Satori receives empty range with Reconversion->QueryRange().
  1962. // Apps couldn't call reconversion.
  1963. //
  1964. if (ul == 0) {
  1965. ul++;
  1966. }
  1967. lpwReconvStr->m_CompStrLen = (LONG)ul;
  1968. lpwReconvStr->m_TargetStrLen = (LONG)ul;
  1969. }
  1970. }
  1971. }
  1972. return hr;
  1973. }
  1974. /////////////////////////////////////////////////////////////////////////////
  1975. // ImmIfGetSelection
  1976. HRESULT
  1977. ImmIfGetSelection::GetSelection(
  1978. TfEditCookie ec,
  1979. Interface_Attach<ITfContext> ic,
  1980. Interface<ITfRange>* rangeSrc,
  1981. Interface_Attach<ImmIfIME> ImmIfIme
  1982. )
  1983. {
  1984. Interface_TFSELECTION sel;
  1985. ULONG cFetched;
  1986. if (ic->GetSelection(ec, TF_DEFAULT_SELECTION, 1, sel, &cFetched) != S_OK)
  1987. return E_FAIL;
  1988. return sel->range->Clone(*rangeSrc);
  1989. }
  1990. /////////////////////////////////////////////////////////////////////////////
  1991. // ImmIfGetReadOnlyPropMargin
  1992. HRESULT
  1993. ImmIfGetReadOnlyPropMargin::GetReadOnlyPropMargin(
  1994. TfEditCookie ec,
  1995. Interface_Attach<ITfContext> ic,
  1996. Interface<ITfRangeACP>* rangeSrc,
  1997. INT_PTR* cch,
  1998. Interface_Attach<ImmIfIME> ImmIfIme
  1999. )
  2000. {
  2001. HRESULT hr;
  2002. Interface<ITfRange> range_readonly_prop;
  2003. *cch = 0;
  2004. //
  2005. // Create the range that covers start of text to rangeSrc.
  2006. //
  2007. if (FAILED(hr=ic->GetStart(ec, range_readonly_prop)))
  2008. return hr;
  2009. if (FAILED(hr=range_readonly_prop->ShiftEndToRange(ec, *rangeSrc, TF_ANCHOR_START)))
  2010. return hr;
  2011. //
  2012. // same ?
  2013. //
  2014. BOOL empty;
  2015. if (FAILED(hr=range_readonly_prop->IsEmpty(ec, &empty)))
  2016. return hr;
  2017. if (empty)
  2018. return S_OK;
  2019. //
  2020. // find the first non readonly range in the text store.
  2021. //
  2022. ITfProperty *prop;
  2023. if (SUCCEEDED(ic->GetProperty(GUID_PROP_MSIMTF_READONLY, &prop)))
  2024. {
  2025. IEnumTfRanges *enumranges;
  2026. if (SUCCEEDED(prop->EnumRanges(ec, &enumranges, range_readonly_prop)))
  2027. {
  2028. ITfRange *rangeTmp;
  2029. while (enumranges->Next(1, &rangeTmp, NULL) == S_OK)
  2030. {
  2031. VARIANT var;
  2032. QuickVariantInit(&var);
  2033. prop->GetValue(ec, rangeTmp, &var);
  2034. if ((var.vt == VT_I4) && (var.lVal != 0))
  2035. {
  2036. while (rangeTmp->IsEmpty(ec, &empty) == S_OK && !empty)
  2037. {
  2038. WCHAR wstr[256 + 1];
  2039. ULONG ulcch;
  2040. rangeTmp->GetText(ec,
  2041. TF_TF_MOVESTART,
  2042. wstr,
  2043. ARRAYSIZE(wstr) - 1,
  2044. &ulcch);
  2045. *cch += ulcch;
  2046. }
  2047. }
  2048. rangeTmp->Release();
  2049. }
  2050. enumranges->Release();
  2051. }
  2052. prop->Release();
  2053. }
  2054. return S_OK;
  2055. }
  2056. /////////////////////////////////////////////////////////////////////////////
  2057. // ImmIfGetCursorPosition
  2058. HRESULT
  2059. ImmIfGetCursorPosition::GetCursorPosition(
  2060. TfEditCookie ec,
  2061. HIMC hIMC,
  2062. Interface_Attach<ITfContext> ic,
  2063. CWCompCursorPos* lpwCursorPosition,
  2064. Interface_Attach<ImmIfIME> ImmIfIme
  2065. )
  2066. {
  2067. HRESULT hr;
  2068. LIBTHREAD *pLibTLS = ImmIfIme->_GetLibTLS();
  2069. IMCLock imc(hIMC);
  2070. if (FAILED(hr = imc.GetResult()))
  2071. return hr;
  2072. BOOL bInWriteSession;
  2073. if (FAILED(hr = ic->InWriteSession(ImmIfIme->GetClientId(), &bInWriteSession)))
  2074. return hr;
  2075. Interface<ITfRange> FullTextRange;
  2076. LONG lTextLength;
  2077. if (FAILED(hr=GetAllTextRange(ec, ic, &FullTextRange, &lTextLength)))
  2078. return hr;
  2079. CWCompString CompStr;
  2080. CWCompAttribute CompAttr;
  2081. if (FAILED(hr = _GetTextAndAttribute(pLibTLS, ec, imc, ic,
  2082. FullTextRange,
  2083. CompStr,
  2084. CompAttr,
  2085. bInWriteSession))) {
  2086. return hr;
  2087. }
  2088. if (FAILED(hr = _GetCursorPosition(ec, imc, ic, *lpwCursorPosition, CompAttr))) {
  2089. return hr;
  2090. }
  2091. return hr;
  2092. }