Source code of Windows XP (NT5)
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.

3075 lines
68 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module CMSGFLT.CPP -- Text Message Implementation |
  5. *
  6. * Most everything to do with IME message handling.
  7. *
  8. * Original Author: <nl>
  9. * Hon Wah Chan
  10. *
  11. * History: <nl>
  12. * 2/6/98 v-honwch
  13. *
  14. * Copyright (c) 1995-2000, Microsoft Corporation. All rights reserved.
  15. */
  16. #include "_common.h"
  17. #ifndef NOFEPROCESSING
  18. #ifndef NOPRIVATEMESSAGE
  19. #include "_MSREMSG.H"
  20. #endif
  21. #include "_array.h"
  22. #include "msctf.h"
  23. #include "textstor.h"
  24. #include "msctfp.h"
  25. #include "textserv.h"
  26. #include "_cmsgflt.h"
  27. #include "_ime.h"
  28. #include "_cuim.h"
  29. #include "imeapp.h"
  30. #define MAX_RECONVERSION_SIZE 100
  31. #define CONTROL(_ch) (_ch - 'A' + 1)
  32. /*
  33. * void CreateIMEMessageFilter(ITextMsgFilter **ppMsgFilter)
  34. *
  35. * @func
  36. * TextMsgFilter class factory.
  37. */
  38. void CreateIMEMessageFilter(ITextMsgFilter **ppMsgFilter)
  39. {
  40. CTextMsgFilter *pNewFilter = new CTextMsgFilter;
  41. *ppMsgFilter = pNewFilter ? pNewFilter : NULL;
  42. }
  43. /*
  44. * void CTextMsgFilter::~CTextMsgFilter
  45. *
  46. * @mfunc
  47. * CTextMsgFilter Destructor
  48. * Release objects being used.
  49. *
  50. */
  51. CTextMsgFilter::~CTextMsgFilter ()
  52. {
  53. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::~CTextMsgFilter");
  54. if (_nIMEMode)
  55. {
  56. SetIMESentenseMode(FALSE);
  57. _nIMEMode = 0;
  58. }
  59. if (_hIMCContext)
  60. ImmAssociateContext(_hwnd, _hIMCContext, _fUsingAIMM); // Restore IME before exit
  61. if (_pMsgCallBack)
  62. {
  63. delete _pMsgCallBack;
  64. _pMsgCallBack = NULL;
  65. }
  66. // Release various objects
  67. TurnOffUIM(FALSE);
  68. TurnOffAimm(FALSE);
  69. if (_pFilter)
  70. _pFilter->Release();
  71. if (_pTextSel)
  72. _pTextSel->Release();
  73. _pFilter = NULL;
  74. _pTextDoc = NULL;
  75. _pTextSel = NULL;
  76. _hwnd = NULL;
  77. _hIMCContext = NULL;
  78. FreePv(_pcrComp);
  79. _pcrComp = NULL;
  80. }
  81. /*
  82. * STDMETHODIMP CTextMsgFilter::QueryInterface (riid, ppv)
  83. *
  84. * @mfunc
  85. * IUnknown QueryInterface support
  86. *
  87. * @rdesc
  88. * NOERROR if interface supported
  89. *
  90. */
  91. STDMETHODIMP CTextMsgFilter::QueryInterface (REFIID riid, void ** ppv)
  92. {
  93. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::QueryInterface");
  94. if( IsEqualIID(riid, IID_IUnknown) )
  95. {
  96. *ppv = (IUnknown *)this;
  97. }
  98. else if( IsEqualIID(riid, IID_ITextMsgFilter) )
  99. {
  100. *ppv = (ITextMsgFilter *)this;
  101. }
  102. else
  103. {
  104. *ppv = NULL;
  105. return E_NOINTERFACE;
  106. }
  107. AddRef();
  108. return NOERROR;
  109. }
  110. /*
  111. * STDMETHODIMP_(ULONG) CTextMsgFilter::AddRef
  112. *
  113. * @mfunc
  114. * IUnknown AddRef support
  115. *
  116. * @rdesc
  117. * Reference count
  118. */
  119. STDMETHODIMP_(ULONG) CTextMsgFilter::AddRef()
  120. {
  121. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::AddRef");
  122. return ++_crefs;
  123. }
  124. /*
  125. * STDMETHODIMP_(ULONG) CTextMsgFilter::Release()
  126. *
  127. * @mfunc
  128. * IUnknown Release support - delete object when reference count is 0
  129. *
  130. * @rdesc
  131. * Reference count
  132. */
  133. STDMETHODIMP_(ULONG) CTextMsgFilter::Release()
  134. {
  135. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::Release");
  136. _crefs--;
  137. if( _crefs == 0 )
  138. {
  139. delete this;
  140. return 0;
  141. }
  142. return _crefs;
  143. }
  144. /*
  145. * STDMETHODIMP_(HRESULT) CTextMsgFilter::AttachDocument(HWND, ITextDocument2)
  146. *
  147. * @mfunc
  148. * Attach message filter. Perform genral initialization
  149. *
  150. * @rdesc
  151. * NOERROR
  152. */
  153. STDMETHODIMP_(HRESULT) CTextMsgFilter::AttachDocument( HWND hwnd, ITextDocument2 *pTextDoc, IUnknown *punk)
  154. {
  155. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::AttachDocument");
  156. // Cache the values for possible later use.
  157. // The TextDocument interface pointer is not AddRefed because it is a back pointer
  158. // and the lifetime of message filters is assumed to be nested inside text documents
  159. _hwnd = hwnd;
  160. _pTextDoc = pTextDoc;
  161. _pTextService = (ITextServices *)punk;
  162. // Don't get selection until it is needed
  163. _pTextSel = NULL;
  164. _fUnicodeWindow = 0;
  165. if (hwnd)
  166. _fUnicodeWindow = IsWindowUnicode(hwnd);
  167. _fUsingAIMM = 0;
  168. _pTim = NULL;
  169. _pCUIM = NULL;
  170. _fUsingUIM = 0;
  171. // Check if current keyboard is MSIME98 or later.
  172. CheckIMEType(NULL);
  173. // Initialize some member data
  174. _fHangulToHanja = FALSE;
  175. _fIMECancelComplete = FALSE;
  176. _fIMEAlwaysNotify = FALSE;
  177. _hIMCContext = NULL;
  178. _pcrComp = NULL;
  179. _pMsgCallBack = NULL;
  180. _pTextDoc->GetFEFlags(&_lFEFlags);
  181. _fRE10Mode = (_lFEFlags & tomRE10Mode);
  182. _uSystemCodePage = GetACP();
  183. return NOERROR;
  184. }
  185. /*
  186. * STDMETHODIMP_(HRESULT) CTextMsgFilter::HandleMessage(UINT *, WPARAM *, LPARAM *, LRESULT *)
  187. *
  188. * @mfunc
  189. * Main Message filter message loop handling
  190. *
  191. * @rdesc
  192. * S_OK if we have handled the message
  193. * S_FALSE if we want the caller to process the message
  194. */
  195. STDMETHODIMP_(HRESULT) CTextMsgFilter::HandleMessage(
  196. UINT * pmsg,
  197. WPARAM * pwparam,
  198. LPARAM * plparam,
  199. LRESULT * plres)
  200. {
  201. //TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::HandleMessage");
  202. HRESULT hr = S_FALSE;
  203. BOOL bReleaseSelction = FALSE;
  204. HRESULT hResult;
  205. // Give other message filters a chance to handle message
  206. // Stop with the first guy that handles the message
  207. if (_pFilter)
  208. hr = _pFilter->HandleMessage(pmsg, pwparam, plparam, plres);
  209. if (hr == S_OK)
  210. return hr;
  211. if (IsIMEComposition() || _pCUIM && _pCUIM->IsUIMTyping())
  212. {
  213. // During IME Composition, there are some messages we should
  214. // not handle. Also, there are other messages we need to handle by
  215. // terminating the IME composition first.
  216. // For WM_KEYDOWN, this is handled inside edit.c OnTxKeyDown().
  217. switch( *pmsg )
  218. {
  219. case WM_COPY:
  220. case WM_CUT:
  221. case WM_DROPFILES:
  222. case EM_REDO:
  223. case EM_SETCHARFORMAT:
  224. case WM_SETFONT:
  225. return S_OK; // Just ignore these
  226. case EM_UNDO:
  227. case WM_UNDO:
  228. // just terminate and exist for undo cases
  229. CompleteUIMTyping(CIme::TERMINATE_NORMAL);
  230. return S_OK;
  231. case WM_SETTEXT:
  232. case WM_CLEAR:
  233. case EM_STREAMIN:
  234. // these messages are used to reset our state, so reset
  235. // IME as well
  236. CompleteUIMTyping(CIme::TERMINATE_FORCECANCEL);
  237. break;
  238. case EM_SETTEXTEX:
  239. if (!_fRE10Mode) // Don't terminate if running in 10 mode
  240. CompleteUIMTyping(CIme::TERMINATE_FORCECANCEL);
  241. break;
  242. case WM_SYSKEYDOWN:
  243. // Don't terminate IME composition on VK_PROCESSKEY (F10) since Japanese
  244. // IME will process the F10 key
  245. if (*pwparam != VK_PROCESSKEY)
  246. CompleteUIMTyping(CIme::TERMINATE_NORMAL); // otherwise we want to terminate the IME
  247. break;
  248. case WM_CHAR:
  249. case WM_UNICHAR:
  250. if (IsIMEComposition() && _ime->GetIMELevel() == IME_LEVEL_3 && !_fReceivedKeyDown)
  251. return S_OK; // Ignore this during IME composition and we haven't seen
  252. // any keydown message,
  253. // else fall thru to terminate composition
  254. _fReceivedKeyDown = 0;
  255. case EM_SETWORDBREAKPROC:
  256. case WM_PASTE:
  257. case EM_PASTESPECIAL:
  258. case EM_SCROLL:
  259. case EM_SCROLLCARET:
  260. case WM_VSCROLL:
  261. case WM_HSCROLL:
  262. case EM_SETREADONLY:
  263. case EM_SETPARAFORMAT:
  264. case WM_INPUTLANGCHANGEREQUEST:
  265. case EM_REPLACESEL:
  266. case EM_STREAMOUT:
  267. CompleteUIMTyping(CIme::TERMINATE_NORMAL);
  268. break;
  269. case WM_KILLFOCUS:
  270. CompleteUIMTyping(CIme::TERMINATE_NORMAL, FALSE);
  271. break;
  272. case EM_SETSEL:
  273. if (IsIMEComposition())
  274. CompleteUIMTyping(CIme::TERMINATE_NORMAL);
  275. else
  276. return S_OK; // Ignore this during Cicero typing
  277. case WM_KEYUP:
  278. _fReceivedKeyDown = 0;
  279. break;
  280. case WM_KEYDOWN:
  281. _fReceivedKeyDown = 1;
  282. if(GetKeyState(VK_CONTROL) & 0x8000)
  283. {
  284. // During IME Composition, there are some key events we should
  285. // not handle. Also, there are other key events we need to handle by
  286. // terminating the IME composition first.
  287. switch((WORD) *pwparam)
  288. {
  289. case VK_TAB:
  290. case VK_CLEAR:
  291. case VK_NUMPAD5:
  292. case 'A': // Ctrl-A => select all
  293. case 'C': // Ctrl-C => copy
  294. case 'X': // Ctrl-X => cut
  295. case 'Y': // Ctrl-Y => redo
  296. return S_OK; // Just ignore these
  297. case 'V': // Ctrl-V => paste
  298. case 'Z': // Ctrl-Z => undo
  299. CompleteUIMTyping(CIme::TERMINATE_NORMAL);
  300. if ((WORD) *pwparam == 'Z') // Early exist for undo case
  301. return S_OK;
  302. }
  303. }
  304. else
  305. {
  306. switch((WORD) *pwparam)
  307. {
  308. case VK_F16:
  309. return S_OK; // Just ignore these
  310. case VK_BACK:
  311. case VK_INSERT: // Ins
  312. case VK_LEFT: // Left arrow
  313. case VK_RIGHT: // Right arrow
  314. case VK_UP: // Up arrow
  315. case VK_DOWN: // Down arrow
  316. case VK_HOME: // Home
  317. case VK_END: // End
  318. case VK_PRIOR: // PgUp
  319. case VK_NEXT: // PgDn
  320. case VK_DELETE: // Del
  321. case CONTROL('J'):
  322. case VK_RETURN:
  323. CompleteUIMTyping(CIme::TERMINATE_NORMAL);
  324. break;
  325. }
  326. }
  327. break;
  328. default:
  329. // Only need to handle mouse related msgs during composition
  330. if (IN_RANGE(WM_MOUSEFIRST, *pmsg, WM_MBUTTONDBLCLK) || *pmsg == WM_SETCURSOR)
  331. {
  332. if (IsIMEComposition())
  333. {
  334. bReleaseSelction = GetTxSelection();
  335. if (_pTextSel)
  336. hr = IMEMouseCheck( *this, pmsg, pwparam, plparam, plres);
  337. goto Exit;
  338. }
  339. // Cicero composition
  340. if (_pCUIM->_fMosueSink)
  341. {
  342. bReleaseSelction = GetTxSelection();
  343. if (_pTextSel)
  344. hr = _pCUIM->MouseCheck(pmsg, pwparam, plparam, plres);
  345. goto Exit;
  346. }
  347. if (IN_RANGE(WM_LBUTTONDOWN, *pmsg, WM_MOUSELAST) && !(*pmsg == WM_LBUTTONUP || *pmsg == WM_RBUTTONUP || *pmsg == WM_MBUTTONUP))
  348. CompleteUIMTyping(CIme::TERMINATE_NORMAL); // Terminate on Mouse down and double-click messages
  349. }
  350. break;
  351. }
  352. }
  353. // Get Fe Flags for ES_NOIME or ES_SELFIME setting
  354. _lFEFlags = 0;
  355. // ... Local mucking with msg, params, etc, ...
  356. switch ( *pmsg )
  357. {
  358. case WM_CHAR:
  359. hr = OnWMChar (pmsg, pwparam, plparam, plres);
  360. break;
  361. case WM_IME_CHAR:
  362. _uKeyBoardCodePage = GetKeyboardCodePage(0x0FFFFFFFF);
  363. hResult = _pTextDoc->GetFEFlags(&_lFEFlags);
  364. if ((_lFEFlags & ES_NOIME))
  365. hr = S_OK;
  366. else
  367. hr = OnWMIMEChar (pmsg, pwparam, plparam, plres);
  368. break;
  369. case WM_IME_STARTCOMPOSITION:
  370. _fReceivedKeyDown = 0;
  371. _uKeyBoardCodePage = GetKeyboardCodePage(0x0FFFFFFFF);
  372. hResult = _pTextDoc->GetFEFlags(&_lFEFlags);
  373. if (!(_lFEFlags & ES_SELFIME))
  374. {
  375. bReleaseSelction = GetTxSelection();
  376. if (_pTextSel)
  377. hr = StartCompositionGlue (*this);
  378. }
  379. break;
  380. case WM_IME_COMPOSITION:
  381. _fReceivedKeyDown = 0;
  382. _uKeyBoardCodePage = GetKeyboardCodePage(0x0FFFFFFFF);
  383. hResult = _pTextDoc->GetFEFlags(&_lFEFlags);
  384. if ((_lFEFlags & ES_NOIME) && !IsIMEComposition())
  385. hr = S_OK;
  386. else if (!(_lFEFlags & ES_SELFIME))
  387. {
  388. bReleaseSelction = GetTxSelection();
  389. if (_pTextSel)
  390. {
  391. hr = CompositionStringGlue ( *plparam, *this );
  392. // Turn off Result string bit to avoid WM_IME_CHAR message.
  393. *plparam &= ~GCS_RESULTSTR;
  394. }
  395. }
  396. if (_hwnd && IsIMEComposition() && _ime->IgnoreIMECharMsg())
  397. {
  398. _ime->AcceptIMECharMsg();
  399. if (fHaveAIMM)
  400. hr = CallAIMMDefaultWndProc(_hwnd, *pmsg, *pwparam, *plparam, plres);
  401. else
  402. *plres = ::DefWindowProc(_hwnd, *pmsg, *pwparam, *plparam);
  403. hr = S_OK;
  404. }
  405. break;
  406. case WM_IME_ENDCOMPOSITION:
  407. _fReceivedKeyDown = 0;
  408. hResult = _pTextDoc->GetFEFlags(&_lFEFlags);
  409. if (!(_lFEFlags & ES_SELFIME))
  410. {
  411. bReleaseSelction = GetTxSelection();
  412. if (_pTextSel)
  413. hr = EndCompositionGlue ( *this, FALSE );
  414. }
  415. break;
  416. case WM_IME_NOTIFY:
  417. hResult = _pTextDoc->GetFEFlags(&_lFEFlags);
  418. if (!(_lFEFlags & (ES_SELFIME | ES_NOIME)))
  419. {
  420. bReleaseSelction = GetTxSelection();
  421. if (_pTextSel)
  422. hr = IMENotifyGlue ( *pwparam, *plparam, *this );
  423. }
  424. break;
  425. case WM_IME_COMPOSITIONFULL: // Level 2 comp string about to overflow.
  426. hResult = _pTextDoc->GetFEFlags(&_lFEFlags);
  427. if (!(_lFEFlags & ES_SELFIME))
  428. {
  429. IMECompositionFull ( *this );
  430. }
  431. hr = S_FALSE;
  432. break;
  433. case WM_KEYDOWN:
  434. if (*pwparam == VK_KANJI)
  435. {
  436. hResult = _pTextDoc->GetFEFlags(&_lFEFlags);
  437. _uKeyBoardCodePage = GetKeyboardCodePage(0x0FFFFFFFF);
  438. // for Korean, need to convert the next Korean Hangul character to Hanja
  439. if(CP_KOREAN == _uKeyBoardCodePage && !(_lFEFlags & (ES_SELFIME | ES_NOIME)))
  440. {
  441. bReleaseSelction = GetTxSelection();
  442. if (_pTextSel)
  443. hr = IMEHangeulToHanja ( *this );
  444. }
  445. }
  446. break;
  447. case WM_INPUTLANGCHANGE:
  448. CheckIMEType((HKL)*plparam);
  449. if (_nIMEMode && GetFocus() == _hwnd)
  450. SetIMESentenseMode(TRUE, (HKL)*plparam);
  451. hr = S_FALSE;
  452. break;
  453. case WM_INPUTLANGCHANGEREQUEST:
  454. if (_nIMEMode && GetFocus() == _hwnd)
  455. SetIMESentenseMode(FALSE);
  456. break;
  457. case WM_KILLFOCUS:
  458. OnKillFocus();
  459. break;
  460. case WM_SETFOCUS:
  461. OnSetFocus();
  462. break;
  463. case EM_SETIMEOPTIONS:
  464. *plres = OnSetIMEOptions(*pwparam, *plparam);
  465. hr = S_OK;
  466. break;
  467. case EM_GETIMEOPTIONS:
  468. *plres = OnGetIMEOptions();
  469. hr = S_OK;
  470. break;
  471. case WM_IME_REQUEST:
  472. hResult = _pTextDoc->GetFEFlags(&_lFEFlags);
  473. if (!(_lFEFlags & (ES_SELFIME | ES_NOIME)))
  474. {
  475. bReleaseSelction = GetTxSelection();
  476. if (_pTextSel)
  477. {
  478. _uKeyBoardCodePage = GetKeyboardCodePage(0x0FFFFFFFF);
  479. if (*pwparam == IMR_RECONVERTSTRING || *pwparam == IMR_CONFIRMRECONVERTSTRING
  480. || *pwparam == IMR_DOCUMENTFEED)
  481. hr = OnIMEReconvert(pmsg, pwparam, plparam, plres, _fUnicodeWindow);
  482. else if (*pwparam == IMR_QUERYCHARPOSITION)
  483. hr = OnIMEQueryPos(pmsg, pwparam, plparam, plres, _fUnicodeWindow);
  484. }
  485. }
  486. break;
  487. case EM_RECONVERSION:
  488. hResult = _pTextDoc->GetFEFlags(&_lFEFlags);
  489. if (!(_lFEFlags & (ES_SELFIME | ES_NOIME)))
  490. {
  491. // Application initiates reconversion
  492. bReleaseSelction = GetTxSelection();
  493. if (_pTextSel)
  494. {
  495. if (!(IsIMEComposition() || _pCUIM && _pCUIM->IsUIMTyping()))
  496. {
  497. if (_pCUIM && _pCUIM->Reconverse() >= 0)
  498. break;
  499. if (_fMSIME && MSIMEReconvertRequestMsg)
  500. IMEMessage( *this, MSIMEReconvertRequestMsg, 0, (LPARAM)_hwnd, TRUE );
  501. else
  502. {
  503. hr = OnIMEReconvert(pmsg, pwparam, plparam, plres, TRUE);
  504. *plres = 0;
  505. }
  506. }
  507. }
  508. }
  509. hr = S_OK;
  510. break;
  511. case EM_SETLANGOPTIONS:
  512. // Setup IME related setting.
  513. // hr is not S_OK so textserv could handle other language setting
  514. _fIMEAlwaysNotify = (*plparam & IMF_IMEALWAYSSENDNOTIFY) != 0;
  515. _fIMECancelComplete = (*plparam & IMF_IMECANCELCOMPLETE) != 0;
  516. *plres = 1;
  517. break;
  518. case EM_GETLANGOPTIONS:
  519. // Report IME related setting.
  520. // hr is not S_OK so textserv could fill in other language setting
  521. if ( _fIMECancelComplete )
  522. *plres |= IMF_IMECANCELCOMPLETE;
  523. if ( _fIMEAlwaysNotify )
  524. *plres |= IMF_IMEALWAYSSENDNOTIFY;
  525. break;
  526. case EM_GETIMECOMPMODE:
  527. // Get current IME level
  528. if (_pCUIM && _pCUIM->IsUIMTyping())
  529. *plres = ICM_CTF;
  530. else
  531. *plres = OnGetIMECompositionMode( *this );
  532. hr = S_OK;
  533. break;
  534. case EM_SETUIM:
  535. // This is RE private message equivalent to EM_SETEDITSTYLE
  536. if (!_fNoIme) // Ignore if no IME
  537. {
  538. if (!_fUsingUIM && !_fUsingAIMM) // Ignore if we already using something
  539. {
  540. if (*pwparam == SES_USEAIMM11 || *pwparam == SES_USEAIMM12)
  541. {
  542. if (!_fTurnOffAIMM)
  543. StartAimm(*pwparam == SES_USEAIMM12);
  544. }
  545. else if (!_fTurnOffUIM) // Client doesn't want UIM?
  546. StartUIM();
  547. }
  548. }
  549. hr = S_OK;
  550. break;
  551. case EM_SETEDITSTYLE:
  552. if (*plparam & SES_USECTF)
  553. {
  554. if ((*pwparam & SES_USECTF))
  555. {
  556. if (!_fRE10Mode)
  557. {
  558. if (_fUsingAIMM)
  559. TurnOffAimm(TRUE);
  560. // Turn on Cicero
  561. if (!_fUsingUIM)
  562. StartUIM();
  563. goto SKIP_AIMM;
  564. }
  565. }
  566. else
  567. {
  568. // Turn off Cicero
  569. _fTurnOffUIM = 1; // Flag to ignore in EM_SETUIM
  570. if (_fUsingUIM)
  571. TurnOffUIM(TRUE);
  572. }
  573. }
  574. if ((*pwparam & SES_USEAIMM) && ((*plparam & SES_USEAIMM) || *plparam == 0))
  575. {
  576. if (_fUsingUIM)
  577. TurnOffUIM(TRUE);
  578. if (!_fUsingAIMM)
  579. {
  580. hResult = _pTextDoc->GetFEFlags(&_lFEFlags);
  581. if (!(_lFEFlags & ES_NOIME)) // No IME style on?
  582. StartAimm(TRUE);
  583. }
  584. }
  585. else if ((*plparam & SES_USEAIMM))
  586. {
  587. _fTurnOffAIMM = 1; // Flag to ignore in EM_SETUIM
  588. TurnOffAimm(TRUE);
  589. }
  590. SKIP_AIMM:
  591. if ((*plparam == 0 || *plparam & SES_NOIME) && _hwnd)
  592. {
  593. if (*pwparam & SES_NOIME)
  594. {
  595. _fNoIme = 1;
  596. TurnOffUIM(TRUE);
  597. TurnOffAimm(TRUE);
  598. if (!_hIMCContext)
  599. _hIMCContext = ImmAssociateContext(_hwnd, NULL, _fUsingAIMM); // turn off IME
  600. }
  601. else if (*plparam & SES_NOIME)
  602. {
  603. _fNoIme = 0;
  604. if (_hIMCContext)
  605. ImmAssociateContext(_hwnd, _hIMCContext, _fUsingAIMM); // turn on IME
  606. _hIMCContext = NULL;
  607. }
  608. }
  609. if (*plparam & SES_CTFALLOWEMBED)
  610. _fAllowEmbedded = (*pwparam & SES_CTFALLOWEMBED) ? 1 : 0;
  611. if (*plparam & (SES_CTFALLOWSMARTTAG | SES_CTFALLOWPROOFING))
  612. HandleCTFService(*pwparam, *plparam);
  613. // remove settings that are handled.
  614. *pwparam &= ~(SES_NOIME | SES_USEAIMM | SES_USECTF | SES_CTFALLOWEMBED | SES_CTFALLOWSMARTTAG | SES_CTFALLOWPROOFING);
  615. *plparam &= ~(SES_NOIME | SES_USEAIMM | SES_USECTF | SES_CTFALLOWEMBED | SES_CTFALLOWSMARTTAG | SES_CTFALLOWPROOFING);
  616. // fall thru to return the edit style
  617. case EM_GETEDITSTYLE:
  618. if (_hIMCContext)
  619. *plres = SES_NOIME; // IME has been turned off
  620. if (_fUsingAIMM)
  621. *plres |= SES_USEAIMM; // AIMM is on
  622. if (_fUsingUIM)
  623. *plres |= SES_USECTF; // Cicero is on
  624. // Cicero services
  625. if (_fAllowEmbedded)
  626. *plres |= SES_CTFALLOWEMBED;
  627. if (_fAllowSmartTag)
  628. *plres |= SES_CTFALLOWSMARTTAG;
  629. if (_fAllowProofing)
  630. *plres |= SES_CTFALLOWPROOFING;
  631. break;
  632. case EM_SETIMECOLOR:
  633. if (_fRE10Mode)
  634. {
  635. COMPCOLOR* pcrComp = GetIMECompAttributes();
  636. if (pcrComp)
  637. {
  638. memcpy(pcrComp, (const void *)(*plparam), sizeof(COMPCOLOR) * 4);
  639. *plres = 1;
  640. }
  641. }
  642. hr = S_OK;
  643. break;
  644. case EM_GETIMECOLOR:
  645. if (_fRE10Mode)
  646. {
  647. COMPCOLOR* pcrComp = GetIMECompAttributes();
  648. if (pcrComp)
  649. {
  650. memcpy((void *)(*plparam), pcrComp, sizeof(COMPCOLOR) * 4);
  651. *plres = 1;
  652. }
  653. }
  654. hr = S_OK;
  655. break;
  656. case EM_SETIMEMODEBIAS:
  657. OnSetIMEMode(*pwparam, *plparam);
  658. // following thru to return EM_GETIMEMODEBIAS
  659. case EM_GETIMEMODEBIAS:
  660. *plres = OnGetIMEMode();
  661. hr = S_OK;
  662. break;
  663. case EM_SETCTFMODEBIAS:
  664. OnSetUIMMode(*pwparam);
  665. // following thru to return EM_GETCTFMODEBIAS
  666. case EM_GETCTFMODEBIAS:
  667. *plres = OnGetUIMMode();
  668. hr = S_OK;
  669. break;
  670. case EM_SETCTFOPENSTATUS:
  671. case EM_GETCTFOPENSTATUS:
  672. *plres = 0;
  673. if (_pCUIM)
  674. *plres = _pCUIM->CTFOpenStatus(*pmsg == EM_GETCTFOPENSTATUS, *pwparam != 0);
  675. hr = S_OK;
  676. break;
  677. case EM_ISIME:
  678. *plres = CheckIMEType(NULL, 0);
  679. hr = S_OK;
  680. break;
  681. case EM_GETIMEPROPERTY:
  682. *plres = ImmGetProperty(GetKeyboardLayout(0x0FFFFFFFF), *pwparam, _fUsingAIMM);
  683. hr = S_OK;
  684. break;
  685. case EM_GETIMECOMPTEXT:
  686. *plres = OnGetIMECompText(*pwparam, *plparam);
  687. hr = S_OK;
  688. break;
  689. case WM_SIZE:
  690. case WM_MOVE:
  691. if (_pMsgCallBack)
  692. _pMsgCallBack->NotifyEvents(NE_LAYOUTCHANGE);
  693. break;
  694. case EM_GETOLEINTERFACE:
  695. if(*plparam && *pwparam == 0x0435446) // 'CTF'
  696. {
  697. if (_pCUIM && _pCUIM->GetITfContext())
  698. {
  699. *(ITfContext **)(*plparam) = _pCUIM->GetITfContext();
  700. _pCUIM->GetITfContext()->AddRef();
  701. }
  702. else
  703. *(IUnknown **)(*plparam) = 0;
  704. *plres = TRUE;
  705. hr = S_OK;
  706. }
  707. break;
  708. default:
  709. if (*pmsg)
  710. {
  711. // Look for IME messages
  712. if (*pmsg == MSIMEReconvertMsg || *pmsg == MSIMEDocFeedMsg
  713. || *pmsg == MSIMEQueryPositionMsg)
  714. {
  715. hResult = _pTextDoc->GetFEFlags(&_lFEFlags);
  716. if (!(_lFEFlags & (ES_SELFIME | ES_NOIME)))
  717. {
  718. bReleaseSelction = GetTxSelection();
  719. if (_pTextSel)
  720. {
  721. if (*pmsg == MSIMEQueryPositionMsg)
  722. hr = OnIMEQueryPos(pmsg, pwparam, plparam, plres, TRUE);
  723. else
  724. hr = OnIMEReconvert(pmsg, pwparam, plparam, plres, TRUE);
  725. }
  726. }
  727. }
  728. if (_pCUIM && _pCUIM->_fMosueSink &&
  729. (IN_RANGE(WM_MOUSEFIRST, *pmsg, WM_MBUTTONDBLCLK) || *pmsg == WM_SETCURSOR))
  730. {
  731. bReleaseSelction = GetTxSelection();
  732. if (_pTextSel)
  733. hr = _pCUIM->MouseCheck(pmsg, pwparam, plparam, plres);
  734. }
  735. }
  736. break;
  737. }
  738. Exit:
  739. // Release Selection if we get it for this message
  740. if (bReleaseSelction && _pTextSel)
  741. {
  742. _pTextSel->Release();
  743. _pTextSel = NULL;
  744. }
  745. // Return the value that will cause message to be processed normally
  746. return hr;
  747. }
  748. /*
  749. * HRESULT CTextMsgFilter::AttachMsgFilter(ITextMsgFilter *)
  750. *
  751. * @mfunc
  752. * Add another message filter to the chain
  753. *
  754. * @rdesc
  755. * NOERROR if added
  756. */
  757. HRESULT STDMETHODCALLTYPE CTextMsgFilter::AttachMsgFilter( ITextMsgFilter *pMsgFilter)
  758. {
  759. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::AttachMsgFilter");
  760. HRESULT hr = NOERROR;
  761. if (_pFilter)
  762. hr = _pFilter->AttachMsgFilter( pMsgFilter );
  763. else
  764. {
  765. _pFilter = pMsgFilter;
  766. _pFilter->AddRef();
  767. }
  768. return hr;
  769. }
  770. /*
  771. * HRESULT CTextMsgFilter::OnWMChar(UINT *, WPARAM *, LPARAM *, LRESULT *)
  772. *
  773. * @mfunc
  774. * Handle WM_CHAR message - look for Japanese keyboard with Kana key on
  775. * Convert the SB Kana to Unicode if needed.
  776. *
  777. * @rdesc
  778. * S_FALSE so caller will handle the modified character in wparam
  779. */
  780. HRESULT CTextMsgFilter::OnWMChar(
  781. UINT * pmsg,
  782. WPARAM * pwparam,
  783. LPARAM * plparam,
  784. LRESULT * plres)
  785. {
  786. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::OnWMChar");
  787. // For Japanese keyboard, if Kana mode is on,
  788. // Kana characters (single byte Japanese chars) are coming in via WM_CHAR.
  789. if ( GetKeyState(VK_KANA) & 0x1 )
  790. {
  791. _uKeyBoardCodePage = GetKeyboardCodePage(0x0FFFFFFFF);
  792. if (_uKeyBoardCodePage == CP_JAPAN)
  793. {
  794. // check if this is a single byte character.
  795. TCHAR unicodeConvert;
  796. BYTE bytes[2];
  797. bytes[0] = (BYTE)(*pwparam >> 8); // Interchange DBCS bytes in endian
  798. bytes[1] = (BYTE)*pwparam; // independent fashion (use byte array)
  799. if (!bytes[0])
  800. {
  801. if(UnicodeFromMbcs((LPWSTR)&unicodeConvert, 1,
  802. (LPCSTR)&bytes[1], 1, _uKeyBoardCodePage) == 1)
  803. *pwparam = unicodeConvert;
  804. }
  805. return InputFEChar(*pwparam);
  806. }
  807. }
  808. return S_FALSE;
  809. }
  810. /*
  811. * HRESULT CTextMsgFilter::OnWMIMEChar(UINT *, WPARAM *, LPARAM *, LRESULT *)
  812. *
  813. * @mfunc
  814. * Handle WM_IMECHAR message - convert the character to unicode.
  815. *
  816. * @rdesc
  817. * S_OK - caller to ignore the message
  818. * S_FALSE - caller to handle the message. wparam may contains a new char
  819. */
  820. HRESULT CTextMsgFilter::OnWMIMEChar(
  821. UINT * pmsg,
  822. WPARAM * pwparam,
  823. LPARAM * plparam,
  824. LRESULT * plres)
  825. {
  826. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::OnWMIMEChar");
  827. TCHAR unicodeConvert;
  828. BYTE bytes[2];
  829. // We may receive IMECHAR even if we have handled the composition char already.
  830. // This is the case when the host does not call the DefWinProc with the composition
  831. // bit masked off. So, we need to ignore this message to avoid double entry.
  832. if (IsIMEComposition() && _ime->IgnoreIMECharMsg())
  833. {
  834. _ime->SkipIMECharMsg(); // Skip this ime char msg
  835. return S_OK;
  836. }
  837. if (_fUnicodeWindow && !W32->OnWin9x())
  838. return S_FALSE;
  839. bytes[0] = *pwparam >> 8; // Interchange DBCS bytes in endian
  840. bytes[1] = *pwparam; // independent fashion (use byte array)
  841. // need to convert both single-byte KANA and DBC
  842. if (!bytes[0] || GetTrailBytesCount(bytes[0], _uKeyBoardCodePage))
  843. {
  844. if( UnicodeFromMbcs((LPWSTR)&unicodeConvert, 1,
  845. bytes[0] == 0 ? (LPCSTR)&bytes[1] : (LPCSTR)bytes,
  846. bytes[0] == 0 ? 1 : 2,
  847. _uKeyBoardCodePage) == 1 )
  848. *pwparam = unicodeConvert;
  849. return InputFEChar(*pwparam);
  850. }
  851. return S_FALSE;
  852. }
  853. /*
  854. * HRESULT CTextMsgFilter::OnIMEReconvert(UINT *, WPARAM *, LPARAM *, LRESULT *)
  855. *
  856. * @mfunc
  857. * Handle IME Reconversion and Document feed. We only handle Unicode messages.
  858. * We use a limit of MAX_RECONVERSION_SIZE(100) characters in both cases.
  859. *
  860. * @rdesc
  861. * S_OK if we have handled the message
  862. */
  863. HRESULT CTextMsgFilter::OnIMEReconvert(
  864. UINT * pmsg,
  865. WPARAM * pwparam,
  866. LPARAM * plparam,
  867. LRESULT * plres,
  868. BOOL fUnicode)
  869. {
  870. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::OnIMEReconvert");
  871. HRESULT hr = S_OK;
  872. LPRECONVERTSTRING lpRCS = (LPRECONVERTSTRING)(*plparam);
  873. long cbStringSize;
  874. long cpMin, cpMax;
  875. long cpParaStart, cpParaEnd;
  876. HRESULT hResult;
  877. ITextRange *pTextRange, *pTempTextRange;
  878. long cbAdded;
  879. BOOL bDocumentFeed;
  880. long cLastChar;
  881. BOOL fAdjustedRange = FALSE;
  882. *plres = 0;
  883. // NT doesn't support Ansi window when the CP_ACP isn't the same
  884. // as keyboard codepage.
  885. if (!fUnicode && !(W32->OnWin9x()) && _uKeyBoardCodePage != _uSystemCodePage)
  886. return S_OK;
  887. bDocumentFeed = (MSIMEDocFeedMsg && *pmsg == MSIMEDocFeedMsg)
  888. || (*pmsg == WM_IME_REQUEST && *pwparam == IMR_DOCUMENTFEED);
  889. if (bDocumentFeed && IsIMEComposition() && _ime->GetIMELevel() == IME_LEVEL_3)
  890. {
  891. // Composition in progress, use composition string as selection
  892. cpMin = ((CIme_Lev3 *)_ime)->GetIMECompositionStart();
  893. cpMax = ((CIme_Lev3 *)_ime)->GetIMECompositionLen() + cpMin;
  894. }
  895. else
  896. {
  897. // Get current selection
  898. hResult = _pTextSel->GetStart(&cpMin);
  899. hResult = _pTextSel->GetEnd(&cpMax);
  900. }
  901. // Expand to include the current paragraph
  902. hResult = _pTextDoc->Range(cpMin, cpMax, &pTextRange);
  903. Assert (pTextRange != NULL);
  904. if (hResult != NOERROR)
  905. return S_OK;
  906. hResult = pTextRange->Expand(tomParagraph, &cbAdded);
  907. // Fail to get Paragraph, get the story
  908. // Note:- Expand will return S_FALSE for plain text when
  909. // the whole story is selected
  910. if (hResult != NOERROR)
  911. hResult = pTextRange->Expand(tomStory, &cbAdded);
  912. hResult = pTextRange->GetStart(&cpParaStart);
  913. hResult = pTextRange->GetEnd(&cpParaEnd);
  914. if (*pwparam == IMR_CONFIRMRECONVERTSTRING)
  915. {
  916. *plres = CheckIMEChange(lpRCS, cpParaStart, cpParaEnd, cpMin, cpMax, fUnicode);
  917. goto Exit;
  918. }
  919. // Initialize to hugh number
  920. _cpReconvertStart = tomForward;
  921. // Check if Par included
  922. hResult = _pTextDoc->Range(cpParaEnd-1, cpParaEnd, &pTempTextRange);
  923. if (hResult != NOERROR)
  924. goto Exit;
  925. Assert (pTempTextRange != NULL);
  926. hResult = pTempTextRange->GetChar(&cLastChar);
  927. pTempTextRange->Release();
  928. if (hResult == NOERROR && (WCHAR)cLastChar == CR)
  929. {
  930. if (cpMax == cpParaEnd)
  931. {
  932. // Par is selected, change selection to exclude the par char
  933. cpMax--;
  934. _pTextSel->SetEnd(cpMax);
  935. if (cpMin > cpMax)
  936. {
  937. // Adjust cpMin as well
  938. cpMin = cpMax;
  939. _pTextSel->SetStart(cpMin);
  940. }
  941. }
  942. // Get rid of par char
  943. cpParaEnd--;
  944. fAdjustedRange = TRUE;
  945. }
  946. // Check for MAX_RECONVERSION_SIZE since we don't want to pass a hugh buffer
  947. // to IME
  948. long cchSelected;
  949. cchSelected = cpMax - cpMin;
  950. if (cpParaEnd - cpParaStart > MAX_RECONVERSION_SIZE)
  951. {
  952. // Too many character selected, forget it
  953. if (cchSelected > MAX_RECONVERSION_SIZE)
  954. goto Exit;
  955. if (cchSelected == MAX_RECONVERSION_SIZE)
  956. {
  957. // Selection reaches the limit
  958. cpParaStart = cpMin;
  959. cpParaEnd = cpMax;
  960. }
  961. else
  962. {
  963. long cchBeforeSelection = cpMin - cpParaStart;
  964. long cchAfterSelection = cpParaEnd - cpMax;
  965. long cchNeeded = MAX_RECONVERSION_SIZE - cchSelected;
  966. if (cchBeforeSelection < cchNeeded/2)
  967. {
  968. // Put in all characters from the Par start
  969. // and move Par end
  970. cpParaEnd = cpParaStart + MAX_RECONVERSION_SIZE - 1;
  971. }
  972. else if (cchAfterSelection < cchNeeded/2)
  973. {
  974. // Put in all character to the Par end
  975. // and move Par start
  976. cpParaStart = cpParaEnd - MAX_RECONVERSION_SIZE + 1;
  977. }
  978. else
  979. {
  980. // Adjust both end
  981. cpParaStart = cpMin - cchNeeded/2;
  982. cpParaEnd = cpParaStart + MAX_RECONVERSION_SIZE - 1;
  983. }
  984. }
  985. fAdjustedRange = TRUE;
  986. }
  987. if (fAdjustedRange)
  988. {
  989. // Adjust the text range
  990. hResult = pTextRange->SetRange(cpParaStart, cpParaEnd);
  991. if (hResult != NOERROR)
  992. goto Exit;
  993. }
  994. cbStringSize = (cpParaEnd - cpParaStart) * 2;
  995. // No char in current par, forget it.
  996. if (cbStringSize <= 0)
  997. goto Exit;
  998. if (EM_RECONVERSION == *pmsg)
  999. {
  1000. // RE reconversion msg, allocate the Reconversion buffer
  1001. lpRCS = (LPRECONVERTSTRING) PvAlloc(sizeof(RECONVERTSTRING) + cbStringSize + 2, GMEM_ZEROINIT);
  1002. Assert(lpRCS != NULL);
  1003. if (lpRCS)
  1004. lpRCS->dwSize = sizeof(RECONVERTSTRING) + cbStringSize + 2;
  1005. }
  1006. if (lpRCS)
  1007. {
  1008. BSTR bstr = NULL;
  1009. LPSTR lpReconvertBuff;
  1010. hResult = pTextRange->GetText(&bstr);
  1011. if (hResult != NOERROR || bstr == NULL)
  1012. {
  1013. if (EM_RECONVERSION == *pmsg)
  1014. FreePv(lpRCS);
  1015. goto Exit; // forget it
  1016. }
  1017. if (lpRCS->dwSize - sizeof(RECONVERTSTRING) - 2 < (DWORD)cbStringSize)
  1018. cbStringSize = lpRCS->dwSize - sizeof(RECONVERTSTRING) - 2;
  1019. lpReconvertBuff = (LPSTR)(lpRCS) + sizeof(RECONVERTSTRING);
  1020. if (fUnicode)
  1021. {
  1022. // fill in the buffer
  1023. memcpy(lpReconvertBuff, (LPSTR)bstr, cbStringSize);
  1024. *(lpReconvertBuff+cbStringSize) = '\0';
  1025. *(lpReconvertBuff+cbStringSize+1) = '\0';
  1026. lpRCS->dwStrLen = (cpParaEnd - cpParaStart);
  1027. lpRCS->dwCompStrLen = (cpMax - cpMin);
  1028. lpRCS->dwCompStrOffset = (cpMin - cpParaStart)*2; // byte offset from beginning of string
  1029. }
  1030. else
  1031. {
  1032. // Ansi case, need to find byte offset and Ansi string
  1033. long cch = WideCharToMultiByte(_uKeyBoardCodePage, 0, bstr, -1, lpReconvertBuff, cbStringSize+1, NULL, NULL);
  1034. Assert (cch > 0);
  1035. if (cch > 0)
  1036. {
  1037. CTempCharBuf tcb;
  1038. char *psz = tcb.GetBuf(cch);
  1039. if (!psz) // No memory
  1040. goto CleanUp; // forget it.
  1041. if (cch > 1 && lpReconvertBuff[cch-1] == '\0')
  1042. cch--; // Get rid of the null char
  1043. int cpOffset = cpMin - cpParaStart;
  1044. Assert(cpOffset >= 0);
  1045. lpRCS->dwStrLen = cch;
  1046. lpRCS->dwCompStrOffset = WideCharToMultiByte(_uKeyBoardCodePage, 0,
  1047. bstr, cpOffset, psz, cch, NULL, NULL);
  1048. lpRCS->dwCompStrLen = 0;
  1049. if (cpMax > cpMin)
  1050. lpRCS->dwCompStrLen = WideCharToMultiByte(_uKeyBoardCodePage, 0,
  1051. bstr+cpOffset, cpMax - cpMin, psz, cch, NULL, NULL);
  1052. }
  1053. else
  1054. {
  1055. CleanUp:
  1056. SysFreeString (bstr);
  1057. if (EM_RECONVERSION == *pmsg)
  1058. FreePv(lpRCS);
  1059. goto Exit; // forget it
  1060. }
  1061. }
  1062. // Fill in the rest of the RCS struct
  1063. lpRCS->dwVersion = 0;
  1064. lpRCS->dwStrOffset = sizeof(RECONVERTSTRING); // byte offset from beginning of struct
  1065. lpRCS->dwTargetStrLen = lpRCS->dwCompStrLen;
  1066. lpRCS->dwTargetStrOffset = lpRCS->dwCompStrOffset;
  1067. *plres = sizeof(RECONVERTSTRING) + cbStringSize + 2;
  1068. // Save this for the CONFIRMRECONVERTSTRING handling
  1069. _cpReconvertStart = cpParaStart;
  1070. _cpReconvertEnd = cpParaEnd;
  1071. SysFreeString (bstr);
  1072. if (EM_RECONVERSION == *pmsg)
  1073. {
  1074. HIMC hIMC = LocalGetImmContext(*this);
  1075. if (hIMC)
  1076. {
  1077. DWORD imeProperties = ImmGetProperty(GetKeyboardLayout(0x0FFFFFFFF), IGP_SETCOMPSTR, _fUsingAIMM);
  1078. if ((imeProperties & (SCS_CAP_SETRECONVERTSTRING | SCS_CAP_MAKEREAD))
  1079. == (SCS_CAP_SETRECONVERTSTRING | SCS_CAP_MAKEREAD))
  1080. {
  1081. if (ImmSetCompositionStringW(hIMC, SCS_QUERYRECONVERTSTRING, lpRCS, *plres, NULL, 0, _fUsingAIMM))
  1082. {
  1083. // Check if there is any change in selection
  1084. CheckIMEChange(lpRCS, cpParaStart, cpParaEnd, cpMin, cpMax, TRUE);
  1085. ImmSetCompositionStringW(hIMC, SCS_SETRECONVERTSTRING, lpRCS, *plres, NULL, 0, _fUsingAIMM);
  1086. }
  1087. }
  1088. LocalReleaseImmContext(*this, hIMC);
  1089. }
  1090. FreePv(lpRCS);
  1091. }
  1092. }
  1093. else
  1094. {
  1095. // return size for IME to allocate the buffer
  1096. *plres = sizeof(RECONVERTSTRING) + cbStringSize + 2;
  1097. }
  1098. Exit:
  1099. pTextRange->Release();
  1100. return hr;
  1101. }
  1102. /*
  1103. * BOOL CTextMsgFilter::CheckIMEChange(LPRECONVERTSTRING,long,long,long,long)
  1104. *
  1105. * @mfunc
  1106. * Verify if IME wants to re-adjust the selection
  1107. *
  1108. * @rdesc
  1109. * TRUE - allow IME to change the selection
  1110. */
  1111. BOOL CTextMsgFilter::CheckIMEChange(
  1112. LPRECONVERTSTRING lpRCS,
  1113. long cpParaStart,
  1114. long cpParaEnd,
  1115. long cpMin,
  1116. long cpMax,
  1117. BOOL fUnicode)
  1118. {
  1119. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::CheckIMEChange");
  1120. long cpImeSelectStart = 0;
  1121. long cpImeSelectEnd = 0;
  1122. HRESULT hResult;
  1123. if (!lpRCS || _cpReconvertStart == tomForward)
  1124. // Never initialize, forget it
  1125. return FALSE;
  1126. if (fUnicode)
  1127. {
  1128. cpImeSelectStart = _cpReconvertStart + lpRCS->dwCompStrOffset / 2;
  1129. cpImeSelectEnd = cpImeSelectStart + lpRCS->dwCompStrLen;
  1130. }
  1131. else
  1132. {
  1133. // Need to convert the byte offset to char offset.
  1134. ITextRange *pTextRange;
  1135. BSTR bstr = NULL;
  1136. hResult = _pTextDoc->Range(_cpReconvertStart, _cpReconvertEnd, &pTextRange);
  1137. if (hResult != NOERROR)
  1138. return FALSE;
  1139. // Get the text
  1140. hResult = pTextRange->GetText(&bstr);
  1141. if (hResult == S_OK)
  1142. {
  1143. long cchReconvert = _cpReconvertEnd - _cpReconvertStart + 1;
  1144. CTempCharBuf tcb;
  1145. char *psz = tcb.GetBuf((cchReconvert)*2);
  1146. hResult = S_FALSE;
  1147. if (psz)
  1148. {
  1149. long cch = WideCharToMultiByte(_uKeyBoardCodePage, 0,
  1150. bstr, -1, psz, (cchReconvert)*2, NULL, NULL);
  1151. if (cch > 0)
  1152. {
  1153. long dwCompStrOffset, dwCompStrLen;
  1154. CTempWcharBuf twcb;
  1155. WCHAR *pwsz = twcb.GetBuf(cchReconvert);
  1156. if (pwsz)
  1157. {
  1158. dwCompStrOffset = MultiByteToWideChar(_uKeyBoardCodePage, 0,
  1159. psz, lpRCS->dwCompStrOffset, pwsz, cchReconvert);
  1160. dwCompStrLen = MultiByteToWideChar(_uKeyBoardCodePage, 0,
  1161. psz+lpRCS->dwCompStrOffset, lpRCS->dwCompStrLen, pwsz, cchReconvert);
  1162. Assert(dwCompStrOffset > 0 || dwCompStrLen > 0);
  1163. cpImeSelectStart = _cpReconvertStart + dwCompStrOffset;
  1164. cpImeSelectEnd = cpImeSelectStart + dwCompStrLen;
  1165. hResult = S_OK;
  1166. }
  1167. }
  1168. }
  1169. }
  1170. if (bstr)
  1171. SysFreeString (bstr);
  1172. pTextRange->Release();
  1173. if (hResult != S_OK)
  1174. return FALSE;
  1175. }
  1176. if (cpParaStart <= cpImeSelectStart && cpImeSelectEnd <= cpParaEnd)
  1177. {
  1178. if (_pTextSel && (cpImeSelectStart != cpMin || cpImeSelectEnd != cpMax))
  1179. {
  1180. // IME changes selection.
  1181. hResult = _pTextSel->SetRange(cpImeSelectStart, cpImeSelectEnd);
  1182. if (hResult != NOERROR)
  1183. return FALSE;
  1184. }
  1185. return TRUE; // Allow Ime to change selection
  1186. }
  1187. return FALSE;
  1188. }
  1189. /*
  1190. * BOOL CTextMsgFilter::GetTxSelection()
  1191. *
  1192. * @mfunc
  1193. * Get Selection if we haven't got it before
  1194. *
  1195. * @rdesc
  1196. * TRUE if this is first time getting the selection
  1197. * FALSE if it is already exist or no selection available.
  1198. */
  1199. BOOL CTextMsgFilter::GetTxSelection()
  1200. {
  1201. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::GetTxSelection");
  1202. HRESULT hResult;
  1203. if (_pTextSel)
  1204. return FALSE; // Already there
  1205. hResult = _pTextDoc->GetSelectionEx(&_pTextSel);
  1206. return _pTextSel ? TRUE : FALSE;
  1207. }
  1208. /*
  1209. * HRESULT CTextMsgFilter::OnIMEQueryPos(UINT *, WPARAM *, LPARAM *, LRESULT *, BOOL)
  1210. *
  1211. * @mfunc
  1212. * Fill in the current character size and window rect. size.
  1213. *
  1214. * @rdesc
  1215. * S_OK
  1216. * *plres = 0 if we do not filled in data
  1217. */
  1218. HRESULT CTextMsgFilter::OnIMEQueryPos(
  1219. UINT * pmsg,
  1220. WPARAM * pwparam,
  1221. LPARAM * plparam,
  1222. LRESULT * plres,
  1223. BOOL fUnicode)
  1224. {
  1225. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::OnIMEQueryPos");
  1226. HRESULT hResult;
  1227. PIMECHARPOSITION pIMECharPos = (PIMECHARPOSITION)*plparam;
  1228. long cpRequest;
  1229. RECT rcArea;
  1230. ITextRange *pTextRange = NULL;
  1231. POINT ptTopPos, ptBottomPos = {0, 0};
  1232. bool fGetBottomPosFail = false;
  1233. if (pIMECharPos->dwSize != sizeof(IMECHARPOSITION))
  1234. goto Exit;
  1235. // NT doesn't support Ansi window when the CP_ACP isn't the same
  1236. // as keyboard codepage.
  1237. if (!fUnicode && !(W32->OnWin9x()) && _uKeyBoardCodePage != _uSystemCodePage)
  1238. goto Exit;
  1239. if (IsIMEComposition() && _ime->GetIMELevel() == IME_LEVEL_3)
  1240. {
  1241. cpRequest = ((CIme_Lev3 *)_ime)->GetIMECompositionStart();
  1242. if (fUnicode)
  1243. cpRequest += pIMECharPos->dwCharPos;
  1244. else if (pIMECharPos->dwCharPos > 0)
  1245. {
  1246. // Need to convert pIMECharPos->dwCharPos from Acp to Cp
  1247. long cchComp = ((CIme_Lev3 *)_ime)->GetIMECompositionLen();
  1248. long cchAcp = (long)(pIMECharPos->dwCharPos);
  1249. BSTR bstr;
  1250. WCHAR *pChar;
  1251. if (cchComp)
  1252. {
  1253. hResult = _pTextDoc->Range(cpRequest, cpRequest+cchComp, &pTextRange);
  1254. Assert (pTextRange != NULL);
  1255. if (hResult != NOERROR || !pTextRange)
  1256. goto Exit;
  1257. hResult = pTextRange->GetText(&bstr);
  1258. if (hResult != NOERROR )
  1259. goto Exit;
  1260. // The algorithm assumes that for a DBCS charset any character
  1261. // above 128 has two bytes, except for the halfwidth KataKana,
  1262. // which are single bytes in ShiftJis.
  1263. pChar = (WCHAR *)bstr;
  1264. Assert (pChar);
  1265. while (cchAcp > 0 && cchComp > 0)
  1266. {
  1267. cchAcp--;
  1268. if(*pChar >= 128 && (CP_JAPAN != _uKeyBoardCodePage ||
  1269. !IN_RANGE(0xFF61, *pChar, 0xFF9F)))
  1270. cchAcp--;
  1271. pChar++;
  1272. cchComp--;
  1273. cpRequest++;
  1274. }
  1275. SysFreeString (bstr);
  1276. pTextRange->Release();
  1277. pTextRange = NULL;
  1278. }
  1279. }
  1280. }
  1281. else if (pIMECharPos->dwCharPos == 0)
  1282. {
  1283. // Get current selection
  1284. hResult = _pTextSel->GetStart(&cpRequest);
  1285. if (hResult != NOERROR)
  1286. goto Exit;
  1287. }
  1288. else
  1289. goto Exit;
  1290. // Get requested cp location in screen coordinates
  1291. hResult = _pTextDoc->Range(cpRequest, cpRequest+1, &pTextRange);
  1292. Assert (pTextRange != NULL);
  1293. if (hResult != NOERROR || !pTextRange)
  1294. goto Exit;
  1295. long lTextFlow;
  1296. long lTopType;
  1297. long lBottomType;
  1298. lTextFlow = _lFEFlags & tomTextFlowMask;
  1299. lTopType = tomStart+TA_TOP+TA_LEFT;
  1300. lBottomType = tomStart+TA_BOTTOM+TA_LEFT;
  1301. if (lTextFlow == tomTextFlowWN)
  1302. {
  1303. lTopType = tomStart+TA_TOP+TA_RIGHT;
  1304. lBottomType = tomStart+TA_BOTTOM+TA_RIGHT ;
  1305. }
  1306. hResult = pTextRange->GetPoint( lTopType,
  1307. &(ptTopPos.x), &(ptTopPos.y) );
  1308. if (hResult != NOERROR)
  1309. {
  1310. // Scroll and try again
  1311. hResult = pTextRange->ScrollIntoView(tomStart);
  1312. if (hResult == NOERROR)
  1313. hResult = pTextRange->GetPoint( lTopType,
  1314. &(ptTopPos.x), &(ptTopPos.y) );
  1315. }
  1316. if (hResult == NOERROR)
  1317. {
  1318. hResult = pTextRange->GetPoint( lBottomType,
  1319. &(ptBottomPos.x), &(ptBottomPos.y) );
  1320. if (hResult != NOERROR)
  1321. fGetBottomPosFail = true;
  1322. }
  1323. pIMECharPos->pt = ptTopPos;
  1324. // Get application rect in screen coordinates
  1325. hResult = _pTextDoc->GetClientRect(tomIncludeInset,
  1326. &(rcArea.left), &(rcArea.top),
  1327. &(rcArea.right), &(rcArea.bottom));
  1328. if (hResult != NOERROR)
  1329. goto Exit;
  1330. // Get line height in pixel
  1331. if (fGetBottomPosFail)
  1332. pIMECharPos->cLineHeight = rcArea.bottom - ptTopPos.y;
  1333. else
  1334. {
  1335. if (lTextFlow == tomTextFlowSW || lTextFlow == tomTextFlowNE)
  1336. pIMECharPos->cLineHeight = abs(ptTopPos.x - ptBottomPos.x);
  1337. else
  1338. pIMECharPos->cLineHeight = abs(ptBottomPos.y - ptTopPos.y);
  1339. if (lTextFlow == tomTextFlowWN)
  1340. pIMECharPos->pt = ptBottomPos;
  1341. }
  1342. pIMECharPos->rcDocument = rcArea;
  1343. *plres = TRUE;
  1344. Exit:
  1345. if (pTextRange)
  1346. pTextRange->Release();
  1347. return S_OK;
  1348. }
  1349. /*
  1350. * CTextMsgFilter::CheckIMEType(HKL hKL, DWORD dwFlags)
  1351. *
  1352. * @mfunc
  1353. * Check for FE IME keyboard and/or MSIME98 or later
  1354. *
  1355. * @rdesc
  1356. * TRUE if FE IME keyboard
  1357. */
  1358. BOOL CTextMsgFilter::CheckIMEType(
  1359. HKL hKL,
  1360. DWORD dwFlags)
  1361. {
  1362. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::CheckIMEType");
  1363. BOOL fFEKeyboard = FALSE;
  1364. if (!hKL)
  1365. hKL = GetKeyboardLayout(0x0FFFFFFFF); // Get default HKL if caller pass in NULL
  1366. // initialize to non MS IME
  1367. if (dwFlags & CHECK_IME_SERVICE) // Check MSIME98?
  1368. _fMSIME = 0;
  1369. if (IsFELCID((WORD)hKL) && ImmIsIME(hKL, _fUsingAIMM))
  1370. {
  1371. fFEKeyboard = TRUE;
  1372. if (dwFlags & CHECK_IME_SERVICE) // Check MSIME98?
  1373. {
  1374. if (MSIMEServiceMsg && IMEMessage( *this, MSIMEServiceMsg, 0, 0, FALSE ))
  1375. _fMSIME = 1;
  1376. }
  1377. }
  1378. return fFEKeyboard;
  1379. }
  1380. /*
  1381. * CTextMsgFilter::InputFEChar(WCHAR wchFEChar)
  1382. *
  1383. * @mfunc
  1384. * Input the FE character and ensure we have a correct font.
  1385. *
  1386. * @rdesc
  1387. * S_OK if handled
  1388. */
  1389. HRESULT CTextMsgFilter::InputFEChar(
  1390. WCHAR wchFEChar)
  1391. {
  1392. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::InputFEChar");
  1393. BOOL bReleaseSelction = GetTxSelection();
  1394. long cchExced;
  1395. HRESULT hr = S_FALSE;
  1396. if (wchFEChar > 256
  1397. && _pTextSel->CanEdit(NULL) == NOERROR
  1398. && _pTextDoc->CheckTextLimit(1, &cchExced) == NOERROR
  1399. && cchExced == 0)
  1400. {
  1401. // setup FE font to handle the FE character
  1402. long cpMin, cpMax;
  1403. TCHAR wchFE[2];
  1404. BOOL fSelect = FALSE;
  1405. ITextRange *pTextRange = NULL;
  1406. ITextFont *pTextFont = NULL;
  1407. ITextFont *pFEFont = NULL;
  1408. HRESULT hResult = S_FALSE;
  1409. BSTR bstr = NULL;
  1410. // Inform client IME compostion is on to by-pass some font setting
  1411. // problem in Arabic systems
  1412. _pTextDoc->IMEInProgress(tomTrue);
  1413. wchFE[0] = wchFEChar;
  1414. wchFE[1] = L'\0';
  1415. _pTextSel->GetStart(&cpMin);
  1416. _pTextSel->GetEnd(&cpMax);
  1417. // For selection case, we want font to the right of first character
  1418. if (cpMin != cpMax)
  1419. {
  1420. hResult = _pTextDoc->Range(cpMin, cpMin, &pTextRange);
  1421. if (hResult != S_OK)
  1422. goto ERROR_EXIT;
  1423. hResult = pTextRange->GetFont(&pTextFont);
  1424. cpMin++;
  1425. fSelect = TRUE;
  1426. }
  1427. else
  1428. hResult = _pTextSel->GetFont(&pTextFont);
  1429. // Get a duplicate font and setup the correct FE font
  1430. hResult = pTextFont->GetDuplicate(&pFEFont);
  1431. if (hResult != S_OK)
  1432. goto ERROR_EXIT;
  1433. CIme::CheckKeyboardFontMatching (cpMin, this, pFEFont);
  1434. if (fSelect)
  1435. _pTextSel->SetText(NULL); // Delete the selection
  1436. bstr = SysAllocString(wchFE);
  1437. if (!bstr)
  1438. {
  1439. hResult = E_OUTOFMEMORY;
  1440. goto ERROR_EXIT;
  1441. }
  1442. _pTextSel->SetFont(pFEFont); // Setup FE font
  1443. _pTextSel->TypeText(bstr); // Input the new FE character
  1444. ERROR_EXIT:
  1445. if (hResult == S_OK)
  1446. hr = S_OK;
  1447. if (pFEFont)
  1448. pFEFont->Release();
  1449. if (pTextFont)
  1450. pTextFont->Release();
  1451. if (pTextRange)
  1452. pTextRange->Release();
  1453. if (bstr)
  1454. SysFreeString(bstr);
  1455. // Inform client IME compostion is done
  1456. _pTextDoc->IMEInProgress(tomFalse);
  1457. }
  1458. if (bReleaseSelction && _pTextSel)
  1459. {
  1460. _pTextSel->Release();
  1461. _pTextSel = NULL;
  1462. }
  1463. return hr;
  1464. }
  1465. /*
  1466. * CTextMsgFilter::OnSetFocus()
  1467. *
  1468. * @mfunc
  1469. * Restore the previous keyboard if we are in FORCEREMEMBER mode.
  1470. * Otherwise, setup the FE keyboard.
  1471. *
  1472. */
  1473. void CTextMsgFilter::OnSetFocus()
  1474. {
  1475. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::OnSetFocus");
  1476. if (_fUsingUIM && _pCUIM)
  1477. {
  1478. _pCUIM->OnSetFocus();
  1479. }
  1480. else if (_fForceRemember && _fIMEHKL)
  1481. {
  1482. // Restore previous keyboard
  1483. ActivateKeyboardLayout(_fIMEHKL, 0);
  1484. if (IsFELCID((WORD)_fIMEHKL))
  1485. {
  1486. // Set Open status and Conversion mode
  1487. HIMC hIMC = LocalGetImmContext(*this);
  1488. if (hIMC)
  1489. {
  1490. if (ImmSetOpenStatus(hIMC, _fIMEEnable, _fUsingAIMM) && _fIMEEnable)
  1491. ImmSetConversionStatus(hIMC, _fIMEConversion, _fIMESentence, _fUsingAIMM); // Set conversion status
  1492. LocalReleaseImmContext(*this, hIMC);
  1493. }
  1494. }
  1495. }
  1496. else
  1497. SetupIMEOptions();
  1498. if (_nIMEMode)
  1499. SetIMESentenseMode(TRUE);
  1500. }
  1501. /*
  1502. * CTextMsgFilter::OnKillFocus()
  1503. *
  1504. * @mfunc
  1505. * If we are in FORCE_REMEMBER mode, save the current keyboard
  1506. * and conversion setting.
  1507. *
  1508. */
  1509. void CTextMsgFilter::OnKillFocus()
  1510. {
  1511. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::OnKillFocus");
  1512. // Windowless mode, need to inform Cicero
  1513. if (!_hwnd && _fUsingUIM && _pCUIM)
  1514. _pCUIM->OnSetFocus(FALSE);
  1515. if (_fForceRemember)
  1516. {
  1517. // Get current keyboard
  1518. _fIMEHKL = GetKeyboardLayout(0x0FFFFFFFF);
  1519. if (IsFELCID((WORD)_fIMEHKL))
  1520. {
  1521. // Get Open status
  1522. HIMC hIMC = LocalGetImmContext(*this);
  1523. if (hIMC)
  1524. {
  1525. _fIMEEnable = ImmGetOpenStatus(hIMC, _fUsingAIMM);
  1526. if (_fIMEEnable)
  1527. ImmGetConversionStatus(hIMC, &_fIMEConversion, &_fIMESentence, _fUsingAIMM); // get conversion status
  1528. LocalReleaseImmContext(*this, hIMC);
  1529. }
  1530. }
  1531. }
  1532. if (_nIMEMode)
  1533. SetIMESentenseMode(FALSE);
  1534. }
  1535. /*
  1536. * CTextMsgFilter::OnSetIMEOptions(WPARAM wparam, LPARAM lparam)
  1537. *
  1538. * @mfunc
  1539. *
  1540. * @rdesc
  1541. */
  1542. LRESULT CTextMsgFilter::OnSetIMEOptions(
  1543. WPARAM wparam,
  1544. LPARAM lparam)
  1545. {
  1546. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::OnSetIMEOptions");
  1547. LRESULT lIMEOptionCurrent = OnGetIMEOptions();
  1548. LRESULT lIMEOptionNew = 0;
  1549. // Mask off bits that we will support for now
  1550. lparam &= (IMF_FORCEACTIVE | IMF_FORCEENABLE | IMF_FORCEREMEMBER);
  1551. switch(wparam)
  1552. {
  1553. case ECOOP_SET:
  1554. lIMEOptionNew = lparam;
  1555. break;
  1556. case ECOOP_OR:
  1557. lIMEOptionNew = lIMEOptionCurrent | lparam;
  1558. break;
  1559. case ECOOP_AND:
  1560. lIMEOptionNew = lIMEOptionCurrent & lparam;
  1561. break;
  1562. case ECOOP_XOR:
  1563. lIMEOptionNew = lIMEOptionCurrent ^ lparam;
  1564. break;
  1565. default:
  1566. return 0; // Bad option
  1567. }
  1568. if (lIMEOptionNew == lIMEOptionCurrent) // Nothing change
  1569. return 1;
  1570. _fForceActivate = FALSE;
  1571. if (lIMEOptionNew & IMF_FORCEACTIVE)
  1572. _fForceActivate = TRUE;
  1573. _fForceEnable = FALSE;
  1574. if (lIMEOptionNew & IMF_FORCEENABLE)
  1575. _fForceEnable = TRUE;
  1576. _fForceRemember = FALSE;
  1577. if (lIMEOptionNew & IMF_FORCEREMEMBER)
  1578. _fForceRemember = TRUE;
  1579. SetupIMEOptions();
  1580. return 1;
  1581. }
  1582. /*
  1583. * CTextMsgFilter::OnGetIMEOptions()
  1584. *
  1585. * @mfunc
  1586. *
  1587. * @rdesc
  1588. */
  1589. LRESULT CTextMsgFilter::OnGetIMEOptions()
  1590. {
  1591. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::OnGetIMEOptions");
  1592. LRESULT lres = 0;
  1593. if (_fForceActivate)
  1594. lres |= IMF_FORCEACTIVE;
  1595. if (_fForceEnable)
  1596. lres |= IMF_FORCEENABLE;
  1597. if (_fForceRemember)
  1598. lres |= IMF_FORCEREMEMBER;
  1599. return lres;
  1600. }
  1601. /*
  1602. * CTextMsgFilter::SetupIMEOptions()
  1603. *
  1604. * @mfunc
  1605. *
  1606. */
  1607. void CTextMsgFilter::SetupIMEOptions()
  1608. {
  1609. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::SetupIMEOptions");
  1610. if (!_hwnd)
  1611. return;
  1612. _uKeyBoardCodePage = GetKeyboardCodePage(0x0FFFFFFFF);
  1613. if (_fForceEnable)
  1614. {
  1615. LONG cpgLocale = GetACP();
  1616. INT iCharRep = CharRepFromCodePage(cpgLocale);
  1617. if (W32->IsFECodePage(cpgLocale))
  1618. {
  1619. if (_uKeyBoardCodePage != (UINT)cpgLocale)
  1620. W32->CheckChangeKeyboardLayout(iCharRep);
  1621. HIMC hIMC = LocalGetImmContext(*this);
  1622. if (hIMC)
  1623. {
  1624. if (ImmSetOpenStatus(hIMC, TRUE, _fUsingAIMM) && _fForceActivate)
  1625. {
  1626. // Activate native input mode
  1627. DWORD dwConversion;
  1628. DWORD dwSentence;
  1629. if (ImmGetConversionStatus(hIMC, &dwConversion, &dwSentence, _fUsingAIMM))
  1630. {
  1631. dwConversion |= IME_CMODE_NATIVE;
  1632. if (iCharRep == SHIFTJIS_INDEX)
  1633. dwConversion |= IME_CMODE_FULLSHAPE;
  1634. ImmSetConversionStatus(hIMC, dwConversion, dwSentence, _fUsingAIMM);
  1635. }
  1636. }
  1637. LocalReleaseImmContext(*this, hIMC);
  1638. }
  1639. }
  1640. }
  1641. }
  1642. /*
  1643. * CTextMsgFilter::OnSetIMEMode(WPARAM wparam, LPARAM lparam)
  1644. *
  1645. * @mfunc
  1646. * Handle EM_SETIMEMODE message to setup or clear the IMF_SMODE_PHRASEPREDICT mode
  1647. *
  1648. */
  1649. void CTextMsgFilter::OnSetIMEMode(
  1650. WPARAM wparam,
  1651. LPARAM lparam)
  1652. {
  1653. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::OnSetIMEMode");
  1654. BOOL fNotifyUIM = FALSE;
  1655. if (!(lparam & (IMF_SMODE_PLAURALCLAUSE | IMF_SMODE_NONE))) // Only IMF_SMODE_PHRASEPREDICT for now
  1656. return; // Bad mask option
  1657. if ((wparam & (IMF_SMODE_PLAURALCLAUSE | IMF_SMODE_NONE)) == _nIMEMode) // Nothing change...
  1658. return; // Done.
  1659. _nIMEMode = wparam & (IMF_SMODE_PLAURALCLAUSE | IMF_SMODE_NONE);
  1660. if (_hwnd && GetFocus() == _hwnd)
  1661. SetIMESentenseMode(_nIMEMode);
  1662. // Setup UIM mode bias
  1663. if (_nIMEMode)
  1664. {
  1665. if (_nIMEMode == IMF_SMODE_PLAURALCLAUSE && _wUIMModeBias != CTFMODEBIAS_NAME)
  1666. {
  1667. _wUIMModeBias = CTFMODEBIAS_NAME;
  1668. fNotifyUIM = TRUE;
  1669. }
  1670. else if (_nIMEMode == IMF_SMODE_NONE && _wUIMModeBias != CTFMODEBIAS_DEFAULT)
  1671. {
  1672. _wUIMModeBias = CTFMODEBIAS_DEFAULT;
  1673. fNotifyUIM = TRUE;
  1674. }
  1675. }
  1676. else
  1677. {
  1678. _wUIMModeBias = 0;
  1679. fNotifyUIM = TRUE;
  1680. }
  1681. if (fNotifyUIM && _pMsgCallBack)
  1682. _pMsgCallBack->NotifyEvents(NE_MODEBIASCHANGE);
  1683. }
  1684. /*
  1685. * CTextMsgFilter::SetIMESentenseMode()
  1686. *
  1687. * @mfunc
  1688. * Setup phrase mode or restore previous sentence mode
  1689. */
  1690. void CTextMsgFilter::SetIMESentenseMode(
  1691. BOOL fSetup,
  1692. HKL hKL)
  1693. {
  1694. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::SetIMESentenseMode");
  1695. if (_hwnd && CheckIMEType(hKL, 0) && // FE IME Keyboard?
  1696. (fSetup || _fRestoreOLDIME))
  1697. {
  1698. HIMC hIMC = LocalGetImmContext(*this);
  1699. if (hIMC)
  1700. {
  1701. DWORD dwConversion;
  1702. DWORD dwSentence;
  1703. if (ImmGetConversionStatus(hIMC, &dwConversion, &dwSentence, _fUsingAIMM))
  1704. {
  1705. if (fSetup)
  1706. {
  1707. if (!_fRestoreOLDIME)
  1708. {
  1709. // Setup IME Mode
  1710. _wOldIMESentence = dwSentence & 0x0FFFF;
  1711. _fRestoreOLDIME = 1;
  1712. }
  1713. dwSentence &= 0x0FFFF0000;
  1714. if (_nIMEMode == IMF_SMODE_PLAURALCLAUSE)
  1715. dwSentence |= IME_SMODE_PLAURALCLAUSE;
  1716. else
  1717. dwSentence |= IME_SMODE_NONE;
  1718. }
  1719. else
  1720. {
  1721. // Restore previous mode
  1722. dwSentence &= 0x0FFFF0000;
  1723. dwSentence |= _wOldIMESentence;
  1724. _fRestoreOLDIME = 0;
  1725. }
  1726. ImmSetConversionStatus(hIMC, dwConversion, dwSentence, _fUsingAIMM);
  1727. }
  1728. LocalReleaseImmContext(*this, hIMC);
  1729. }
  1730. }
  1731. }
  1732. /*
  1733. * CTextMsgFilter::OnGetIMECompText(WPARAM wparam, LPARAM lparam)
  1734. *
  1735. * @mfunc
  1736. *
  1737. * @rdesc
  1738. */
  1739. int CTextMsgFilter::OnGetIMECompText(
  1740. WPARAM wparam,
  1741. LPARAM lparam)
  1742. {
  1743. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::OnGetIMECompText");
  1744. if (_ime)
  1745. {
  1746. HRESULT hr;
  1747. IMECOMPTEXT *pIMECompText = (IMECOMPTEXT *)wparam;
  1748. if (pIMECompText->flags == ICT_RESULTREADSTR)
  1749. {
  1750. int cbSize = pIMECompText->cb;
  1751. hr = CIme::CheckInsertResultString(0, *this, NULL, &cbSize, (WCHAR *)lparam);
  1752. if (hr == S_OK)
  1753. return cbSize/2;
  1754. }
  1755. }
  1756. return 0;
  1757. }
  1758. /*
  1759. * CTextMsgFilter::NoIMEProcess()
  1760. *
  1761. * @mfunc
  1762. * check if you should handle IME
  1763. */
  1764. BOOL CTextMsgFilter::NoIMEProcess()
  1765. {
  1766. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::NoIMEProcess");
  1767. if (_fNoIme)
  1768. return TRUE;
  1769. _pTextDoc->GetFEFlags(&_lFEFlags);
  1770. if (_lFEFlags & (ES_NOIME | tomUsePassword))
  1771. return TRUE;
  1772. return FALSE;
  1773. }
  1774. /*
  1775. * CTextMsgFilter::MouseOperation(UINT msg, long ichStart, long cchComp, WPARAM wParam,
  1776. * WPARAM *pwParamBefore, BOOL *pfTerminateIME, HWND hwndIME)
  1777. *
  1778. * @mfunc
  1779. * handle mouse operation for CTF or IME
  1780. *
  1781. * @rdesc
  1782. * BOOL-TRUE if CTF or IME handled the mouse events
  1783. */
  1784. BOOL CTextMsgFilter::MouseOperation(
  1785. UINT msg,
  1786. long ichStart,
  1787. long cchComp,
  1788. WPARAM wParam,
  1789. WPARAM *pwParamBefore,
  1790. BOOL *pfTerminateIME,
  1791. HWND hwndIME,
  1792. long *pCpCursor,
  1793. ITfMouseSink *pMouseSink)
  1794. {
  1795. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::MouseOperation");
  1796. BOOL fRetCode = FALSE;
  1797. BOOL fButtonPressed = FALSE;
  1798. WORD wButtons = 0;
  1799. POINT ptCursor;
  1800. WPARAM wParamIME;
  1801. WPARAM fwkeys = wParam;
  1802. BOOL fHandleIME = hwndIME ? TRUE : FALSE;
  1803. HWND hHostWnd = _hwnd;
  1804. long hWnd;
  1805. if (!hHostWnd) // Windowless mode...
  1806. {
  1807. if (_pTextDoc->GetWindow(&hWnd) != S_OK || !hWnd)
  1808. return FALSE;
  1809. hHostWnd = (HWND)(DWORD_PTR)hWnd;
  1810. }
  1811. *pfTerminateIME = TRUE;
  1812. switch (msg)
  1813. {
  1814. case WM_MOUSEMOVE:
  1815. goto LCheckButton;
  1816. case WM_LBUTTONDOWN:
  1817. fButtonPressed = TRUE;
  1818. case WM_LBUTTONDBLCLK:
  1819. fwkeys |= MK_LBUTTON;
  1820. goto LCheckButton;
  1821. case WM_LBUTTONUP:
  1822. fwkeys &= (~MK_LBUTTON);
  1823. goto LCheckButton;
  1824. case WM_RBUTTONDOWN:
  1825. fButtonPressed = TRUE;
  1826. case WM_RBUTTONDBLCLK:
  1827. fwkeys |= MK_RBUTTON;
  1828. goto LCheckButton;
  1829. case WM_RBUTTONUP:
  1830. fwkeys &= (~MK_RBUTTON);
  1831. goto LCheckButton;
  1832. case WM_MBUTTONUP:
  1833. fwkeys &= (~MK_MBUTTON);
  1834. goto LCheckButton;
  1835. case WM_MBUTTONDOWN:
  1836. fButtonPressed = TRUE;
  1837. case WM_MBUTTONDBLCLK:
  1838. fwkeys |= MK_MBUTTON;
  1839. LCheckButton:
  1840. if (fwkeys & MK_LBUTTON)
  1841. wButtons |= IMEMOUSE_LDOWN;
  1842. if (fwkeys & MK_RBUTTON)
  1843. wButtons |= IMEMOUSE_RDOWN;
  1844. if (fwkeys & MK_MBUTTON)
  1845. wButtons |= IMEMOUSE_MDOWN;
  1846. break;
  1847. case WM_SETCURSOR:
  1848. wButtons = LOBYTE(*pwParamBefore);
  1849. break;
  1850. default:
  1851. return FALSE;
  1852. }
  1853. // Kor special - click should terminate IME
  1854. if (fHandleIME && fButtonPressed && _uKeyBoardCodePage == CP_KOREAN)
  1855. {
  1856. *pfTerminateIME = TRUE;
  1857. return FALSE;
  1858. }
  1859. // Change in button since last message?
  1860. if ((wButtons != LOBYTE(LOWORD(*pwParamBefore))) && GetCapture() == hHostWnd)
  1861. {
  1862. fButtonPressed = FALSE;
  1863. wButtons = 0;
  1864. ReleaseCapture();
  1865. }
  1866. if (GetCursorPos(&ptCursor))
  1867. {
  1868. ITextRange *pTextRange;
  1869. HRESULT hResult;
  1870. long ichCursor;
  1871. long lTextFlow;
  1872. POINT ptCPTop = {0, 0};
  1873. POINT ptCPBottom = {0, 0};
  1874. POINT ptCenterTop = {0, 0};
  1875. POINT ptCenterBottom = {0, 0};
  1876. BOOL fWithinCompText = FALSE;
  1877. // Get cp at current Cursor position
  1878. hResult = _pTextDoc->RangeFromPoint(ptCursor.x, ptCursor.y,
  1879. &pTextRange);
  1880. if (hResult != NOERROR)
  1881. return FALSE;
  1882. _pTextDoc->GetFEFlags(&lTextFlow);
  1883. lTextFlow &= tomTextFlowMask;
  1884. hResult = pTextRange->GetStart(&ichCursor);
  1885. pTextRange->GetPoint(TA_TOP, &(ptCPTop.x), &(ptCPTop.y));
  1886. pTextRange->GetPoint(TA_BOTTOM, &(ptCPBottom.x), &(ptCPBottom.y));
  1887. pTextRange->Release();
  1888. pTextRange = NULL;
  1889. if (hResult != NOERROR)
  1890. return FALSE;
  1891. if (pCpCursor)
  1892. *pCpCursor = ichCursor;
  1893. // Click within composition text?
  1894. if (ichStart <= ichCursor && ichCursor <= ichStart + cchComp)
  1895. {
  1896. WORD wPos = 0;
  1897. LONG lTestCursor = TestPoint(ptCPTop, ptCPBottom, ptCursor, TEST_ALL, lTextFlow);
  1898. if (lTestCursor & (TEST_TOP | TEST_BOTTOM))
  1899. goto HIT_OUTSIDE;
  1900. // Cursor locates to the left of the first composition character
  1901. // or cursor locates to the right of the last composition character
  1902. if (ichStart == ichCursor && (lTestCursor & TEST_LEFT) ||
  1903. ichCursor == ichStart + cchComp && (lTestCursor & TEST_RIGHT))
  1904. goto HIT_OUTSIDE;
  1905. // Need to calculate the relative position of the Cursor and the center of character:
  1906. //
  1907. // If Cursor locates to the Left of the cp,
  1908. // If Cursor is more than 1/4 the character width from the cp
  1909. // wPos = 0;
  1910. // Otherwise
  1911. // wPos = 1;
  1912. //
  1913. // If Cursor locates to the Right of the cp,
  1914. // If Cursor is less than 1/4 the character width from the cp
  1915. // wPos = 2;
  1916. // Otherwise
  1917. // wPos = 3;
  1918. //
  1919. if (lTestCursor & TEST_LEFT)
  1920. hResult = _pTextDoc->Range(ichCursor-1, ichCursor, &pTextRange);
  1921. else
  1922. hResult = _pTextDoc->Range(ichCursor, ichCursor+1, &pTextRange);
  1923. if (pTextRange)
  1924. {
  1925. LONG lTestCenter = 0;
  1926. LONG uMouse = 0;
  1927. LONG uHalfCenter = 0;
  1928. pTextRange->GetPoint(tomStart + TA_TOP + TA_CENTER, &(ptCenterTop.x), &(ptCenterTop.y));
  1929. pTextRange->GetPoint(tomStart + TA_BOTTOM + TA_CENTER, &(ptCenterBottom.x), &(ptCenterBottom.y));
  1930. pTextRange->Release();
  1931. lTestCenter = TestPoint(ptCPTop, ptCPBottom, ptCenterBottom, TEST_ALL, lTextFlow);
  1932. if (lTestCenter & (TEST_TOP | TEST_BOTTOM))
  1933. goto HIT_OUTSIDE; // Not on the same line
  1934. if (lTextFlow == tomTextFlowES || lTextFlow == tomTextFlowWN)
  1935. {
  1936. uMouse = ptCursor.x - ptCPBottom.x;
  1937. uHalfCenter = ptCenterBottom.x - ptCPBottom.x;
  1938. }
  1939. else
  1940. {
  1941. uMouse = ptCursor.y - ptCPBottom.y;
  1942. uHalfCenter = ptCenterBottom.y - ptCPBottom.y;
  1943. }
  1944. uMouse = abs(uMouse);
  1945. uHalfCenter = abs(uHalfCenter) / 2;
  1946. if (lTestCursor & TEST_LEFT)
  1947. {
  1948. if (lTestCenter & TEST_LEFT)
  1949. wPos = uMouse > uHalfCenter ? 0: 1;
  1950. }
  1951. else if (lTestCenter & TEST_RIGHT)
  1952. wPos = uMouse >= uHalfCenter ? 3: 2;
  1953. wButtons = MAKEWORD(wButtons, wPos);
  1954. }
  1955. wParamIME = MAKEWPARAM(wButtons, ichCursor - ichStart);
  1956. fButtonPressed &= (*pwParamBefore & 0xff) == 0;
  1957. if (*pwParamBefore != wParamIME || fHandleIME && msg == WM_MOUSEMOVE && !fButtonPressed)
  1958. {
  1959. *pwParamBefore = wParamIME;
  1960. if (fHandleIME) // IME case
  1961. {
  1962. HIMC hIMC = LocalGetImmContext(*this);
  1963. if (hIMC)
  1964. {
  1965. fRetCode = SendMessage(hwndIME, MSIMEMouseMsg, *pwParamBefore, hIMC);
  1966. LocalReleaseImmContext(*this, hIMC);
  1967. }
  1968. }
  1969. else // Cicero case
  1970. {
  1971. BOOL fEaten = FALSE;
  1972. DWORD dwBtn = 0;
  1973. dwBtn |= wButtons & IMEMOUSE_LDOWN ? MK_LBUTTON : 0;
  1974. dwBtn |= wButtons & IMEMOUSE_MDOWN ? MK_MBUTTON : 0;
  1975. dwBtn |= wButtons & IMEMOUSE_RDOWN ? MK_RBUTTON : 0;
  1976. if (S_OK == pMouseSink->OnMouseEvent(ichCursor - ichStart, wPos, dwBtn, &fEaten) && fEaten)
  1977. fRetCode = TRUE;
  1978. }
  1979. }
  1980. else
  1981. fRetCode = TRUE; // No change from last time, no need to send message to IME
  1982. fWithinCompText = TRUE;
  1983. if (fHandleIME && fRetCode && fButtonPressed && GetCapture() != hHostWnd)
  1984. SetCapture(hHostWnd);
  1985. }
  1986. HIT_OUTSIDE:
  1987. if (!fWithinCompText && (GetCapture() == hHostWnd || msg == WM_LBUTTONUP)) //We don't want to determine while dragging...
  1988. fRetCode = TRUE;
  1989. }
  1990. *pfTerminateIME = !fRetCode;
  1991. return fRetCode;
  1992. }
  1993. /*
  1994. * CTextMsgFilter::CompleteUIMTyping(LONG mode, BOOL fTransaction)
  1995. *
  1996. * @mfunc
  1997. * Terminate IME or UIM composition
  1998. *
  1999. */
  2000. void CTextMsgFilter::CompleteUIMTyping(
  2001. LONG mode,
  2002. BOOL fTransaction)
  2003. {
  2004. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::CompleteUIMTyping");
  2005. if (_ime)
  2006. {
  2007. Assert(!(_pCUIM && _pCUIM->IsUIMTyping()));
  2008. _ime->TerminateIMEComposition(*this, (CIme::TerminateMode)mode);
  2009. }
  2010. else
  2011. {
  2012. Assert (_pCUIM);
  2013. if (_pCUIM && _fSendTransaction == 0)
  2014. {
  2015. if (fTransaction)
  2016. {
  2017. ITextStoreACPSink *ptss = _pCUIM->_ptss;
  2018. if (ptss)
  2019. {
  2020. _fSendTransaction = 1;
  2021. ptss->OnStartEditTransaction();
  2022. }
  2023. }
  2024. _pCUIM->CompleteUIMText();
  2025. }
  2026. }
  2027. }
  2028. /*
  2029. * CTextMsgFilter::GetIMECompAttributes()
  2030. *
  2031. * @mfunc
  2032. * Get the 1.0 mode IME color and underline for displaying cmposition strings
  2033. *
  2034. * @rdesc
  2035. * COMPCOLOR *. Could be NULL if PvAlloc failed
  2036. *
  2037. */
  2038. COMPCOLOR* CTextMsgFilter::GetIMECompAttributes()
  2039. {
  2040. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::GetIMECompAttributes");
  2041. // For 1.0 mode IME color
  2042. if (!_pcrComp)
  2043. {
  2044. _pcrComp = (COMPCOLOR *)PvAlloc(sizeof(COMPCOLOR) * 4, GMEM_ZEROINIT);
  2045. if (_pcrComp)
  2046. {
  2047. // Init. IME composition color/underline the same way as RE1.0
  2048. _pcrComp[0].crBackground = 0x0ffffff;
  2049. _pcrComp[0].dwEffects = CFE_UNDERLINE;
  2050. _pcrComp[1].crBackground = 0x0808080;
  2051. _pcrComp[2].crBackground = 0x0ffffff;
  2052. _pcrComp[2].dwEffects = CFE_UNDERLINE;
  2053. _pcrComp[3].crText = 0x0ffffff;
  2054. }
  2055. }
  2056. return _pcrComp;
  2057. }
  2058. /*
  2059. * CTextMsgFilter::SetupCallback()
  2060. *
  2061. * @mfunc
  2062. *
  2063. * @rdesc
  2064. *
  2065. */
  2066. void CTextMsgFilter::SetupCallback()
  2067. {
  2068. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::SetupCallback");
  2069. if (!_pMsgCallBack)
  2070. _pMsgCallBack = new CMsgCallBack(this);
  2071. if (_pMsgCallBack)
  2072. {
  2073. LRESULT lresult;
  2074. _pTextService->TxSendMessage(EM_SETCALLBACK, 0, (LPARAM)_pMsgCallBack, &lresult);
  2075. }
  2076. }
  2077. /*
  2078. * CTextMsgFilter::SetupLangSink()
  2079. *
  2080. * @mfunc
  2081. * Setup the Language sink to catch the keyboard changing event. We are not
  2082. * getting WM_INPUTLANGCHANGEREQUEST and thus need this sink.
  2083. *
  2084. */
  2085. void CTextMsgFilter::SetupLangSink()
  2086. {
  2087. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::SetupLangSink");
  2088. if (!_pITfIPP)
  2089. {
  2090. CoCreateInstance(CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_INPROC_SERVER,
  2091. IID_ITfInputProcessorProfiles, (void**)&_pITfIPP);
  2092. if (_pITfIPP)
  2093. {
  2094. _pCLangProfileSink = new CLangProfileSink();
  2095. if (_pCLangProfileSink)
  2096. {
  2097. if (_pCLangProfileSink->_Advise(this, _pITfIPP) != S_OK)
  2098. {
  2099. _pCLangProfileSink->Release();
  2100. _pCLangProfileSink = NULL;
  2101. _pITfIPP->Release();
  2102. _pITfIPP = NULL;
  2103. }
  2104. }
  2105. else
  2106. {
  2107. _pITfIPP->Release();
  2108. _pITfIPP = NULL;
  2109. }
  2110. }
  2111. }
  2112. }
  2113. /*
  2114. * CTextMsgFilter::ReleaseLangSink()
  2115. *
  2116. * @mfunc
  2117. * Release the lang sink object
  2118. *
  2119. */
  2120. void CTextMsgFilter::ReleaseLangSink()
  2121. {
  2122. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::ReleaseLangSink");
  2123. if (_pITfIPP)
  2124. {
  2125. Assert(_pCLangProfileSink);
  2126. _pCLangProfileSink->_Unadvise();
  2127. _pCLangProfileSink->Release();
  2128. _pCLangProfileSink = NULL;
  2129. _pITfIPP->Release();
  2130. _pITfIPP = NULL;
  2131. }
  2132. }
  2133. /*
  2134. * CTextMsgFilter::StartUIM()
  2135. *
  2136. * @mfunc
  2137. *
  2138. * @rdesc
  2139. *
  2140. */
  2141. void CTextMsgFilter::StartUIM()
  2142. {
  2143. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::StartUIM");
  2144. if (NoIMEProcess())
  2145. return;
  2146. _fUsingUIM = CreateUIM(this);
  2147. if (_fUsingUIM)
  2148. {
  2149. SetupCallback();
  2150. SetupLangSink();
  2151. }
  2152. }
  2153. /*
  2154. * CTextMsgFilter::StartAimm()
  2155. *
  2156. * @mfunc
  2157. *
  2158. * @rdesc
  2159. *
  2160. */
  2161. void CTextMsgFilter::StartAimm(BOOL fUseAimm12)
  2162. {
  2163. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::StartAimm");
  2164. if (!_hwnd || NoIMEProcess())
  2165. return;
  2166. if (LoadAIMM(fUseAimm12))
  2167. {
  2168. HRESULT hResult = ActivateAIMM(FALSE);
  2169. if (hResult == NOERROR)
  2170. {
  2171. DWORD dwAtom;
  2172. ATOM aClass;
  2173. // filter client windows
  2174. if (dwAtom = GetClassLong(_hwnd, GCW_ATOM))
  2175. {
  2176. aClass = dwAtom;
  2177. hResult = FilterClientWindowsAIMM(&aClass, 1, _hwnd);
  2178. }
  2179. _fUsingAIMM = 1;
  2180. SetupCallback();
  2181. if (!fLoadAIMM10)
  2182. SetupLangSink();
  2183. }
  2184. }
  2185. }
  2186. /*
  2187. * CTextMsgFilter::TurnOffUIM()
  2188. *
  2189. * @mfunc
  2190. *
  2191. * @rdesc
  2192. *
  2193. */
  2194. void CTextMsgFilter::TurnOffUIM(BOOL fSafeToSendMessage)
  2195. {
  2196. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::TurnOffUIM");
  2197. if (fSafeToSendMessage && _fUsingUIM && _pCUIM && _pCUIM->IsUIMTyping())
  2198. CompleteUIMTyping(CIme::TERMINATE_NORMAL);
  2199. _fUsingUIM = FALSE;
  2200. ReleaseLangSink();
  2201. // Release various objects
  2202. if (_pCUIM)
  2203. {
  2204. CUIM *pCUIM = _pCUIM;
  2205. LRESULT lresult;
  2206. _pCUIM = NULL;
  2207. if (fSafeToSendMessage)
  2208. _pTextService->TxSendMessage(EM_SETUPNOTIFY, 0, (LPARAM)(ITxNotify *)pCUIM, &lresult);
  2209. else
  2210. pCUIM->_fShutDown = 1;
  2211. pCUIM->Uninit();
  2212. pCUIM->Release();
  2213. }
  2214. if (_pTim)
  2215. {
  2216. ITfThreadMgr *pTim = _pTim;
  2217. _pTim = NULL;
  2218. pTim->Deactivate();
  2219. pTim->Release();
  2220. }
  2221. // Turn off Callback
  2222. if (fSafeToSendMessage && _pMsgCallBack)
  2223. {
  2224. LRESULT lresult;
  2225. _pTextService->TxSendMessage(EM_SETCALLBACK, 0, (LPARAM)0, &lresult);
  2226. delete _pMsgCallBack;
  2227. _pMsgCallBack = NULL;
  2228. }
  2229. }
  2230. /*
  2231. * CTextMsgFilter::HandleCTFService(wparam, lparam)
  2232. *
  2233. * @mfunc
  2234. * Setup Cicero setting to handle or disable smarttag and proofing services
  2235. *
  2236. */
  2237. void CTextMsgFilter::HandleCTFService(
  2238. WPARAM wparam,
  2239. LPARAM lparam)
  2240. {
  2241. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::HandleCTFService");
  2242. BOOL fChangeInSetting = FALSE;
  2243. if (lparam & SES_CTFALLOWSMARTTAG)
  2244. {
  2245. BOOL fAllowSmartTagLocal = (wparam & SES_CTFALLOWSMARTTAG) ? 1 : 0;
  2246. if ((BOOL)_fAllowSmartTag != fAllowSmartTagLocal)
  2247. {
  2248. _fAllowSmartTag = fAllowSmartTagLocal;
  2249. fChangeInSetting = TRUE;
  2250. }
  2251. }
  2252. if (lparam & SES_CTFALLOWPROOFING)
  2253. {
  2254. BOOL fAllowProofLocal = (wparam & SES_CTFALLOWPROOFING) ? 1 : 0;
  2255. if ((BOOL)_fAllowProofing != fAllowProofLocal)
  2256. {
  2257. _fAllowProofing = fAllowProofLocal;
  2258. fChangeInSetting = TRUE;
  2259. }
  2260. }
  2261. if (fChangeInSetting)
  2262. {
  2263. if (_fUsingUIM && _pCUIM)
  2264. _pCUIM->NotifyService();
  2265. }
  2266. }
  2267. /*
  2268. * CTextMsgFilter::TurnOffAimm()
  2269. *
  2270. * @mfunc
  2271. * Turn off Aimm.
  2272. *
  2273. */
  2274. void CTextMsgFilter::TurnOffAimm(BOOL fSafeToSendMessage)
  2275. {
  2276. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::TurnOffAimm");
  2277. if (_fUsingAIMM)
  2278. {
  2279. if (IsIMEComposition())
  2280. {
  2281. if (fSafeToSendMessage)
  2282. CompleteUIMTyping(CIme::TERMINATE_NORMAL);
  2283. else
  2284. {
  2285. delete _ime;
  2286. _ime = NULL;
  2287. }
  2288. }
  2289. _fUsingAIMM = FALSE;
  2290. UnfilterClientWindowsAIMM(_hwnd);
  2291. DeactivateAIMM();
  2292. ReleaseLangSink();
  2293. // Turn off Callback
  2294. if (fSafeToSendMessage && _pMsgCallBack)
  2295. {
  2296. LRESULT lresult;
  2297. _pTextService->TxSendMessage(EM_SETCALLBACK, 0, (LPARAM)0, &lresult);
  2298. delete _pMsgCallBack;
  2299. _pMsgCallBack = NULL;
  2300. }
  2301. }
  2302. }
  2303. /*
  2304. * void CTextMsgFilter::OnSetUIMMode()
  2305. *
  2306. * @mfunc
  2307. *
  2308. * @rdesc
  2309. *
  2310. */
  2311. void CTextMsgFilter::OnSetUIMMode(WORD wUIMModeBias)
  2312. {
  2313. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextMsgFilter::OnSetUIMMode");
  2314. if (_wUIMModeBias != wUIMModeBias &&
  2315. IN_RANGE(CTFMODEBIAS_DEFAULT, wUIMModeBias, CTFMODEBIAS_HALFWIDTHALPHANUMERIC))
  2316. {
  2317. _wUIMModeBias = wUIMModeBias;
  2318. if (_pMsgCallBack)
  2319. _pMsgCallBack->NotifyEvents(NE_MODEBIASCHANGE);
  2320. }
  2321. }
  2322. /*
  2323. * HRESULT CMsgCallBack::HandlePostMessage()
  2324. *
  2325. * @mfunc
  2326. *
  2327. * @rdesc
  2328. *
  2329. */
  2330. HRESULT CMsgCallBack::HandlePostMessage(
  2331. HWND hWnd,
  2332. UINT msg,
  2333. WPARAM wparam,
  2334. LPARAM lparam,
  2335. LRESULT *plres)
  2336. {
  2337. //TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CMsgCallBack::HandlePostMessage");
  2338. if (_pTextMsgFilter->_fUsingAIMM)
  2339. return CallAIMMDefaultWndProc(hWnd, msg, wparam, lparam, plres);
  2340. return S_FALSE;
  2341. }
  2342. /*
  2343. * HRESULT CMsgCallBack::NotifyEvents()
  2344. *
  2345. * @mfunc
  2346. *
  2347. * @rdesc
  2348. *
  2349. */
  2350. HRESULT CMsgCallBack::NotifyEvents(DWORD dwEvents)
  2351. {
  2352. //TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CMsgCallBack::NotifyEvents");
  2353. CUIM *pCUIM = _pTextMsgFilter->_pCUIM;
  2354. if (pCUIM)
  2355. {
  2356. ITextStoreACPSink *ptss = pCUIM->_ptss;
  2357. if (dwEvents & NE_ENTERTOPLEVELCALLMGR)
  2358. {
  2359. pCUIM->_cCallMgrLevels++;
  2360. }
  2361. else if (dwEvents & NE_EXITTOPLEVELCALLMGR)
  2362. {
  2363. Assert (pCUIM->_cCallMgrLevels > 0);
  2364. pCUIM->_cCallMgrLevels--;
  2365. }
  2366. if (pCUIM->_cCallMgrLevels)
  2367. {
  2368. // Save events to be sent later
  2369. if ((dwEvents & NE_CALLMGRSELCHANGE) && !pCUIM->_fReadLockOn)
  2370. pCUIM->_fSelChangeEventPending = 1;
  2371. if (dwEvents & (NE_CALLMGRCHANGE | NE_LAYOUTCHANGE))
  2372. pCUIM->_fLayoutEventPending = 1;
  2373. if (dwEvents & NE_MODEBIASCHANGE)
  2374. pCUIM->_fModeBiasPending = 1;
  2375. }
  2376. else
  2377. {
  2378. if (pCUIM->_fSelChangeEventPending || (dwEvents & NE_CALLMGRSELCHANGE))
  2379. {
  2380. pCUIM->_fSelChangeEventPending = 0;
  2381. if (ptss && !pCUIM->_fHoldCTFSelChangeNotify && !pCUIM->_fReadLockOn)
  2382. ptss->OnSelectionChange();
  2383. }
  2384. if (pCUIM->_fLayoutEventPending || (dwEvents & (NE_CALLMGRCHANGE | NE_LAYOUTCHANGE)))
  2385. {
  2386. pCUIM->_fLayoutEventPending = 0;
  2387. if (ptss)
  2388. ptss->OnLayoutChange(TS_LC_CHANGE, 0);
  2389. }
  2390. if (pCUIM->_fModeBiasPending || (dwEvents & NE_MODEBIASCHANGE))
  2391. {
  2392. pCUIM->_fModeBiasPending = 0;
  2393. if (ptss)
  2394. {
  2395. LONG ccpMax = 0;
  2396. if (pCUIM->GetStoryLength(&ccpMax) != S_OK)
  2397. ccpMax = tomForward;
  2398. ptss->OnAttrsChange(0, ccpMax, 1, &GUID_PROP_MODEBIAS); // only ModeBias for now
  2399. }
  2400. }
  2401. // Probably safe to let UIM to lock data now
  2402. if (ptss && (pCUIM->_fReadLockPending || pCUIM->_fWriteLockPending))
  2403. {
  2404. HRESULT hResult;
  2405. HRESULT hResult1;
  2406. hResult = pCUIM->RequestLock(pCUIM->_fWriteLockPending ? TS_LF_READWRITE : TS_LF_READ, &hResult1);
  2407. }
  2408. if (_pTextMsgFilter->_fSendTransaction)
  2409. {
  2410. _pTextMsgFilter->_fSendTransaction = 0;
  2411. if (ptss)
  2412. ptss->OnEndEditTransaction();
  2413. }
  2414. pCUIM->_fHoldCTFSelChangeNotify = 0;
  2415. }
  2416. }
  2417. return S_OK;
  2418. }
  2419. /*
  2420. * CLangProfileSink::QueryInterface()
  2421. *
  2422. * @mfunc
  2423. *
  2424. * @rdesc
  2425. *
  2426. */
  2427. STDAPI CLangProfileSink::QueryInterface(REFIID riid, void **ppvObj)
  2428. {
  2429. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CLangProfileSink::QueryInterface");
  2430. *ppvObj = NULL;
  2431. if (IsEqualIID(riid, IID_IUnknown) ||
  2432. IsEqualIID(riid, IID_ITfLanguageProfileNotifySink))
  2433. *ppvObj = this;
  2434. if (*ppvObj)
  2435. {
  2436. AddRef();
  2437. return S_OK;
  2438. }
  2439. return E_NOINTERFACE;
  2440. }
  2441. /*
  2442. * CLangProfileSink::AddRef()
  2443. *
  2444. * @mfunc
  2445. *
  2446. * @rdesc
  2447. *
  2448. */
  2449. STDAPI_(ULONG) CLangProfileSink::AddRef()
  2450. {
  2451. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CLangProfileSink::AddRef");
  2452. return ++_cRef;
  2453. }
  2454. /*
  2455. * CLangProfileSink::Release()
  2456. *
  2457. * @mfunc
  2458. *
  2459. * @rdesc
  2460. *
  2461. */
  2462. STDAPI_(ULONG) CLangProfileSink::Release()
  2463. {
  2464. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CLangProfileSink::Release");
  2465. long cr;
  2466. cr = --_cRef;
  2467. Assert(cr >= 0);
  2468. if (cr == 0)
  2469. delete this;
  2470. return cr;
  2471. }
  2472. /*
  2473. * CLangProfileSink::CLangProfileSink()
  2474. *
  2475. * @mfunc
  2476. *
  2477. * @rdesc
  2478. *
  2479. */
  2480. CLangProfileSink::CLangProfileSink()
  2481. {
  2482. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CLangProfileSink::CLangProfileSink");
  2483. _cRef = 1;
  2484. _dwCookie = (DWORD)(-1);
  2485. }
  2486. /*
  2487. * CLangProfileSink::OnLanguageChange()
  2488. *
  2489. * @mfunc
  2490. *
  2491. * @rdesc
  2492. *
  2493. */
  2494. STDMETHODIMP CLangProfileSink::OnLanguageChange(LANGID langid, BOOL *pfAccept)
  2495. {
  2496. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CLangProfileSink::OnLanguageChange");
  2497. Assert (pfAccept);
  2498. *pfAccept = TRUE;
  2499. if (_pTextMsgFilter->_hwnd && GetFocus() == _pTextMsgFilter->_hwnd)
  2500. {
  2501. LRESULT lresult = 0;
  2502. if ( S_OK == _pTextMsgFilter->_pTextService->TxSendMessage(
  2503. EM_GETDOCFLAGS, GDF_ALL, 0, &lresult))
  2504. {
  2505. if (lresult & GDF_SINGLECPG)
  2506. {
  2507. LCID syslcid = GetSysLCID();
  2508. // Check if new langid supported by the system
  2509. if (langid != syslcid)
  2510. {
  2511. LOCALESIGNATURE ls;
  2512. if(GetLocaleInfoA(langid, LOCALE_FONTSIGNATURE, (LPSTR)&ls, sizeof(ls)))
  2513. {
  2514. CHARSETINFO cs;
  2515. HDC hdc = GetDC(_pTextMsgFilter->_hwnd);
  2516. TranslateCharsetInfo((DWORD *)(DWORD_PTR)GetTextCharsetInfo(hdc, NULL, 0), &cs, TCI_SRCCHARSET);
  2517. ReleaseDC(_pTextMsgFilter->_hwnd, hdc);
  2518. DWORD fsShell = cs.fs.fsCsb[0];
  2519. if (!(fsShell & ls.lsCsbSupported[0]))
  2520. *pfAccept = FALSE;
  2521. }
  2522. }
  2523. }
  2524. }
  2525. if (*pfAccept == TRUE && _pTextMsgFilter-> _nIMEMode)
  2526. _pTextMsgFilter->SetIMESentenseMode(FALSE);
  2527. }
  2528. return S_OK;
  2529. }
  2530. /*
  2531. * CLangProfileSink::OnLanguageChanged()
  2532. *
  2533. * @mfunc
  2534. *
  2535. * @rdesc
  2536. *
  2537. */
  2538. STDMETHODIMP CLangProfileSink::OnLanguageChanged()
  2539. {
  2540. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CLangProfileSink::OnLanguageChanged");
  2541. return S_OK;
  2542. }
  2543. /*
  2544. * CLangProfileSink::_Advise()
  2545. *
  2546. * @mfunc
  2547. *
  2548. * @rdesc
  2549. *
  2550. */
  2551. HRESULT CLangProfileSink::_Advise(
  2552. CTextMsgFilter *pTextMsgFilter,
  2553. ITfInputProcessorProfiles *pipp)
  2554. {
  2555. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CLangProfileSink::_Advise");
  2556. HRESULT hr;
  2557. ITfSource *pSource = NULL;
  2558. _pTextMsgFilter = pTextMsgFilter;
  2559. _pITFIPP = pipp;
  2560. hr = E_FAIL;
  2561. if (FAILED(_pITFIPP->QueryInterface(IID_ITfSource, (void **)&pSource)))
  2562. goto Exit;
  2563. if (FAILED(pSource->AdviseSink(IID_ITfLanguageProfileNotifySink, this, &_dwCookie)))
  2564. goto Exit;
  2565. hr = S_OK;
  2566. Exit:
  2567. pSource->Release();
  2568. return hr;
  2569. }
  2570. /*
  2571. * CLangProfileSink::_Unadvise()
  2572. *
  2573. * @mfunc
  2574. *
  2575. * @rdesc
  2576. *
  2577. */
  2578. HRESULT CLangProfileSink::_Unadvise()
  2579. {
  2580. TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CLangProfileSink::_Unadvise");
  2581. HRESULT hr;
  2582. ITfSource *pSource = NULL;
  2583. hr = E_FAIL;
  2584. if (_pITFIPP == NULL)
  2585. return hr;
  2586. if (FAILED(_pITFIPP->QueryInterface(IID_ITfSource, (void **)&pSource)))
  2587. return hr;
  2588. if (FAILED(pSource->UnadviseSink(_dwCookie)))
  2589. goto Exit;
  2590. hr = S_OK;
  2591. Exit:
  2592. pSource->Release();
  2593. return hr;
  2594. }
  2595. #endif // NOFEPROCESSING