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.

684 lines
21 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. txtevcb.cpp
  5. Abstract:
  6. This file implements the CTextEventSinkCallBack Class.
  7. Author:
  8. Revision History:
  9. Notes:
  10. --*/
  11. #include "private.h"
  12. #include "txtevcb.h"
  13. #include "ime.h"
  14. #include "editses.h"
  15. #include "context.h"
  16. #include "profile.h"
  17. // from ctf\sapilayr\globals.cpp
  18. const GUID GUID_ATTR_SAPI_GREENBAR = {
  19. 0xc3a9e2e8,
  20. 0x738c,
  21. 0x48e0,
  22. {0xac, 0xc8, 0x43, 0xee, 0xfa, 0xbf, 0x83, 0xc8}
  23. };
  24. //+---------------------------------------------------------------------------
  25. //
  26. // CTextEventSinkCallBack::_IsSapiFeedbackUIPresent
  27. //
  28. //----------------------------------------------------------------------------
  29. BOOL CTextEventSinkCallBack::_IsSapiFeedbackUIPresent(
  30. Interface_Attach<ITfContext>& ic,
  31. TESENDEDIT *ee
  32. )
  33. {
  34. EnumPropertyArgs args;
  35. args.comp_guid = GUID_ATTR_SAPI_GREENBAR;
  36. if (FAILED(ic->GetProperty(GUID_PROP_ATTRIBUTE, args.Property)))
  37. return FALSE;
  38. Interface<IEnumTfRanges> EnumReadOnlyProperty;
  39. if (FAILED(args.Property->EnumRanges(ee->ecReadOnly, EnumReadOnlyProperty, NULL)))
  40. return FALSE;
  41. args.ec = ee->ecReadOnly;
  42. args.pLibTLS = m_pLibTLS;
  43. CEnumrateInterface<IEnumTfRanges,
  44. ITfRange,
  45. EnumPropertyArgs> Enumrate(EnumReadOnlyProperty,
  46. EnumPropertyCallback,
  47. &args); // Argument of callback func.
  48. ENUM_RET ret_prop_attribute = Enumrate.DoEnumrate();
  49. if (ret_prop_attribute == ENUM_FIND)
  50. return TRUE;
  51. return FALSE;
  52. }
  53. //+---------------------------------------------------------------------------
  54. //
  55. // CTextEventSinkCallBack::_IsComposingPresent
  56. //
  57. //----------------------------------------------------------------------------
  58. BOOL CTextEventSinkCallBack::_IsComposingPresent(
  59. Interface_Attach<ITfContext>& ic,
  60. TESENDEDIT *ee
  61. )
  62. {
  63. /*
  64. * This is automatic detection code of the Hangul + alphanumeric input
  65. * If detected a Hangul + alphanumeric, then we finalized all text.
  66. */
  67. EnumTrackPropertyArgs args;
  68. const GUID *guids[] = {&GUID_PROP_COMPOSING,
  69. &GUID_PROP_MSIMTF_PREPARE_RECONVERT};
  70. const int guid_size = sizeof(guids) / sizeof(GUID*);
  71. args.guids = (GUID**)guids;
  72. args.num_guids = guid_size;
  73. if (FAILED(ic->TrackProperties(guids, args.num_guids, // system property
  74. NULL, 0, // application property
  75. args.Property)))
  76. return FALSE;
  77. //
  78. // get the text range that does not include read only area for
  79. // reconversion.
  80. //
  81. Interface<ITfRange> rangeAllText;
  82. LONG cch;
  83. if (FAILED(ImmIfEditSessionCallBack::GetAllTextRange(ee->ecReadOnly,
  84. ic,
  85. &rangeAllText,
  86. &cch)))
  87. return FALSE;
  88. Interface<IEnumTfRanges> EnumReadOnlyProperty;
  89. if (FAILED(args.Property->EnumRanges(ee->ecReadOnly, EnumReadOnlyProperty, rangeAllText)))
  90. return FALSE;
  91. args.ec = ee->ecReadOnly;
  92. args.pLibTLS = m_pLibTLS;
  93. CEnumrateInterface<IEnumTfRanges,
  94. ITfRange,
  95. EnumTrackPropertyArgs> Enumrate(EnumReadOnlyProperty,
  96. EnumTrackPropertyCallback,
  97. &args); // Argument of callback func.
  98. ENUM_RET ret_prop_composing = Enumrate.DoEnumrate();
  99. if (ret_prop_composing == ENUM_FIND)
  100. return TRUE;
  101. return FALSE;
  102. }
  103. //+---------------------------------------------------------------------------
  104. //
  105. // CTextEventSinkCallBack::_IsInterim
  106. //
  107. //----------------------------------------------------------------------------
  108. BOOL CTextEventSinkCallBack::_IsInterim(
  109. Interface_Attach<ITfContext>& ic,
  110. TESENDEDIT *ee
  111. )
  112. {
  113. Interface_TFSELECTION sel;
  114. ULONG cFetched;
  115. if (ic->GetSelection(ee->ecReadOnly, TF_DEFAULT_SELECTION, 1, sel, &cFetched) != S_OK)
  116. return FALSE;
  117. if (sel->style.fInterimChar) {
  118. return TRUE;
  119. }
  120. return FALSE;
  121. }
  122. //+---------------------------------------------------------------------------
  123. //
  124. // CTextEventSinkCallBack::_IsCompositionChanged
  125. //
  126. //----------------------------------------------------------------------------
  127. BOOL CTextEventSinkCallBack::_IsCompositionChanged(
  128. Interface_Attach<ITfContext>& ic,
  129. TESENDEDIT *ee
  130. )
  131. {
  132. ENUM_RET enumret;
  133. BOOL fChanged;
  134. if (SUCCEEDED(ee->pEditRecord->GetSelectionStatus(&fChanged)))
  135. {
  136. if (fChanged)
  137. return TRUE;
  138. }
  139. //
  140. // Find GUID_PROP_MSIMTF_TRACKCOMPOSITION property.
  141. //
  142. EnumFindFirstTrackCompRangeArgs argsFindFirstTrackCompRange;
  143. Interface<ITfProperty> PropertyTrackComposition;
  144. if (FAILED(ic->GetProperty(GUID_PROP_MSIMTF_TRACKCOMPOSITION,
  145. argsFindFirstTrackCompRange.Property)))
  146. return FALSE;
  147. Interface<IEnumTfRanges> EnumFindFirstTrackCompRange;
  148. if (FAILED(argsFindFirstTrackCompRange.Property->EnumRanges(ee->ecReadOnly,
  149. EnumFindFirstTrackCompRange,
  150. NULL)))
  151. return FALSE;
  152. argsFindFirstTrackCompRange.ec = ee->ecReadOnly;
  153. CEnumrateInterface<IEnumTfRanges,
  154. ITfRange,
  155. EnumFindFirstTrackCompRangeArgs> EnumrateFindFirstTrackCompRange(
  156. EnumFindFirstTrackCompRange,
  157. EnumFindFirstTrackCompRangeCallback,
  158. &argsFindFirstTrackCompRange);
  159. enumret = EnumrateFindFirstTrackCompRange.DoEnumrate();
  160. //
  161. // if there is no track composition property,
  162. // the composition has been changed since we put it.
  163. //
  164. if (enumret != ENUM_FIND)
  165. return TRUE;
  166. Interface<ITfRange> rangeTrackComposition;
  167. if (FAILED(argsFindFirstTrackCompRange.Range->Clone(rangeTrackComposition)))
  168. return FALSE;
  169. //
  170. // get the text range that does not include read only area for
  171. // reconversion.
  172. //
  173. Interface<ITfRange> rangeAllText;
  174. LONG cch;
  175. if (FAILED(ImmIfEditSessionCallBack::GetAllTextRange(ee->ecReadOnly,
  176. ic,
  177. &rangeAllText,
  178. &cch)))
  179. return FALSE;
  180. LONG lResult;
  181. if (FAILED(rangeTrackComposition->CompareStart(ee->ecReadOnly,
  182. rangeAllText,
  183. TF_ANCHOR_START,
  184. &lResult)))
  185. return FALSE;
  186. //
  187. // if the start position of the track composition range is not
  188. // the beggining of IC,
  189. // the composition has been changed since we put it.
  190. //
  191. if (lResult != 0)
  192. return TRUE;
  193. if (FAILED(rangeTrackComposition->CompareEnd(ee->ecReadOnly,
  194. rangeAllText,
  195. TF_ANCHOR_END,
  196. &lResult)))
  197. return FALSE;
  198. //
  199. // if the start position of the track composition range is not
  200. // the beggining of IC,
  201. // the composition has been changed since we put it.
  202. //
  203. if (lResult != 0)
  204. return TRUE;
  205. //
  206. // If we find the changes in these property, we need to update hIMC.
  207. //
  208. const GUID *guids[] = {&GUID_PROP_COMPOSING,
  209. &GUID_PROP_ATTRIBUTE,
  210. &GUID_PROP_READING,
  211. &GUID_PROP_MSIMTF_PREPARE_RECONVERT};
  212. const int guid_size = sizeof(guids) / sizeof(GUID*);
  213. Interface<IEnumTfRanges> EnumPropertyChanged;
  214. if (FAILED(ee->pEditRecord->GetTextAndPropertyUpdates(TF_GTP_INCL_TEXT,
  215. guids, guid_size,
  216. EnumPropertyChanged)))
  217. return FALSE;
  218. EnumPropertyChangedCallbackArgs args;
  219. args.ec = ee->ecReadOnly;
  220. CEnumrateInterface<IEnumTfRanges,
  221. ITfRange,
  222. EnumPropertyChangedCallbackArgs> Enumrate(EnumPropertyChanged,
  223. EnumPropertyChangedCallback,
  224. &args);
  225. enumret = Enumrate.DoEnumrate();
  226. if (enumret == ENUM_FIND)
  227. return TRUE;
  228. return FALSE;
  229. }
  230. //+---------------------------------------------------------------------------
  231. //
  232. // CTextEventSinkCallBack::TextEventSinkCallback
  233. //
  234. //----------------------------------------------------------------------------
  235. // static
  236. HRESULT
  237. CTextEventSinkCallBack::TextEventSinkCallback(
  238. UINT uCode,
  239. void *pv,
  240. void *pvData
  241. )
  242. {
  243. DebugMsg(TF_FUNC, TEXT("TextEventSinkCallback"));
  244. ASSERT(uCode == ICF_TEXTDELTA); // the pvData cast only works in this case
  245. if (uCode != ICF_TEXTDELTA)
  246. return S_OK;
  247. CTextEventSinkCallBack* _this = (CTextEventSinkCallBack*)pv;
  248. ASSERT(_this);
  249. TESENDEDIT* ee = (TESENDEDIT*)pvData;
  250. ASSERT(ee);
  251. HRESULT hr;
  252. IMCLock imc(_this->m_hIMC);
  253. if (FAILED(hr = imc.GetResult()))
  254. return hr;
  255. IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
  256. if (FAILED(hr=imc_ctfime.GetResult()))
  257. return hr;
  258. CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
  259. if (_pCicContext == NULL)
  260. return E_FAIL;
  261. ASSERT(_pCicContext != NULL);
  262. #ifdef UNSELECTCHECK
  263. if (!_pAImeContext->m_fSelected)
  264. return S_OK;
  265. #endif UNSELECTCHECK
  266. Interface_Attach<ITfContext> ic(_pCicContext->GetInputContext());
  267. /*
  268. * We have composition text.
  269. */
  270. TLS* ptls = TLS::GetTLS();
  271. if (ptls == NULL)
  272. {
  273. return E_OUTOFMEMORY;
  274. }
  275. BOOL fInReconvertEditSession;
  276. fInReconvertEditSession = _pCicContext->m_fInReconvertEditSession.IsSetFlag();
  277. if (!_this->_IsCompositionChanged(ic, ee))
  278. return S_OK;
  279. BOOL fComp;
  280. BOOL fSapiFeedback;
  281. // need to check speech feedback UI.
  282. fSapiFeedback = _this->_IsSapiFeedbackUIPresent(ic, ee);
  283. fComp = _this->_IsComposingPresent(ic, ee);
  284. LANGID langid;
  285. CicProfile* _pProfile = ptls->GetCicProfile();
  286. if (_pProfile == NULL)
  287. {
  288. DebugMsg(TF_ERROR, TEXT("CTextEventSinkCallBack::TextEventSinkCallback. _pProfile==NULL."));
  289. return E_OUTOFMEMORY;
  290. }
  291. _pProfile->GetLangId(&langid);
  292. switch (PRIMARYLANGID(langid))
  293. {
  294. case LANG_KOREAN:
  295. //
  296. // We will finalize Korean composition string immediately if it
  297. // doesn't set the interim definition. For example, Korean
  298. // Handwriting TIP case.
  299. //
  300. // Bug#482983 - Notepad doesn't support the level 2 composition
  301. // window for Korean.
  302. //
  303. // And we should not do this during HanjaReConversion.
  304. //
  305. if (fComp && _pCicContext->m_fHanjaReConversion.IsResetFlag())
  306. {
  307. if (!(_this->_IsInterim(ic, ee)))
  308. {
  309. //
  310. // Reset fComp to false to complete the current composition
  311. // string.
  312. //
  313. fComp = FALSE;
  314. }
  315. }
  316. break;
  317. case LANG_JAPANESE:
  318. case LANG_CHINESE:
  319. break;
  320. default:
  321. //
  322. // #500698
  323. //
  324. // Reset fComp to false to complete the current composition
  325. // string.
  326. //
  327. if (!ptls->NonEACompositionEnabled())
  328. {
  329. fComp = FALSE;
  330. }
  331. break;
  332. }
  333. //
  334. // Update composition and generate WM_IME_COMPOSITION
  335. //
  336. // if there is SAPI green bar.
  337. // - there is only hIMC composition if there is Speech Green bar.
  338. //
  339. // if Reconversion just started.
  340. // - because some tip may not change the text yet.
  341. // then there is no composition range yet.
  342. //
  343. // if now clearing DocFeed buffer.
  344. // - because the change happens in read-only text
  345. // nothing in hIMC changes.
  346. //
  347. if (fComp || fSapiFeedback || fInReconvertEditSession ||
  348. _pCicContext->m_fInClearDocFeedEditSession.IsSetFlag())
  349. {
  350. //
  351. // Retreive text delta from GUID_PROP_COMPOSING
  352. //
  353. const GUID *guids[] = {&GUID_PROP_COMPOSING};
  354. const int guid_size = sizeof(guids) / sizeof(GUID*);
  355. Interface<IEnumTfRanges> EnumPropertyUpdate;
  356. hr = ee->pEditRecord->GetTextAndPropertyUpdates(0, // dwFlags
  357. guids, guid_size,
  358. EnumPropertyUpdate);
  359. if (SUCCEEDED(hr)) {
  360. EnumPropertyUpdateArgs args(ic.GetPtr(), _this->m_tid, imc, _this->m_pLibTLS);
  361. if (FAILED(hr=ic->GetProperty(GUID_PROP_COMPOSING, args.Property)))
  362. return hr;
  363. args.ec = ee->ecReadOnly;
  364. args.dwDeltaStart = 0;
  365. CEnumrateInterface<IEnumTfRanges,
  366. ITfRange,
  367. EnumPropertyUpdateArgs> Enumrate(EnumPropertyUpdate,
  368. EnumPropertyUpdateCallback,
  369. &args); // Argument of callback func.
  370. ENUM_RET ret_prop_update = Enumrate.DoEnumrate();
  371. if (ret_prop_update == ENUM_FIND) {
  372. //
  373. // Remove GUID_PROP_MSIMTF_PREPARE_RECONVERT property.
  374. //
  375. _this->EscbRemoveProperty(imc, &GUID_PROP_MSIMTF_PREPARE_RECONVERT);
  376. //
  377. // Update composition string with delta start position
  378. //
  379. return _this->EscbUpdateCompositionString(imc, args.dwDeltaStart);
  380. }
  381. }
  382. //
  383. // Update composition string
  384. //
  385. return _this->EscbUpdateCompositionString(imc);
  386. }
  387. else {
  388. //
  389. // Clear DocFeed range's text store.
  390. // Find GUID_PROP_MSIMTF_READONLY property and SetText(NULL).
  391. //
  392. // ImmIfIME::ClearDocFeedBuffer() essential function for all ESCB_RECONVERTSTRING's edit
  393. // session except only ImmIfIME::SetupDocFeedString() since this is provided for keyboard
  394. // TIP's DocFeeding.
  395. //
  396. _this->EscbClearDocFeedBuffer(imc, *_pCicContext, FALSE); // No TF_ES_SYNC
  397. //
  398. // Composition complete.
  399. //
  400. return _this->EscbCompComplete(imc, FALSE); // No TF_ES_SYNC
  401. }
  402. }
  403. //+---------------------------------------------------------------------------
  404. //
  405. // CTextEventSinkCallBack::EnumPropertyCallback
  406. //
  407. //----------------------------------------------------------------------------
  408. // static
  409. ENUM_RET
  410. CTextEventSinkCallBack::EnumPropertyCallback(
  411. ITfRange* pRange,
  412. EnumPropertyArgs *pargs
  413. )
  414. {
  415. ENUM_RET ret = ENUM_CONTINUE;
  416. VARIANT var;
  417. QuickVariantInit(&var);
  418. HRESULT hr = pargs->Property->GetValue(pargs->ec, pRange, &var);
  419. if (SUCCEEDED(hr)) {
  420. if (IsEqualIID(pargs->comp_guid, GUID_NULL)) {
  421. if ((V_VT(&var) == VT_I4 && V_I4(&var) != 0))
  422. ret = ENUM_FIND;
  423. }
  424. else if (V_VT(&var) == VT_I4) {
  425. TfGuidAtom guid = V_I4(&var);
  426. if (IsEqualTFGUIDATOM(pargs->pLibTLS, guid, pargs->comp_guid))
  427. ret = ENUM_FIND;
  428. }
  429. }
  430. VariantClear(&var);
  431. return ret;
  432. }
  433. //+---------------------------------------------------------------------------
  434. //
  435. // CTextEventSinkCallBack::EnumTrackPropertyCallback
  436. //
  437. //----------------------------------------------------------------------------
  438. // static
  439. ENUM_RET
  440. CTextEventSinkCallBack::EnumTrackPropertyCallback(
  441. ITfRange* pRange,
  442. EnumTrackPropertyArgs *pargs
  443. )
  444. {
  445. ENUM_RET ret = ENUM_CONTINUE;
  446. VARIANT var;
  447. QuickVariantInit(&var);
  448. HRESULT hr = pargs->Property->GetValue(pargs->ec, pRange, &var);
  449. if (SUCCEEDED(hr)) {
  450. Interface<IEnumTfPropertyValue> EnumPropVal;
  451. hr = var.punkVal->QueryInterface(IID_IEnumTfPropertyValue, EnumPropVal);
  452. if (SUCCEEDED(hr)) {
  453. TF_PROPERTYVAL tfPropertyVal;
  454. while (EnumPropVal->Next(1, &tfPropertyVal, NULL) == S_OK) {
  455. for (int i=0; i < pargs->num_guids; i++) {
  456. if (IsEqualGUID(tfPropertyVal.guidId, *pargs->guids[i])) {
  457. if ((V_VT(&tfPropertyVal.varValue) == VT_I4 && V_I4(&tfPropertyVal.varValue) != 0)) {
  458. ret = ENUM_FIND;
  459. break;
  460. }
  461. }
  462. }
  463. VariantClear(&tfPropertyVal.varValue);
  464. if (ret == ENUM_FIND)
  465. break;
  466. }
  467. }
  468. }
  469. VariantClear(&var);
  470. return ret;
  471. }
  472. //+---------------------------------------------------------------------------
  473. //
  474. // CTextEventSinkCallBack::EnumPropertyUpdateCallback
  475. //
  476. //----------------------------------------------------------------------------
  477. // static
  478. ENUM_RET
  479. CTextEventSinkCallBack::EnumPropertyUpdateCallback(
  480. ITfRange* update_range,
  481. EnumPropertyUpdateArgs *pargs
  482. )
  483. {
  484. ENUM_RET ret = ENUM_CONTINUE;
  485. VARIANT var;
  486. QuickVariantInit(&var);
  487. HRESULT hr = pargs->Property->GetValue(pargs->ec, update_range, &var);
  488. if (SUCCEEDED(hr)) {
  489. if ((V_VT(&var) == VT_I4 && V_I4(&var) != 0)) {
  490. Interface_Creator<ImmIfEditSession> _pEditSession(
  491. new ImmIfEditSession(ESCB_GET_ALL_TEXT_RANGE,
  492. pargs->imc,
  493. pargs->tid,
  494. pargs->ic.GetPtr(),
  495. pargs->pLibTLS)
  496. );
  497. if (_pEditSession.Valid()) {
  498. Interface<ITfRange> full_range;
  499. if (SUCCEEDED(_pEditSession->RequestEditSession(TF_ES_READ | TF_ES_SYNC,
  500. &full_range))) {
  501. if (SUCCEEDED(full_range->ShiftEndToRange(pargs->ec, update_range, TF_ANCHOR_START))) {
  502. Interface<ITfRangeACP> unupdate_range;
  503. if (SUCCEEDED(full_range->QueryInterface(IID_ITfRangeACP, unupdate_range))) {
  504. LONG acpStart;
  505. LONG cch;
  506. if (SUCCEEDED(unupdate_range->GetExtent(&acpStart, &cch))) {
  507. pargs->dwDeltaStart = cch;
  508. ret = ENUM_FIND;
  509. }
  510. }
  511. }
  512. }
  513. }
  514. }
  515. }
  516. VariantClear(&var);
  517. return ret;
  518. }
  519. //+---------------------------------------------------------------------------
  520. //
  521. // CTextEventSinkCallBack::EnumPropertyChangedCallback
  522. //
  523. //----------------------------------------------------------------------------
  524. // static
  525. ENUM_RET
  526. CTextEventSinkCallBack::EnumPropertyChangedCallback(
  527. ITfRange* update_range,
  528. EnumPropertyChangedCallbackArgs *pargs
  529. )
  530. {
  531. BOOL empty;
  532. if (update_range->IsEmpty(pargs->ec, &empty) == S_OK && empty)
  533. return ENUM_CONTINUE;
  534. return ENUM_FIND;
  535. }
  536. //+---------------------------------------------------------------------------
  537. //
  538. // CTextEventSinkCallBack::EnumPropertyChangedCallback
  539. //
  540. //----------------------------------------------------------------------------
  541. // static
  542. ENUM_RET
  543. CTextEventSinkCallBack::EnumFindFirstTrackCompRangeCallback(
  544. ITfRange* update_range,
  545. EnumFindFirstTrackCompRangeArgs *pargs
  546. )
  547. {
  548. ENUM_RET ret = ENUM_CONTINUE;
  549. VARIANT var;
  550. QuickVariantInit(&var);
  551. HRESULT hr = pargs->Property->GetValue(pargs->ec, update_range, &var);
  552. if (SUCCEEDED(hr))
  553. {
  554. if ((V_VT(&var) == VT_I4 && V_I4(&var) != 0))
  555. {
  556. update_range->Clone(pargs->Range);
  557. ret = ENUM_FIND;
  558. }
  559. }
  560. VariantClear(&var);
  561. return ret;
  562. }