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.

389 lines
12 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 "cime.h"
  13. #include "txtevcb.h"
  14. #include "immif.h"
  15. #include "editses.h"
  16. // from ctf\sapilayr\globals.cpp
  17. const GUID GUID_ATTR_SAPI_GREENBAR =
  18. {
  19. 0xc3a9e2e8,
  20. 0x738c,
  21. 0x48e0,
  22. {0xac, 0xc8, 0x43, 0xee, 0xfa, 0xbf, 0x83, 0xc8}
  23. };
  24. BOOL CTextEventSinkCallBack::_IsSapiFeedbackUIPresent(
  25. Interface_Attach<ITfContext>& ic,
  26. TESENDEDIT *ee
  27. )
  28. {
  29. EnumROPropertyArgs args;
  30. args.comp_guid = GUID_ATTR_SAPI_GREENBAR;
  31. if (FAILED(ic->GetProperty(GUID_PROP_ATTRIBUTE, args.Property)))
  32. return FALSE;
  33. Interface<IEnumTfRanges> EnumReadOnlyProperty;
  34. if (FAILED(args.Property->EnumRanges(ee->ecReadOnly, EnumReadOnlyProperty, NULL)))
  35. return FALSE;
  36. args.ec = ee->ecReadOnly;
  37. args.pLibTLS = m_pImmIfIME->_GetLibTLS();
  38. CEnumrateInterface<IEnumTfRanges,
  39. ITfRange,
  40. EnumROPropertyArgs> Enumrate(EnumReadOnlyProperty,
  41. EnumReadOnlyRangeCallback,
  42. &args); // Argument of callback func.
  43. ENUM_RET ret_prop_attribute = Enumrate.DoEnumrate();
  44. if (ret_prop_attribute == ENUM_FIND)
  45. return TRUE;
  46. return FALSE;
  47. }
  48. // static
  49. HRESULT
  50. CTextEventSinkCallBack::TextEventSinkCallback(
  51. UINT uCode,
  52. void *pv,
  53. void *pvData
  54. )
  55. {
  56. IMTLS *ptls;
  57. DebugMsg(TF_FUNC, "TextEventSinkCallback");
  58. ASSERT(uCode == ICF_TEXTDELTA); // the pvData cast only works in this case
  59. if (uCode != ICF_TEXTDELTA)
  60. return S_OK;
  61. CTextEventSinkCallBack* _this = (CTextEventSinkCallBack*)pv;
  62. ASSERT(_this);
  63. ImmIfIME* _ImmIfIME = _this->m_pImmIfIME;
  64. ASSERT(_ImmIfIME);
  65. TESENDEDIT* ee = (TESENDEDIT*)pvData;
  66. ASSERT(ee);
  67. HRESULT hr;
  68. IMCLock imc(_this->m_hIMC);
  69. if (FAILED(hr = imc.GetResult()))
  70. return hr;
  71. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  72. if (_pAImeContext == NULL)
  73. return E_FAIL;
  74. ASSERT(_pAImeContext != NULL);
  75. #ifdef UNSELECTCHECK
  76. if (!_pAImeContext->m_fSelected)
  77. return S_OK;
  78. #endif UNSELECTCHECK
  79. Interface_Attach<ITfContext> ic(_pAImeContext->GetInputContext());
  80. #if 0
  81. //
  82. // What we want to do here is a check of reentrancy of this event sink.
  83. //
  84. BOOL fInWrite;
  85. if (FAILED(hr = ic->InWriteSession(_ImmIfIME->GetClientId(), &fInWrite)))
  86. return hr;
  87. Assert(!fInWrite);
  88. #endif
  89. BOOL fLangEA = TRUE;
  90. BOOL fComp = TRUE;
  91. BOOL fSapiFeedback = TRUE;
  92. /*
  93. * if EA language, then we have composition text.
  94. */
  95. if ((ptls = IMTLS_GetOrAlloc()) == NULL)
  96. return E_FAIL;
  97. LANGID langid;
  98. ptls->pAImeProfile->GetLangId(&langid);
  99. if (PRIMARYLANGID(langid) == LANG_JAPANESE ||
  100. PRIMARYLANGID(langid) == LANG_KOREAN ||
  101. PRIMARYLANGID(langid) == LANG_CHINESE ) {
  102. // need to check speech feedback UI for these lang too
  103. BOOL fFeedback = _this->_IsSapiFeedbackUIPresent(ic, ee);
  104. /*
  105. * This is automatic detection code of the Hangul + alphanumeric input
  106. * If detected a Hangul + alphanumeric, then we finalized all text.
  107. */
  108. EnumROPropertyArgs args;
  109. args.comp_guid = GUID_NULL;
  110. if (FAILED(hr=ic->GetProperty(GUID_PROP_COMPOSING, args.Property)))
  111. return hr;
  112. Interface<IEnumTfRanges> EnumReadOnlyProperty;
  113. hr = args.Property->EnumRanges(ee->ecReadOnly, EnumReadOnlyProperty, NULL);
  114. if (FAILED(hr))
  115. return hr;
  116. args.ec = ee->ecReadOnly;
  117. args.pLibTLS = _ImmIfIME->_GetLibTLS();
  118. CEnumrateInterface<IEnumTfRanges,
  119. ITfRange,
  120. EnumROPropertyArgs> Enumrate(EnumReadOnlyProperty,
  121. EnumReadOnlyRangeCallback,
  122. &args); // Argument of callback func.
  123. ENUM_RET ret_prop_composing = Enumrate.DoEnumrate();
  124. if (!fFeedback && ret_prop_composing != ENUM_FIND)
  125. fComp = FALSE;
  126. }
  127. else {
  128. /*
  129. * if not EA language and not SAPI, then we immediately finalize the text.
  130. */
  131. fLangEA = FALSE;
  132. EnumROPropertyArgs args;
  133. args.comp_guid = GUID_ATTR_SAPI_GREENBAR;
  134. if (FAILED(hr=ic->GetProperty(GUID_PROP_ATTRIBUTE, args.Property)))
  135. return hr;
  136. Interface<IEnumTfRanges> EnumReadOnlyProperty;
  137. hr = args.Property->EnumRanges(ee->ecReadOnly, EnumReadOnlyProperty, NULL);
  138. if (FAILED(hr))
  139. return hr;
  140. args.ec = ee->ecReadOnly;
  141. args.pLibTLS = _ImmIfIME->_GetLibTLS();
  142. CEnumrateInterface<IEnumTfRanges,
  143. ITfRange,
  144. EnumROPropertyArgs> Enumrate(EnumReadOnlyProperty,
  145. EnumReadOnlyRangeCallback,
  146. &args); // Argument of callback func.
  147. ENUM_RET ret_prop_attribute = Enumrate.DoEnumrate();
  148. if (ret_prop_attribute != ENUM_FIND)
  149. fSapiFeedback = FALSE;
  150. }
  151. //
  152. // Update composition and generate WM_IME_COMPOSITION
  153. //
  154. // if EA lang and there is composition property range.
  155. // - EA has a hIMC composition by default.
  156. //
  157. // if non EA lang and there is SAPI green bar.
  158. // - there is only hIMC composition if there is Speech Green bar.
  159. //
  160. // if Reconversion just started.
  161. // - because some tip may not change the text yet.
  162. // then there is no composition range yet.
  163. //
  164. // if now clearing DocFeed buffer.
  165. // - because the change happens in read-only text
  166. // nothing in hIMC changes.
  167. //
  168. if ((fLangEA && fComp) ||
  169. (!fLangEA && fSapiFeedback) ||
  170. _pAImeContext->IsInReconvertEditSession() ||
  171. _pAImeContext->IsInClearDocFeedEditSession())
  172. {
  173. //
  174. // Retreive text delta
  175. //
  176. const GUID guid = GUID_PROP_COMPOSING;
  177. const GUID *pguid = &guid;
  178. Interface<IEnumTfRanges> EnumPropertyUpdate;
  179. hr = ee->pEditRecord->GetTextAndPropertyUpdates(0, // dwFlags
  180. &pguid, 1,
  181. EnumPropertyUpdate);
  182. if (SUCCEEDED(hr)) {
  183. EnumPropertyUpdateArgs args(ic.GetPtr(), _ImmIfIME, imc);
  184. if (FAILED(hr=ic->GetProperty(GUID_PROP_COMPOSING, args.Property)))
  185. return hr;
  186. args.ec = ee->ecReadOnly;
  187. args.dwDeltaStart = 0;
  188. CEnumrateInterface<IEnumTfRanges,
  189. ITfRange,
  190. EnumPropertyUpdateArgs> Enumrate(EnumPropertyUpdate,
  191. EnumPropertyUpdateCallback,
  192. &args); // Argument of callback func.
  193. ENUM_RET ret_prop_update = Enumrate.DoEnumrate();
  194. if (ret_prop_update == ENUM_FIND) {
  195. //
  196. // Update composition string with delta start position
  197. //
  198. return _ImmIfIME->_UpdateCompositionString(args.dwDeltaStart);
  199. }
  200. }
  201. //
  202. // Update composition string
  203. //
  204. return _ImmIfIME->_UpdateCompositionString();
  205. }
  206. else {
  207. #if 0
  208. //
  209. // Review:
  210. //
  211. // need to be reviewed by Matsubara-san.
  212. // Why we need this? We can not assume tip always set the new
  213. // selection.
  214. //
  215. BOOL fChanged;
  216. hr = ee->pEditRecord->GetSelectionStatus(&fChanged);
  217. if (FAILED(hr))
  218. return hr;
  219. if (! fChanged)
  220. /*
  221. * If no change selection status, then return it.
  222. */
  223. return S_FALSE;
  224. #endif
  225. //
  226. // Clear DocFeed range's text store.
  227. // Find GUID_PROP_MSIMTF_READONLY property and SetText(NULL).
  228. //
  229. // ImmIfIME::ClearDocFeedBuffer() essential function for all ESCB_RECONVERTSTRING's edit
  230. // session except only ImmIfIME::SetupDocFeedString() since this is provided for keyboard
  231. // TIP's DocFeeding.
  232. //
  233. _ImmIfIME->ClearDocFeedBuffer(_pAImeContext->GetInputContext(), imc, FALSE); // No TF_ES_SYNC
  234. //
  235. // Composition complete.
  236. //
  237. return _ImmIfIME->_CompComplete(imc, FALSE); // No TF_ES_SYNC
  238. }
  239. }
  240. // static
  241. ENUM_RET
  242. CTextEventSinkCallBack::EnumReadOnlyRangeCallback(
  243. ITfRange* pRange,
  244. EnumROPropertyArgs *pargs
  245. )
  246. {
  247. ENUM_RET ret = ENUM_CONTINUE;
  248. VARIANT var;
  249. QuickVariantInit(&var);
  250. HRESULT hr = pargs->Property->GetValue(pargs->ec, pRange, &var);
  251. if (SUCCEEDED(hr)) {
  252. if (IsEqualIID(pargs->comp_guid, GUID_NULL)) {
  253. if ((V_VT(&var) == VT_I4 && V_I4(&var) != 0))
  254. ret = ENUM_FIND;
  255. }
  256. else if (V_VT(&var) == VT_I4) {
  257. TfGuidAtom guid = V_I4(&var);
  258. if (IsEqualTFGUIDATOM(pargs->pLibTLS, guid, pargs->comp_guid))
  259. ret = ENUM_FIND;
  260. }
  261. }
  262. VariantClear(&var);
  263. return ret;
  264. }
  265. // static
  266. ENUM_RET
  267. CTextEventSinkCallBack::EnumPropertyUpdateCallback(
  268. ITfRange* update_range,
  269. EnumPropertyUpdateArgs *pargs
  270. )
  271. {
  272. ENUM_RET ret = ENUM_CONTINUE;
  273. VARIANT var;
  274. QuickVariantInit(&var);
  275. HRESULT hr = pargs->Property->GetValue(pargs->ec, update_range, &var);
  276. if (SUCCEEDED(hr)) {
  277. if ((V_VT(&var) == VT_I4 && V_I4(&var) != 0)) {
  278. Interface_Creator<ImmIfEditSession> _pEditSession(
  279. new ImmIfEditSession(ESCB_GET_ALL_TEXT_RANGE,
  280. pargs->immif->GetClientId(),
  281. pargs->immif->GetCurrentInterface(),
  282. pargs->imc)
  283. );
  284. if (_pEditSession.Valid()) {
  285. Interface<ITfRange> full_range;
  286. if (SUCCEEDED(_pEditSession->RequestEditSession(TF_ES_READ | TF_ES_SYNC,
  287. &full_range))) {
  288. if (SUCCEEDED(full_range->ShiftEndToRange(pargs->ec, update_range, TF_ANCHOR_START))) {
  289. Interface<ITfRangeACP> unupdate_range;
  290. if (SUCCEEDED(full_range->QueryInterface(IID_ITfRangeACP, unupdate_range))) {
  291. LONG acpStart;
  292. LONG cch;
  293. if (SUCCEEDED(unupdate_range->GetExtent(&acpStart, &cch))) {
  294. pargs->dwDeltaStart = cch;
  295. ret = ENUM_FIND;
  296. }
  297. }
  298. }
  299. }
  300. }
  301. }
  302. }
  303. VariantClear(&var);
  304. return ret;
  305. }
  306. CTextEventSinkCallBack::CTextEventSinkCallBack(
  307. ImmIfIME* pImmIfIME,
  308. HIMC hIMC
  309. ) : m_pImmIfIME(pImmIfIME),
  310. CTextEventSink(TextEventSinkCallback, NULL)
  311. {
  312. m_pImmIfIME->AddRef();
  313. m_hIMC = hIMC;
  314. }
  315. CTextEventSinkCallBack::~CTextEventSinkCallBack(
  316. )
  317. {
  318. m_pImmIfIME->Release();
  319. }