Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

737 lines
22 KiB

  1. #include "private.h"
  2. #include "korimx.h"
  3. #include "timsink.h"
  4. #include "immxutil.h"
  5. #include "fnrecon.h"
  6. #include "helpers.h"
  7. #include "skbdmode.h"
  8. #include "osver.h"
  9. // REVIEW
  10. /*---------------------------------------------------------------------------
  11. CKorIMX::_EditSessionCallback
  12. ---------------------------------------------------------------------------*/
  13. HRESULT CKorIMX::_EditSessionCallback2(TfEditCookie ec, CEditSession2 *pes)
  14. {
  15. ITfContext* pic = pes->GetContext();
  16. CKorIMX* pKorTip = pes->GetTIP();
  17. ESSTRUCT* pess = pes->GetStruct();
  18. ITfRange* pRange;
  19. CHangulAutomata* pAutomata;
  20. LPWSTR pszCand = NULL;
  21. Assert(pic != NULL);
  22. Assert(pKorTip != NULL);
  23. if ((pKorTip == NULL) || (pic == NULL))
  24. return E_FAIL;
  25. switch (pess->id)
  26. {
  27. case ESCB_FINALIZECONVERSION:
  28. {
  29. CCandidateListEx *pCandList;
  30. CCandidateStringEx *pCandItem;
  31. pCandList = pess->pCandList;
  32. pCandItem = pess->pCandStr;
  33. pRange = pess->pRange;
  34. pszCand = pCandItem->m_psz;
  35. if (pszCand)
  36. {
  37. size_t cchCand = 0;
  38. StringCchLengthW(pszCand, CIC_KOR_CANDSTR_MAX, &cchCand);
  39. // Set Reading text
  40. SetTextAndReading(pKorTip->_GetLibTLS(), ec, pic, pRange,
  41. pszCand,
  42. cchCand,
  43. pCandItem->m_langid, pCandItem->m_pszRead);
  44. }
  45. pCandList->Release();
  46. // First complete current comp string
  47. if (pAutomata = pKorTip->GetAutomata(pic))
  48. pAutomata->MakeComplete();
  49. pKorTip->MakeResultString(ec, pic, pRange);
  50. pKorTip->CloseCandidateUIProc();
  51. break;
  52. }
  53. case ESCB_COMPLETE:
  54. {
  55. BOOL fReleaseRange = fFalse;
  56. // If No composition exist, nothing to complete
  57. if (pKorTip->GetIPComposition(pic) == NULL)
  58. break;
  59. pRange = pess->pRange;
  60. pAutomata = pKorTip->GetAutomata(pic);
  61. // Close cand UI if exist.
  62. pKorTip->CloseCandidateUIProc();
  63. if (pRange == NULL)
  64. {
  65. GetSelectionSimple(ec, pic, &pRange);
  66. fReleaseRange = fTrue;
  67. }
  68. if (pRange)
  69. {
  70. if (pAutomata)
  71. pAutomata->MakeComplete();
  72. pKorTip->MakeResultString(ec, pic, pRange);
  73. }
  74. if (fReleaseRange)
  75. {
  76. SafeRelease(pRange);
  77. }
  78. //return pKorTip->_MultiRangeConversion(ec, pes->_state.u, pic, pRange);
  79. break;
  80. }
  81. case ESCB_INSERT_PAD_STRING:
  82. {
  83. WCHAR szText[2];
  84. GetSelectionSimple(ec, pic, &pRange);
  85. szText[0] = (WCHAR)pess->wParam;
  86. szText[1] = L'\0';
  87. if (FAILED(pKorTip->SetInputString(ec, pic, pRange, szText, CKorIMX::GetLangID())))
  88. break;
  89. pKorTip->MakeResultString(ec, pic, pRange);
  90. SafeRelease(pRange);
  91. break;
  92. }
  93. case ESCB_KEYSTROKE:
  94. {
  95. WPARAM wParam = pess->wParam;
  96. LPARAM lParam = pess->lParam;
  97. return pKorTip->_Keystroke(ec, pic, wParam, lParam, (const BYTE *)pess->pv1);
  98. break;
  99. }
  100. // Complete and Selection range changed
  101. case ESCB_TEXTEVENT:
  102. if (pKorTip->IsKeyFocus() && (GetSelectionSimple(ec, pic, &pRange) == S_OK))
  103. {
  104. ITfComposition *pComposition;
  105. ITfRange *pRangeOldComp;
  106. //IEnumTfRanges *pEnumText = pess->pEnumRange;
  107. BOOL fChanged = fFalse;
  108. BOOL fEmpty;
  109. // Check modebias here
  110. if (pess->fBool)
  111. fChanged = pKorTip->CheckModeBias(ec, pic, pRange);
  112. //////////////////////////////////////////////////////////////////
  113. // To complete on mouse click we using Range change notification.
  114. // In future version, we could remove this code and use custom property
  115. // or reading string. Cutom property can hold Hangul Automata object.
  116. //
  117. // Office apps explicitly call complete but this for unknown Cicero apps.
  118. //////////////////////////////////////////////////////////////////
  119. pComposition = pKorTip->GetIPComposition(pic);
  120. if (pComposition == NULL)
  121. goto ExitTextEvent;
  122. // Office apps are not going through here.
  123. pComposition->GetRange(&pRangeOldComp);
  124. if (pRangeOldComp == NULL)
  125. goto ExitTextEvent;
  126. pRange->IsEmpty(ec, &fEmpty);
  127. if (fEmpty && (CR_EQUAL != CompareRanges(ec, pRange, pRangeOldComp)))
  128. {
  129. ITfProperty *pPropAttr;
  130. TfGuidAtom attr;
  131. // Clear attrib
  132. if (SUCCEEDED(pic->GetProperty(GUID_PROP_ATTRIBUTE, &pPropAttr)))
  133. {
  134. if (SUCCEEDED(GetAttrPropertyData(ec, pPropAttr, pRangeOldComp, &attr)))
  135. {
  136. if (pKorTip->IsKorIMX_GUID_ATOM(attr))
  137. {
  138. pPropAttr->Clear(ec, pRangeOldComp);
  139. }
  140. }
  141. pPropAttr->Release();
  142. }
  143. pAutomata = pKorTip->GetAutomata(pic);
  144. if (pAutomata)
  145. pAutomata->MakeComplete();
  146. pKorTip->EndIPComposition(ec, pic);
  147. // pKorTip->MakeResultString(ec, pic, pRangeOldComp);
  148. fChanged = fTrue;
  149. }
  150. SafeRelease(pRangeOldComp);
  151. ExitTextEvent:
  152. pRange->Release();
  153. // Close cand UI if exist.
  154. if (fChanged)
  155. pKorTip->CloseCandidateUIProc();
  156. }
  157. break;
  158. // case ESCB_RANGEBROKEN:
  159. // pKorTip->FlushIPRange(ec, pic);
  160. // break;
  161. case ESCB_CANDUI_CLOSECANDUI:
  162. // u : ESCB_CANDUI_CLOSECANDUI
  163. // pv : this
  164. // hwnd : - (not used)
  165. // wParam : - (not used)
  166. // lParam : - (not used)
  167. // pv1 : - (not used)
  168. // pv2 : - (not used)
  169. // pic : - (not used)
  170. // pRange : - (not used)
  171. // fBool : - (not used)
  172. pKorTip->CloseCandidateUIProc();
  173. break;
  174. // Hanja conv button up
  175. case ESCB_HANJA_CONV:
  176. // u : ESCB_HANJA_CONV
  177. // pv : this
  178. // hwnd : - (not used)
  179. // wParam : - (not used)
  180. // lParam : - (not used)
  181. // pv1 : - (not used)
  182. // pv2 : - (not used)
  183. // pic : - pic
  184. // pRange : - (not used)
  185. // fBool : - (not used)
  186. // O10 #220177: Simulate VK_HANJA key to invoke HHC
  187. if (GetAIMM(pic) && (IsOnNT5() || PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_JAPANESE))
  188. {
  189. keybd_event(VK_HANJA, 0, 0, 0);
  190. keybd_event(VK_HANJA, 0, KEYEVENTF_KEYUP, 0);
  191. }
  192. else
  193. if (GetSelectionSimple(ec, pic, &pRange) == S_OK)
  194. {
  195. if (pKorTip->GetIPComposition(pic))
  196. pKorTip->DoHanjaConversion(ec, pic, pRange);
  197. else
  198. pKorTip->Reconvert(pRange);
  199. SafeRelease(pRange);
  200. }
  201. // Update Hanja button
  202. if (pKorTip->m_pToolBar != NULL)
  203. pKorTip->m_pToolBar->Update(UPDTTB_HJMODE);
  204. break;
  205. ///////////////////////////////////////////////////////////////////////////
  206. // Reconversion Callbacks
  207. case ESCB_FINALIZERECONVERSION:
  208. {
  209. CCandidateListEx *pCandList = pess->pCandList;
  210. CCandidateStringEx *pCandItem = pess->pCandStr;
  211. pRange = pess->pRange;
  212. pszCand = pCandItem->m_psz;
  213. Assert(pRange != NULL);
  214. pKorTip->CloseCandidateUI(pic);
  215. if (GetAIMM(pic) == fFalse)
  216. {
  217. if (pszCand)
  218. {
  219. size_t cchCand = 0;
  220. StringCchLengthW(pszCand, CIC_KOR_CANDSTR_MAX, &cchCand);
  221. //ITfRange *pRangeTmp;
  222. SetTextAndReading(pKorTip->_GetLibTLS(), ec, pic, pRange,
  223. pszCand,
  224. cchCand,
  225. pCandItem->m_langid, pCandItem->m_pszRead);
  226. }
  227. // To clear current selection and composition
  228. pKorTip->MakeResultString(ec, pic, pRange);
  229. }
  230. else
  231. {
  232. if (pszCand)
  233. {
  234. pRange->SetText(ec, 0, pszCand, 1/* wcslen(pszCand)*/);
  235. SetSelectionSimple(ec, pic, pRange);
  236. }
  237. pKorTip->EndIPComposition(ec, pic);
  238. }
  239. // if hit reconversion on composition string, we need to clear automata.
  240. pAutomata = pKorTip->GetAutomata(pic);
  241. if (pRange && pAutomata && pAutomata->GetCompositionChar())
  242. pAutomata->MakeComplete();
  243. SafeRelease(pRange);
  244. break;
  245. }
  246. case ESCB_ONSELECTRECONVERSION:
  247. break;
  248. case ESCB_ONCANCELRECONVERSION:
  249. pRange = pess->pRange;
  250. pKorTip->CancelCandidate(ec, pic);
  251. if (GetAIMM(pic) == fFalse)
  252. {
  253. // To clear current selection and composition
  254. pKorTip->MakeResultString(ec, pic, pRange);
  255. }
  256. else
  257. pKorTip->EndIPComposition(ec, pic);
  258. // if hit reconversion on composition string, we need to clear automata.
  259. pAutomata = pKorTip->GetAutomata(pic);
  260. if (pRange && pAutomata && pAutomata->GetCompositionChar())
  261. pAutomata->MakeComplete();
  262. SafeRelease(pRange);
  263. break;
  264. case ESCB_RECONV_QUERYRECONV:
  265. {
  266. CFnReconversion *pReconv = (CFnReconversion *)pess->pv1;
  267. if (pKorTip->IsCandUIOpen())
  268. return E_FAIL;
  269. return pReconv->_QueryRange(ec, pic, pess->pRange, (ITfRange **)pess->pv2);
  270. }
  271. case ESCB_RECONV_GETRECONV:
  272. {
  273. CFnReconversion *pReconv = (CFnReconversion *)pess->pv1;
  274. if (pKorTip->IsCandUIOpen())
  275. return E_FAIL;
  276. return pReconv->_GetReconversion(ec, pic, pess->pRange, (CCandidateListEx **)pess->pv2, pess->fBool);
  277. }
  278. case ESCB_RECONV_SHOWCAND:
  279. {
  280. ITfComposition* pComposition;
  281. GUID attr;
  282. ITfProperty* pProp = NULL;
  283. pRange = pess->pRange;
  284. pComposition = pKorTip->GetIPComposition(pic);
  285. if (/*GetAIMM(pic) == fFalse && */ pComposition == NULL)
  286. {
  287. pKorTip->CreateIPComposition(ec, pic, pRange);
  288. // Set input attr and composing state.
  289. if (SUCCEEDED(pic->GetProperty(GUID_PROP_ATTRIBUTE, &pProp)))
  290. {
  291. attr = GUID_ATTR_KORIMX_INPUT;
  292. SetAttrPropertyData(pKorTip->_GetLibTLS(), ec, pProp, pRange, attr);
  293. pProp->Release();
  294. }
  295. }
  296. pKorTip->OpenCandidateUI(ec, pic, pess->pRange, pess->pCandList);
  297. break;
  298. }
  299. case ESCB_INIT_MODEBIAS:
  300. // Check mode bias
  301. //
  302. // id : ESCB_INIT_MODEBIAS
  303. // ptip : this
  304. // pic : pic
  305. pKorTip->InitializeModeBias(ec, pic);
  306. break;
  307. }
  308. return S_OK;
  309. }
  310. /*---------------------------------------------------------------------------
  311. CKorIMX::_DIMCallback
  312. ---------------------------------------------------------------------------*/
  313. /* static */
  314. HRESULT CKorIMX::_DIMCallback(UINT uCode, ITfDocumentMgr *pdimNew, ITfDocumentMgr *pdimPrev, void *pv)
  315. {
  316. ITfContext *pic = NULL;
  317. CKorIMX *pKorImx = (CKorIMX *)pv;
  318. Assert(pKorImx != NULL);
  319. switch (uCode)
  320. {
  321. case TIM_CODE_SETFOCUS:
  322. if (pdimPrev)
  323. {
  324. TraceMsg(DM_TRACE, TEXT("TIM_CODE_SETFOCUS: pdimPrev"));
  325. pdimPrev->GetTop(&pic);
  326. pKorImx->OnFocusChange(pic, fFalse);
  327. SafeRelease(pic);
  328. SafeReleaseClear(pKorImx->m_pCurrentDim);
  329. }
  330. if (pdimNew)
  331. {
  332. TraceMsg(DM_TRACE, TEXT("TIM_CODE_SETFOCUS: pdimNew"));
  333. SafeReleaseClear(pKorImx->m_pCurrentDim);
  334. // Set New dim
  335. pKorImx->m_pCurrentDim = pdimNew;
  336. pKorImx->m_pCurrentDim->AddRef();
  337. pdimNew->GetTop(&pic);
  338. pKorImx->OnFocusChange(pic, fTrue);
  339. if (pic)
  340. pic->Release();
  341. }
  342. break;
  343. }
  344. return S_OK;
  345. }
  346. /*---------------------------------------------------------------------------
  347. CKorIMX::_ICCallback
  348. Document Input Manager callback. ITfThreadMgrEventSink
  349. ---------------------------------------------------------------------------*/
  350. /* static */
  351. HRESULT CKorIMX::_ICCallback(UINT uCode, ITfContext *pic, void *pv)
  352. {
  353. CKorIMX *_this = (CKorIMX *)pv;
  354. switch (uCode)
  355. {
  356. case TIM_CODE_INITIC:
  357. if (!_this->IsPendingCleanup()) // ignore new ic's if we're being shutdown.
  358. {
  359. _this->_InitICPriv(pic);
  360. }
  361. break;
  362. case TIM_CODE_UNINITIC:
  363. _this->_DeleteICPriv(pic);
  364. break;
  365. }
  366. return S_OK;
  367. }
  368. /*---------------------------------------------------------------------------
  369. CKorIMX::_CompEventSinkCallback
  370. ---------------------------------------------------------------------------*/
  371. HRESULT CKorIMX::_CompEventSinkCallback(void *pv, REFGUID rguid)
  372. {
  373. CICPriv* picp = (CICPriv*)pv;
  374. ITfContext* pic;
  375. CKorIMX *_this;
  376. if (picp == NULL)
  377. return S_OK; // error
  378. pic = picp->GetIC();
  379. if (pic == NULL)
  380. return S_OK; // error
  381. _this = picp->GetIMX();
  382. if (_this == NULL || _this->m_pToolBar == NULL)
  383. return S_OK; // do nothinig
  384. // if Open/Close compartment
  385. if (IsEqualGUID(rguid, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE))
  386. {
  387. _this->m_pToolBar->Update(UPDTTB_CMODE|UPDTTB_FHMODE);
  388. }
  389. else
  390. // if conversion mode compartment
  391. if (IsEqualGUID(rguid, GUID_COMPARTMENT_KORIMX_CONVMODE))
  392. {
  393. DWORD dwConvMode = _this->GetConvMode(pic);
  394. BOOL fIsOn = _this->IsOn(pic);
  395. // We just open for Hangul mode do not close for Alphanumeric mode for Cicero full aware apps.
  396. // This will prevent redundant Open/Close compartment call.
  397. if (dwConvMode == TIP_ALPHANUMERIC_MODE && fIsOn)
  398. _this->SetOnOff(pic, fFalse);
  399. else
  400. if (dwConvMode != TIP_ALPHANUMERIC_MODE && fIsOn == fFalse)
  401. _this->SetOnOff(pic, fTrue);
  402. _this->m_pToolBar->Update(UPDTTB_CMODE|UPDTTB_FHMODE);
  403. }
  404. else
  405. // if SoftKeyboard compartmemnt
  406. if (IsEqualGUID(rguid, GUID_COMPARTMENT_KOR_SOFTKBD_OPENCLOSE))
  407. {
  408. BOOL fSkbdOn = _this->GetSoftKBDOnOff();
  409. _this->ShowSoftKBDWindow(fSkbdOn);
  410. if (_this->m_pToolBar && _this->m_pToolBar->GetSkbdMode())
  411. _this->m_pToolBar->GetSkbdMode()->UpdateToggle();
  412. }
  413. else
  414. // if SoftKeyboard compartmemnt
  415. if (IsEqualGUID(rguid, GUID_COMPARTMENT_SOFTKBD_KBDLAYOUT))
  416. {
  417. DWORD dwSoftLayout, dwCurLabel;
  418. HRESULT hr;
  419. if (_this->m_pSoftKbd == NULL)
  420. return E_FAIL;
  421. dwSoftLayout = _this->GetSoftKBDLayout();
  422. dwCurLabel = _this->GetHangulSKbd()->dwCurLabel;
  423. hr = _this->m_pSoftKbd->SelectSoftKeyboard(dwSoftLayout);
  424. if (FAILED(hr))
  425. return hr;
  426. if (dwSoftLayout == _this->m_KbdStandard.dwSoftKbdLayout)
  427. hr = _this->m_pSoftKbd->SetKeyboardLabelText(GetKeyboardLayout(0));
  428. else
  429. hr = _this->m_pSoftKbd->SetKeyboardLabelTextCombination(dwCurLabel);
  430. if (FAILED(hr))
  431. return hr;
  432. if (_this->GetSoftKBDOnOff())
  433. {
  434. hr = _this->m_pSoftKbd->ShowSoftKeyboard(fTrue);
  435. return hr;
  436. }
  437. }
  438. return S_OK;
  439. }
  440. /*---------------------------------------------------------------------------
  441. CKorIMX::_PreKeyCallback
  442. ---------------------------------------------------------------------------*/
  443. HRESULT CKorIMX::_PreKeyCallback(ITfContext *pic, REFGUID rguid, BOOL *pfEaten, void *pv)
  444. {
  445. CKorIMX *_this = (CKorIMX *)pv;
  446. if (_this == NULL)
  447. return S_OK;
  448. if (IsEqualGUID(rguid, GUID_KOREAN_HANGULSIMULATE))
  449. {
  450. DWORD dwConvMode;
  451. // Toggle Hangul mode
  452. dwConvMode = _this->GetConvMode(pic);
  453. dwConvMode ^= TIP_HANGUL_MODE;
  454. _this->SetConvMode(pic, dwConvMode);
  455. *pfEaten = fTrue;
  456. }
  457. else if (IsEqualGUID(rguid, GUID_KOREAN_HANJASIMULATE))
  458. {
  459. // O10 #317983
  460. if (PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_JAPANESE)
  461. {
  462. keybd_event(VK_HANJA, 0, 0, 0);
  463. keybd_event(VK_HANJA, 0, KEYEVENTF_KEYUP, 0);
  464. *pfEaten = fTrue;
  465. }
  466. else
  467. *pfEaten = fFalse;
  468. }
  469. return S_OK;
  470. }
  471. /* O N E N D E D I T */
  472. /*------------------------------------------------------------------------------
  473. ------------------------------------------------------------------------------*/
  474. HRESULT CKorIMX::OnEndEdit(ITfContext *pic, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord)
  475. {
  476. UNREFERENCED_PARAMETER(ecReadOnly);
  477. static const GUID *rgModeBiasProperties[] =
  478. {
  479. &GUID_PROP_MODEBIAS
  480. };
  481. static const GUID *rgAttrProperties[] =
  482. {
  483. &GUID_PROP_ATTRIBUTE,
  484. };
  485. CEditSession2 *pes;
  486. ESSTRUCT ess;
  487. HRESULT hr;
  488. BOOL fInWriteSession;
  489. CICPriv *picp;
  490. IEnumTfRanges *pEnumText = NULL;
  491. ITfRange *pRange = NULL;
  492. ULONG ulFetched = 0;
  493. BOOL fCallES = fFalse;
  494. BOOL fSelChanged = fFalse;
  495. Assert(pic != NULL);
  496. if (pic == NULL)
  497. return S_OK; // error
  498. pic->InWriteSession(GetTID(), &fInWriteSession);
  499. if (fInWriteSession)
  500. return S_OK; // own change.
  501. picp = GetInputContextPriv(pic);
  502. if (picp == NULL)
  503. return S_OK; // error
  504. if (picp->GetfTransaction())
  505. return S_OK; // skip in transaction.
  506. //////////////////////////////////////////////////////////////////////////
  507. // Init to call ESCB_TEXTEVENT
  508. ESStructInit(&ess, ESCB_TEXTEVENT);
  509. // Call ESCB_TEXTEVENT callback only if GUID_PROP_MODEBIAS changed.
  510. hr = pEditRecord->GetTextAndPropertyUpdates(0/*TF_GTP_INCL_TEXT*/, rgModeBiasProperties, ARRAYSIZE(rgModeBiasProperties), &pEnumText);
  511. if (FAILED(hr) || pEnumText == NULL)
  512. return S_OK;
  513. if (pEnumText->Next(1, &pRange, &ulFetched) == S_OK)
  514. {
  515. SafeRelease(pRange);
  516. // ModeBias changed.
  517. ess.fBool = fTrue;
  518. }
  519. pEnumText->Release();
  520. // Selection changed?
  521. pEditRecord->GetSelectionStatus(&fSelChanged);
  522. // If Attribute changed, set selection change true.
  523. if (fSelChanged == fFalse)
  524. {
  525. hr = pEditRecord->GetTextAndPropertyUpdates(0/*TF_GTP_INCL_TEXT*/, rgAttrProperties, ARRAYSIZE(rgAttrProperties), &pEnumText);
  526. if (FAILED(hr) || pEnumText == NULL)
  527. return S_OK;
  528. if (pEnumText->Next(1, &pRange, &ulFetched) == S_OK)
  529. {
  530. SafeRelease(pRange);
  531. fSelChanged = fTrue;
  532. }
  533. pEnumText->Release();
  534. }
  535. // Perf: Call ES only if (ModeBias change) or (Selection changed and comp object exist)
  536. // I guess calling ES is pretty much costing since sel change occurs for ever cursor move.
  537. if (fSelChanged)
  538. fSelChanged = (GetIPComposition(pic) != NULL) ? fTrue : fFalse;
  539. // If ModeBias changed or Selection changed, then call ESCB_TEXTEVENT sink
  540. if (ess.fBool || fSelChanged)
  541. {
  542. if ((pes = new CEditSession2( pic, this, &ess, _EditSessionCallback2 )) != NULL)
  543. {
  544. pes->Invoke(ES2_READWRITE | ES2_ASYNC, &hr);
  545. pes->Release();
  546. }
  547. }
  548. return S_OK;
  549. }
  550. /* O N S T A R T E D I T T R A N S A C T I O N */
  551. /*------------------------------------------------------------------------------
  552. ------------------------------------------------------------------------------*/
  553. HRESULT CKorIMX::OnStartEditTransaction(ITfContext *pic)
  554. {
  555. CICPriv *picp;
  556. if (pic == NULL)
  557. return S_OK; // error
  558. picp = GetInputContextPriv(pic);
  559. if (picp)
  560. picp->SetfTransaction(fTrue);
  561. return S_OK;
  562. }
  563. /* O N E N D E D I T T R A N S A C T I O N */
  564. /*------------------------------------------------------------------------------
  565. ------------------------------------------------------------------------------*/
  566. HRESULT CKorIMX::OnEndEditTransaction(ITfContext *pic)
  567. {
  568. BOOL ftran;
  569. CICPriv *picp;
  570. if (pic == NULL)
  571. return S_OK; // error
  572. picp = GetInputContextPriv(pic);
  573. if (picp)
  574. {
  575. ftran = picp->GetfTransaction();
  576. if (ftran)
  577. {
  578. CEditSession2 *pes;
  579. ESSTRUCT ess;
  580. HRESULT hr;
  581. picp->SetfTransaction(fFalse);
  582. ESStructInit(&ess, ESCB_TEXTEVENT);
  583. ess.pEnumRange = NULL;
  584. if ((pes = new CEditSession2( pic, this, &ess, _EditSessionCallback2 )) != NULL)
  585. {
  586. pes->Invoke(ES2_READWRITE | ES2_ASYNC, &hr);
  587. pes->Release();
  588. }
  589. }
  590. }
  591. return S_OK;
  592. }