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.

1075 lines
31 KiB

  1. /****************************************************************************
  2. KORIMX.CPP : CKorIMX class implementation(TIP Main functions)
  3. History:
  4. 15-NOV-1999 CSLim Created
  5. ****************************************************************************/
  6. #include "private.h"
  7. #include "korimx.h"
  8. #include "hanja.h"
  9. #include "globals.h"
  10. #include "immxutil.h"
  11. #include "proputil.h"
  12. #include "kes.h"
  13. #include "helpers.h"
  14. #include "editcb.h"
  15. #include "timsink.h"
  16. #include "icpriv.h"
  17. #include "funcprv.h"
  18. #include "fnrecon.h"
  19. #include "dispattr.h"
  20. #include "insert.h"
  21. #include "statsink.h"
  22. #include "mes.h"
  23. #include "config.h"
  24. #include "osver.h"
  25. /*---------------------------------------------------------------------------
  26. CKorIMX::CKorIMX
  27. Ctor
  28. ---------------------------------------------------------------------------*/
  29. CKorIMX::CKorIMX()
  30. {
  31. extern void DllAddRef(void);
  32. // Init member vars
  33. m_pToolBar = NULL;
  34. m_pPadCore = NULL;
  35. m_pCurrentDim = NULL;
  36. m_ptim = NULL;
  37. m_tid = 0;
  38. m_ptimEventSink = NULL;
  39. m_pkes = NULL;
  40. m_hOwnerWnd = 0;
  41. m_fKeyFocus = fFalse;
  42. m_fPendingCleanup = fFalse;
  43. m_pFuncPrv = NULL;
  44. m_pInsertHelper = NULL;
  45. // Init Cand UI member vars
  46. m_pCandUI = NULL;
  47. m_fCandUIOpen = fFalse;
  48. // SoftKbd
  49. m_psftkbdwndes = NULL;
  50. m_pSoftKbd = NULL;
  51. m_fSoftKbdEnabled = fFalse;
  52. ZeroMemory(&m_libTLS, sizeof(m_libTLS));
  53. // Korean Kbd driver does not exist in system(Non Korean NT4, Non Korean WIN9X)
  54. m_fNoKorKbd = fFalse;
  55. m_fSoftKbdOnOffSave = fFalse;
  56. // Increase dll ref count
  57. DllAddRef();
  58. m_cRef = 1;
  59. ///////////////////////////////////////////////////////////////////////////
  60. // init CDisplayAttributeProvider
  61. //
  62. // Tip can add one or more TF_DISPLAYATTRIBUTE info here.
  63. //
  64. TF_DISPLAYATTRIBUTE dattr;
  65. StringCchCopyW(szProviderName, ARRAYSIZE(szProviderName), L"Korean Keyboard TIP");
  66. // Input string attr
  67. dattr.crText.type = TF_CT_NONE;
  68. dattr.crText.nIndex = 0;
  69. dattr.crBk.type = TF_CT_NONE;
  70. dattr.crBk.nIndex = 0;
  71. dattr.lsStyle = TF_LS_NONE;
  72. dattr.fBoldLine = fFalse;
  73. ClearAttributeColor(&dattr.crLine);
  74. dattr.bAttr = TF_ATTR_INPUT;
  75. Add(GUID_ATTR_KORIMX_INPUT, L"Korean TIP Input String", &dattr);
  76. }
  77. /*---------------------------------------------------------------------------
  78. CKorIMX::~CKorIMX
  79. Dtor
  80. ---------------------------------------------------------------------------*/
  81. CKorIMX::~CKorIMX()
  82. {
  83. extern void DllRelease(void);
  84. if (IsSoftKbdEnabled())
  85. TerminateSoftKbd();
  86. DllRelease();
  87. }
  88. /*---------------------------------------------------------------------------
  89. CKorIMX::CreateInstance
  90. Class Factory's CreateInstance
  91. ---------------------------------------------------------------------------*/
  92. /* static */
  93. HRESULT CKorIMX::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObj)
  94. {
  95. HRESULT hr;
  96. CKorIMX *pimx;
  97. TraceMsg(DM_TRACE, TEXT("CKorIMX_CreateInstance called."));
  98. *ppvObj = NULL;
  99. if (NULL != pUnkOuter)
  100. return CLASS_E_NOAGGREGATION;
  101. pimx = new CKorIMX;
  102. if (pimx == NULL)
  103. return E_OUTOFMEMORY;
  104. hr = pimx->QueryInterface(riid, ppvObj);
  105. pimx->Release();
  106. return hr;
  107. }
  108. /*---------------------------------------------------------------------------
  109. CKorIMX::QueryInterface
  110. ---------------------------------------------------------------------------*/
  111. STDAPI CKorIMX::QueryInterface(REFIID riid, void **ppvObj)
  112. {
  113. if (ppvObj == NULL)
  114. return E_POINTER;
  115. *ppvObj = NULL;
  116. if (IsEqualIID(riid, IID_IUnknown) ||
  117. IsEqualIID(riid, IID_ITfTextInputProcessor))
  118. {
  119. *ppvObj = SAFECAST(this, ITfTextInputProcessor *);
  120. }
  121. else if (IsEqualIID(riid, IID_ITfDisplayAttributeProvider))
  122. {
  123. *ppvObj = SAFECAST(this, ITfDisplayAttributeProvider *);
  124. }
  125. else if (IsEqualIID(riid, IID_ITfThreadFocusSink))
  126. {
  127. *ppvObj = SAFECAST(this, ITfThreadFocusSink *);
  128. }
  129. else if(IsEqualIID(riid, IID_ITfFnConfigure))
  130. {
  131. *ppvObj = SAFECAST(this, ITfFnConfigure *);
  132. }
  133. else if(IsEqualIID(riid, IID_ITfCleanupContextSink))
  134. {
  135. *ppvObj = SAFECAST(this, ITfCleanupContextSink *);
  136. }
  137. else if(IsEqualIID(riid, IID_ITfActiveLanguageProfileNotifySink))
  138. {
  139. *ppvObj = SAFECAST(this, ITfActiveLanguageProfileNotifySink *);
  140. }
  141. else if(IsEqualIID(riid, IID_ITfTextEditSink))
  142. {
  143. *ppvObj = SAFECAST(this, ITfTextEditSink *);
  144. }
  145. else if( IsEqualIID(riid, IID_ITfEditTransactionSink ))
  146. {
  147. *ppvObj = SAFECAST(this, ITfEditTransactionSink* );
  148. }
  149. if (*ppvObj == NULL)
  150. {
  151. return E_NOINTERFACE;
  152. }
  153. AddRef();
  154. return S_OK;
  155. }
  156. /*---------------------------------------------------------------------------
  157. CKorIMX::AddRef
  158. ---------------------------------------------------------------------------*/
  159. STDAPI_(ULONG) CKorIMX::AddRef()
  160. {
  161. m_cRef++;
  162. return m_cRef;
  163. }
  164. /*---------------------------------------------------------------------------
  165. CKorIMX::Release
  166. ---------------------------------------------------------------------------*/
  167. STDAPI_(ULONG) CKorIMX::Release()
  168. {
  169. m_cRef--;
  170. if (0 < m_cRef)
  171. return m_cRef;
  172. delete this;
  173. return 0;
  174. }
  175. /*---------------------------------------------------------------------------
  176. CKorIMX::_KeyEventCallback
  177. ITfKeyEventSink call this function back whenever keyboard event occurs
  178. or test key down and up.
  179. ---------------------------------------------------------------------------*/
  180. HRESULT CKorIMX::_KeyEventCallback(UINT uCode, ITfContext *pic,
  181. WPARAM wParam, LPARAM lParam, BOOL *pfEaten, void *pv)
  182. {
  183. CKorIMX *pimx;
  184. CEditSession2 *pes;
  185. ESSTRUCT ess;
  186. BYTE abKeyState[256];
  187. UINT uVKey = (UINT)LOWORD(wParam);
  188. HRESULT hr;
  189. Assert(pv != NULL);
  190. pimx = (CKorIMX *)pv;
  191. if (pimx == NULL)
  192. {
  193. return E_FAIL;
  194. }
  195. // !!! IME or Tip switched !!!
  196. // if ITfKeyEventSink->OnSetFocus called
  197. if (uCode == KES_CODE_FOCUS)
  198. {
  199. // wParam: fForeground
  200. if (!wParam && pic && pimx->GetIPComposition(pic))
  201. {
  202. ESStructInit(&ess, ESCB_COMPLETE);
  203. // clear display attribute only if current composition exits
  204. if (pes = new CEditSession2(pic, pimx, &ess, CKorIMX::_EditSessionCallback2))
  205. {
  206. pes->Invoke(ES2_READWRITE | ES2_SYNC, &hr);
  207. pes->Release();
  208. }
  209. if (pimx->m_pToolBar != NULL)
  210. {
  211. pimx->m_pToolBar->Update(UPDTTB_ALL);
  212. }
  213. }
  214. pimx->m_fKeyFocus = (BOOL)wParam;
  215. return S_OK;
  216. }
  217. // Set default return values
  218. *pfEaten = fFalse; // Default is not eaten
  219. hr = S_OK;
  220. if (pic == NULL)
  221. goto ExitKesCallback;
  222. // Do not process shift and ctrl key
  223. if (uVKey == VK_SHIFT || uVKey == VK_CONTROL)
  224. goto ExitKesCallback;
  225. // Off 10 #127987
  226. // NT4 workaround: NT4 IMM does not send WM_KEYDOWN::VK_HANGUL to application message queue.
  227. // Unfortunately VK_JUNJA sent as WM_SYSKEYDOWN/UP, so it's useless check here.
  228. if (IsOnNT() && !IsOnNT5())
  229. {
  230. if ((UINT)LOWORD(wParam) == VK_HANGUL /* || (UINT)LOWORD(wParam) == VK_JUNJA*/)
  231. goto AcceptThisKey;
  232. }
  233. // Ignore all Key up message
  234. if ((uCode & KES_CODE_KEYDOWN) == 0)
  235. goto ExitKesCallback;
  236. AcceptThisKey:
  237. if (GetKeyboardState(abKeyState) == fFalse)
  238. goto ExitKesCallback;
  239. // Ignore all key events while candidate UI is opening except cand keys.
  240. // Added Alt check: Bug #525842 - If Alt key pressed, always complete current interim.
  241. // This will be handled in the _IsKeyEaten function.
  242. if (pimx->IsDisabledIC(pic) && !IsAltKeyPushed(abKeyState))
  243. {
  244. if (!IsCandKey(wParam, abKeyState))
  245. *pfEaten = fTrue;
  246. goto ExitKesCallback;
  247. }
  248. // Check if we need to handle this key
  249. if (pimx->_IsKeyEaten(pic, pimx, wParam, lParam, abKeyState) == fFalse)
  250. goto ExitKesCallback;
  251. // if key is eaten
  252. // ITfKeyEventSink->TestKeyDown sets (KES_CODE_KEYDOWN | KES_CODE_TEST)
  253. // ITfKeyEventSink->TestKeyUp sets (KES_CODE_KEYUP | KES_CODE_TEST)
  254. // Response only for OnKeyDown and OnKeyUp
  255. if ((uCode & KES_CODE_TEST) == 0)
  256. {
  257. ESStructInit(&ess, ESCB_KEYSTROKE);
  258. ess.wParam = wParam;
  259. ess.lParam = lParam;
  260. ess.pv1 = abKeyState;
  261. if (pes = new CEditSession2(pic, pimx, &ess, CKorIMX::_EditSessionCallback2))
  262. {
  263. pes->Invoke(ES2_READWRITE | ES2_SYNC, &hr);
  264. pes->Release();
  265. }
  266. }
  267. if (hr == S_OK)
  268. *pfEaten = fTrue;
  269. ExitKesCallback:
  270. return hr;
  271. }
  272. /*---------------------------------------------------------------------------
  273. CKorIMX::GetIC
  274. Get the input context at the top of the stack
  275. ---------------------------------------------------------------------------*/
  276. ITfContext *CKorIMX::GetIC()
  277. {
  278. ITfContext *pic = NULL;
  279. ITfDocumentMgr *pdim = NULL;
  280. if (m_ptim == 0)
  281. {
  282. Assert(0);
  283. return NULL;
  284. }
  285. if (SUCCEEDED(m_ptim->GetFocus(&pdim)) && pdim)
  286. {
  287. pdim->GetTop(&pic);
  288. pdim->Release();
  289. }
  290. return pic;
  291. }
  292. /*---------------------------------------------------------------------------
  293. CKorIMX::SetConvMode
  294. ---------------------------------------------------------------------------*/
  295. DWORD CKorIMX::SetConvMode(ITfContext *pic, DWORD dwConvMode)
  296. {
  297. DWORD dwCurConvMode = GetConvMode(pic);
  298. if (dwConvMode == dwCurConvMode)
  299. return dwConvMode;
  300. SetCompartmentDWORD(m_tid, GetTIM(), GUID_COMPARTMENT_KORIMX_CONVMODE, dwConvMode, fFalse);
  301. // SoftKeyboard
  302. if (IsSoftKbdEnabled())
  303. {
  304. DWORD dwSoftKbdLayout, dwNewSoftKbdLayout;
  305. dwSoftKbdLayout = GetSoftKBDLayout();
  306. if (dwConvMode & TIP_HANGUL_MODE)
  307. dwNewSoftKbdLayout = m_KbdHangul.dwSoftKbdLayout;
  308. else
  309. dwNewSoftKbdLayout = m_KbdStandard.dwSoftKbdLayout;
  310. if (dwSoftKbdLayout != dwNewSoftKbdLayout)
  311. SetSoftKBDLayout(dwNewSoftKbdLayout);
  312. }
  313. // if Comp string exist, finalize it.
  314. if (GetIPComposition(pic))
  315. {
  316. CEditSession2 *pes;
  317. ESSTRUCT ess;
  318. HRESULT hr;
  319. hr = E_OUTOFMEMORY;
  320. ESStructInit(&ess, ESCB_COMPLETE);
  321. if (pes = new CEditSession2(pic, this, &ess, CKorIMX::_EditSessionCallback2))
  322. {
  323. // Word will not allow synchronous lock at this point.
  324. pes->Invoke(ES2_READWRITE | ES2_ASYNC, &hr);
  325. pes->Release();
  326. }
  327. }
  328. return dwConvMode;
  329. }
  330. /*---------------------------------------------------------------------------
  331. CKorIMX::_IsKeyEaten
  332. Return fTrue if this key need to be eaten
  333. ---------------------------------------------------------------------------*/
  334. BOOL CKorIMX::_IsKeyEaten(ITfContext *pic, CKorIMX *pimx, WPARAM wParam, LPARAM lParam, const BYTE abKeyState[256])
  335. {
  336. CHangulAutomata *pAutomata;
  337. BOOL fCompStr = fFalse;
  338. UINT uVKey = (UINT)LOWORD(wParam);
  339. CEditSession2 *pes;
  340. ESSTRUCT ess;
  341. // Hangul and Junja key
  342. if (uVKey == VK_HANGUL || uVKey == VK_JUNJA)
  343. return fTrue;
  344. // Hanja key
  345. if (uVKey == VK_HANJA)
  346. {
  347. CICPriv *picp;
  348. if ((picp = GetInputContextPriv(pic)) == NULL)
  349. {
  350. Assert(0);
  351. return fTrue;
  352. }
  353. // Do not eat VK_HANJA for AIMM 1.2 IME_HANJAMODE .
  354. if (picp->GetAIMM() && GetIPComposition(pic) == NULL)
  355. return fFalse;
  356. else
  357. return fTrue;
  358. }
  359. // if Tip is off do nothing
  360. if (IsOn(pic) == fFalse || GetConvMode(pic) == TIP_ALPHANUMERIC_MODE)
  361. return fFalse;
  362. // Should handle Backspace in interim state
  363. if (uVKey == VK_BACK)
  364. {
  365. if (GetIPComposition(pic))
  366. return fTrue;
  367. else
  368. return fFalse;
  369. }
  370. // Get Hangul Automata
  371. if ((pAutomata = GetAutomata(pic)) == NULL)
  372. return fFalse;
  373. // Alt+xx or Ctrl+xx processing. TIP should not eat.
  374. // Ctrl or Alt pushed with other key and comp str exist we should eat and complete the comp str.
  375. if (IsAltKeyPushed(abKeyState) || IsControlKeyPushed(abKeyState))
  376. {
  377. pAutomata->MakeComplete();
  378. }
  379. else
  380. {
  381. DWORD dwConvMode = GetConvMode(pic);
  382. // If Hangul mode
  383. if (dwConvMode & TIP_HANGUL_MODE)
  384. {
  385. // Start of hangul composition
  386. WORD wcCur;
  387. CIMEData ImeData;
  388. wcCur = pAutomata->GetKeyMap(uVKey, IsShiftKeyPushed(abKeyState) ? 1 : 0 );
  389. // 2beolsik Alphanumeric keys have same layout as English key
  390. // So we don't need process when user pressed Alphanumeric key under 2beolsik
  391. if ((wcCur && ImeData.GetCurrentBeolsik() != KL_2BEOLSIK) || (wcCur & H_HANGUL) )
  392. return fTrue;
  393. }
  394. // if IME_CMODE_FULLSHAPE
  395. if (dwConvMode & TIP_JUNJA_MODE)
  396. {
  397. if (CHangulAutomata::GetEnglishKeyMap(uVKey, IsShiftKeyPushed(abKeyState) ? 1 : 0))
  398. return fTrue;
  399. }
  400. }
  401. //
  402. // Skipped all key matching condition mean this is no handle key.
  403. // We just complete current composition if exist.
  404. //
  405. if (GetIPComposition(pic) != NULL)
  406. {
  407. // No need to handle this key for current Automata.
  408. // Complete composition, if exist.
  409. ESStructInit(&ess, ESCB_COMPLETE);
  410. HRESULT hr;
  411. // Complete current comp char if exist
  412. if ((pes = new CEditSession2(pic, pimx, &ess, CKorIMX::_EditSessionCallback2)) == NULL)
  413. return fFalse;
  414. pes->Invoke(ES2_READWRITE | ES2_SYNC, &hr);
  415. pes->Release();
  416. }
  417. return fFalse;
  418. }
  419. /*----------------------------------------------------------------------------
  420. Banja2Junja
  421. Convert Ascii Half shape to Full shape character
  422. ----------------------------------------------------------------------------*/
  423. /* static */
  424. WCHAR CKorIMX::Banja2Junja(WCHAR bChar)
  425. {
  426. WCHAR wcJunja;
  427. if (bChar == L' ')
  428. wcJunja = 0x3000; // FullWidth space
  429. else
  430. if (bChar == L'~')
  431. wcJunja = 0xFF5E;
  432. else
  433. if (bChar == L'\\')
  434. wcJunja = 0xFFE6; // FullWidth WON sign
  435. else
  436. wcJunja = 0xFF00 + (WORD)(bChar - (BYTE)0x20);
  437. return wcJunja;
  438. }
  439. /*---------------------------------------------------------------------------
  440. CKorIMX::_Keystroke
  441. ---------------------------------------------------------------------------*/
  442. HRESULT CKorIMX::_Keystroke(TfEditCookie ec, ITfContext *pic, WPARAM wParam, LPARAM lParam,
  443. const BYTE abKeyState[256])
  444. {
  445. ITfRange *pSelection = NULL;
  446. WORD wVKey = LOWORD(wParam) & 0x00FF;
  447. DWORD dwConvMode;
  448. HRESULT hResult = S_OK;
  449. // find the extent of the comp string
  450. if (GetSelectionSimple(ec, pic, &pSelection) != S_OK)
  451. {
  452. hResult = S_FALSE;
  453. goto Exit;
  454. }
  455. dwConvMode = GetConvMode(pic);
  456. switch (wVKey)
  457. {
  458. case VK_HANGUL:
  459. dwConvMode ^= TIP_HANGUL_MODE;
  460. SetConvMode(pic, dwConvMode);
  461. break;
  462. case VK_JUNJA:
  463. dwConvMode ^= TIP_JUNJA_MODE;
  464. SetConvMode(pic, dwConvMode);
  465. break;
  466. case VK_HANJA:
  467. if (GetIPComposition(pic))
  468. DoHanjaConversion(ec, pic, pSelection);
  469. else
  470. Reconvert(pSelection);
  471. // Update Hanja button
  472. if (m_pToolBar != NULL)
  473. {
  474. m_pToolBar->Update(UPDTTB_HJMODE);
  475. }
  476. break;
  477. default:
  478. ///////////////////////////////////////////////////////////////////////////
  479. // Run Hangul Automata
  480. if (dwConvMode & TIP_HANGUL_MODE)
  481. {
  482. HAutoMata(ec, pic, pSelection, (LPBYTE)abKeyState, wVKey);
  483. }
  484. else
  485. if (dwConvMode & TIP_JUNJA_MODE) // Junja handling
  486. {
  487. WCHAR pwchKeyCode[2];
  488. // Numeric or English key?
  489. if (pwchKeyCode[0] = CHangulAutomata::GetEnglishKeyMap(wVKey, (abKeyState[VK_SHIFT] & 0x80) ? 1:0))
  490. {
  491. if (wVKey >= 'A' && wVKey <= 'Z')
  492. {
  493. pwchKeyCode[0] = CHangulAutomata::GetEnglishKeyMap(wVKey, (abKeyState[VK_SHIFT] & 0x80) ? 1:0 ^ ((abKeyState[VK_CAPITAL] & 0x01) ? 1:0));
  494. }
  495. // Get Junja code
  496. pwchKeyCode[0] = Banja2Junja(pwchKeyCode[0]);
  497. pwchKeyCode[1] = L'\0';
  498. // Finalize a Junja char
  499. if (SUCCEEDED(SetInputString(ec, pic, pSelection, pwchKeyCode, GetLangID())))
  500. MakeResultString(ec, pic, pSelection);
  501. }
  502. }
  503. break;
  504. }
  505. Exit:
  506. if (pSelection)
  507. pSelection->Release();
  508. return hResult;
  509. }
  510. /*---------------------------------------------------------------------------
  511. CKorIMX::HAutoMata
  512. Run Hangul Automata
  513. ---------------------------------------------------------------------------*/
  514. void CKorIMX::HAutoMata(TfEditCookie ec, ITfContext *pic, ITfRange *pIRange,
  515. LPBYTE lpbKeyState, WORD wVKey)
  516. {
  517. WORD wcCur;
  518. ULONG cch;
  519. LPWSTR pwstr;
  520. CHangulAutomata *pAutomata;
  521. WCHAR pwchText[256];
  522. if ((pAutomata = GetAutomata(pic)) == NULL)
  523. return;
  524. cch = ARRAYSIZE(pwchText);
  525. pIRange->GetText(ec, 0, pwchText, ARRAYSIZE(pwchText) - 1, &cch);
  526. pwstr = pwchText;
  527. switch (wVKey)
  528. {
  529. ///////////////////////////////////////////////////////////
  530. // Back space processing
  531. case VK_BACK :
  532. if (pAutomata->BackSpace())
  533. {
  534. CIMEData ImeData;
  535. if (ImeData.GetJasoDel())
  536. {
  537. *pwstr++ = pAutomata->GetCompositionChar();
  538. *pwstr = L'\0';
  539. SetInputString(ec, pic, pIRange, pwchText, GetLangID());
  540. }
  541. else
  542. {
  543. pAutomata->InitState();
  544. *pwstr = L'\0';
  545. SetInputString(ec, pic, pIRange, pwchText, GetLangID());
  546. }
  547. // All composition deleted.
  548. if (pAutomata->GetCompositionChar() == 0)
  549. {
  550. EndIPComposition(ec, pic);
  551. // Collapse current selection to end and reset block cursor
  552. pIRange->Collapse(ec, TF_ANCHOR_END);
  553. SetSelectionSimple(ec, pic, pIRange);
  554. }
  555. }
  556. else
  557. {
  558. // BUG : impossible
  559. Assert(0);
  560. }
  561. break;
  562. default :
  563. WCHAR wchPrev = pAutomata->GetCompositionChar();
  564. switch (pAutomata->Machine(wVKey, IsShiftKeyPushed(lpbKeyState) ? 1 : 0 ) )
  565. {
  566. case HAUTO_COMPOSITION:
  567. //
  568. pwchText[0] = pAutomata->GetCompositionChar();
  569. pwchText[1] = L'\0';
  570. SetInputString(ec, pic, pIRange, pwchText, GetLangID());
  571. break;
  572. case HAUTO_COMPLETE:
  573. pwchText[0] = pAutomata->GetCompleteChar();
  574. pwchText[1] = L'\0';
  575. if (FAILED(SetInputString(ec, pic, pIRange, pwchText, GetLangID())))
  576. break;
  577. MakeResultString(ec, pic, pIRange);
  578. //
  579. pwchText[0] = pAutomata->GetCompositionChar();
  580. pwchText[1] = L'\0';
  581. SetInputString(ec, pic, pIRange, pwchText, GetLangID());
  582. break;
  583. ////////////////////////////////////////////////////////
  584. // User pressed Alphanumeric key.
  585. // When user type alphanumeric char in interim state.
  586. // ImeProcessKey should guarantee return fTrue only if
  587. // hangul key pressed or alphanumeric key(including special keys)
  588. // pressed in interim state or Fullshape mode.
  589. case HAUTO_NONHANGULKEY:
  590. wcCur = pAutomata->GetKeyMap(wVKey, IsShiftKeyPushed(lpbKeyState) ? 1 : 0 );
  591. if (GetConvMode(pic) & TIP_JUNJA_MODE)
  592. wcCur = Banja2Junja(wcCur);
  593. if (pAutomata->GetCompositionChar())
  594. {
  595. pAutomata->MakeComplete();
  596. MakeResultString(ec, pic, pIRange);
  597. }
  598. if (wcCur)
  599. {
  600. pwchText[0] = wcCur;
  601. pwchText[1] = 0;
  602. if (SUCCEEDED(SetInputString(ec, pic, pIRange, pwchText, GetLangID())))
  603. MakeResultString(ec, pic, pIRange);
  604. }
  605. break;
  606. default :
  607. Assert(0);
  608. } // switch (pInstData->pMachine->Machine(uVirKey, (lpbKeyState[VK_SHIFT] & 0x80) ? 1 : 0 ) )
  609. } // switch (uVirKey)
  610. }
  611. /*---------------------------------------------------------------------------
  612. CKorIMX::DoHanjaConversion
  613. ---------------------------------------------------------------------------*/
  614. HRESULT CKorIMX::DoHanjaConversion(TfEditCookie ec, ITfContext *pic, ITfRange *pRange)
  615. {
  616. ULONG cch;
  617. CCandidateListEx *pCandList;
  618. WCHAR pwchText[256];
  619. Assert(pic != NULL);
  620. Assert(pRange != NULL);
  621. cch = ARRAYSIZE(pwchText);
  622. pRange->GetText(ec, 0, pwchText, ARRAYSIZE(pwchText) - 1, &cch);
  623. // REVIEW: Assume composition string is one char
  624. Assert(cch == 1);
  625. pwchText[1] = 0;
  626. if ((pCandList = CreateCandidateList(pic, pRange, pwchText)) == NULL)
  627. return E_FAIL;
  628. OpenCandidateUI(ec, pic, pRange, pCandList);
  629. pCandList->Release();
  630. return S_OK;
  631. }
  632. /*---------------------------------------------------------------------------
  633. CKorIMX::Reconvert
  634. ---------------------------------------------------------------------------*/
  635. HRESULT CKorIMX::Reconvert(ITfRange *pSelection)
  636. {
  637. ITfFnReconversion *pReconv = NULL;
  638. ITfRange *pRangeReconv = NULL;
  639. BOOL fConvertable;
  640. if (FAILED(GetFunctionProvider()->GetFunction(GUID_NULL, IID_ITfFnReconversion, (IUnknown **)&pReconv)))
  641. return E_FAIL;
  642. if (pReconv->QueryRange(pSelection, &pRangeReconv, &fConvertable) != S_OK)
  643. goto Exit;
  644. if (fConvertable)
  645. pReconv->Reconvert(pRangeReconv);
  646. Exit:
  647. SafeRelease(pReconv);
  648. return S_OK;
  649. }
  650. // REVIEW
  651. /*---------------------------------------------------------------------------
  652. CKorIMX::SetInputString
  653. ---------------------------------------------------------------------------*/
  654. HRESULT CKorIMX::SetInputString(TfEditCookie ec, ITfContext *pic, ITfRange *pRange,
  655. WCHAR *psz, LANGID langid)
  656. {
  657. GUID attr;
  658. ITfComposition *pComposition;
  659. ITfRange *ppCompRange = NULL;
  660. LONG cch;
  661. // BOOL fInsertOK;
  662. cch = wcslen(psz);
  663. pComposition = GetIPComposition(pic);
  664. // If start composition
  665. if (pComposition == NULL)
  666. {
  667. // if new selection, Set overtype.
  668. Assert(m_pInsertHelper != NULL);
  669. if (m_pInsertHelper)
  670. {
  671. HRESULT hr;
  672. CHangulAutomata *pAutomata;
  673. hr = m_pInsertHelper->InsertAtSelection(ec, pic, psz, cch, &ppCompRange);
  674. if (FAILED(hr))
  675. {
  676. if ((pAutomata = GetAutomata(pic)) != NULL)
  677. pAutomata->InitState();
  678. return hr;
  679. }
  680. /* InsertOK = (pRange != NULL);*/
  681. if (ppCompRange == NULL)
  682. {
  683. Assert(0);
  684. return S_FALSE;
  685. }
  686. cch = -1; // flag to avoid a SetText call below
  687. pRange = ppCompRange;
  688. }
  689. CreateIPComposition(ec, pic, pRange);
  690. }
  691. // Set Korean input property
  692. attr = GUID_ATTR_KORIMX_INPUT;
  693. // Use MySetText instead of SetTextAndProperty
  694. // if cch == -1, set only attribute
  695. MySetText(ec, pic, pRange, psz , cch, langid, &attr);
  696. // Always call SetSelection for block cursor
  697. SetSelectionBlock(ec, pic, pRange);
  698. SafeRelease(ppCompRange);
  699. return S_OK;
  700. }
  701. // REVIEW
  702. /*---------------------------------------------------------------------------
  703. CKorIMX::MakeResultString
  704. ---------------------------------------------------------------------------*/
  705. HRESULT CKorIMX::MakeResultString(TfEditCookie ec, ITfContext *pic, ITfRange *pRange)
  706. {
  707. ITfRange *pRangeTmp;
  708. ITfProperty *pPropAttr;
  709. #if 0
  710. ITfProperty *pProp;
  711. #endif
  712. TfGuidAtom attr;
  713. // Clone Range
  714. pRange->Clone(&pRangeTmp);
  715. // Collapse current selection to end and reset block cursor
  716. pRange->Collapse(ec, TF_ANCHOR_END);
  717. SetSelectionSimple(ec, pic, pRange);
  718. #if 0
  719. // Flush IP Range
  720. FlushIPRange(ec, pic);
  721. #endif
  722. if (SUCCEEDED(pic->GetProperty(GUID_PROP_ATTRIBUTE, &pPropAttr)))
  723. {
  724. if (SUCCEEDED(GetAttrPropertyData(ec, pPropAttr, pRangeTmp, &attr)))
  725. {
  726. if (IsKorIMX_GUID_ATOM(attr))
  727. {
  728. pPropAttr->Clear(ec, pRangeTmp);
  729. }
  730. }
  731. pPropAttr->Release();
  732. #if 1
  733. EndIPComposition(ec, pic);
  734. #else
  735. // clear the composition property
  736. if (SUCCEEDED(pic->GetProperty(GUID_PROP_COMPOSING, &pProp)))
  737. {
  738. pProp->Clear(ec, pRangeTmp);
  739. pProp->Release();
  740. }
  741. #endif
  742. // clear any overtype
  743. if (m_pInsertHelper != NULL)
  744. {
  745. m_pInsertHelper->ReleaseBlobs(ec, pic, NULL);
  746. }
  747. }
  748. pRangeTmp->Release();
  749. return S_OK;
  750. }
  751. #if 0
  752. /*---------------------------------------------------------------------------
  753. CKorIMX::_MultiRangeConversion
  754. ---------------------------------------------------------------------------*/
  755. HRESULT CKorIMX::_MultiRangeConversion(TfEditCookie ec, UINT_PTR u, ITfContext *pic, ITfRange *pRange)
  756. {
  757. IEnumTfRanges *pEnumTrack = NULL;
  758. ITfReadOnlyProperty *pProp = NULL;
  759. ITfRange *pPropRange = NULL;
  760. HRESULT hr = E_FAIL;
  761. if (FAILED(EnumTrackTextAndFocus(ec, pic, pRange, &pProp, &pEnumTrack)))
  762. goto Exit;
  763. while(pEnumTrack->Next(1, &pPropRange, 0) == S_OK)
  764. {
  765. ITfRange *pRangeTmp = NULL;
  766. if (!IsOwnerAndFocus(ec, CLSID_KorIMX, pProp, pPropRange))
  767. goto Next;
  768. if (FAILED(pPropRange->Clone(&pRangeTmp)))
  769. goto Next;
  770. switch (u)
  771. {
  772. case ESCB_COMPLETE:
  773. MakeResultString(ec, pic, pRangeTmp);
  774. break;
  775. }
  776. SafeRelease(pRangeTmp);
  777. Next:
  778. SafeRelease(pPropRange);
  779. }
  780. Exit:
  781. SafeRelease(pEnumTrack);
  782. SafeRelease(pProp);
  783. return hr;
  784. }
  785. #endif
  786. /*---------------------------------------------------------------------------
  787. CKorIMX::_OwnerWndProc
  788. ---------------------------------------------------------------------------*/
  789. LRESULT CALLBACK CKorIMX::_OwnerWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  790. {
  791. #if 0
  792. switch (uMsg)
  793. {
  794. case WM_CREATE:
  795. SetThis(hWnd, lParam);
  796. return 0;
  797. case (WM_USER+WM_COMMAND): // local commands
  798. return GetThis(hWnd)->OnCommand((UINT)wParam, lParam);
  799. case WM_DRAWITEM:
  800. {
  801. CKorIMX* pThis = GetThis(hWnd);
  802. if( pThis )
  803. return pThis->OnDrawItem( wParam, lParam );
  804. break;
  805. }
  806. case WM_MEASUREITEM:
  807. {
  808. CKBDTip* pThis = GetThis(hWnd);
  809. if( pThis )
  810. return pThis->OnMeasureItem( wParam, lParam );
  811. break;
  812. }
  813. }
  814. #endif
  815. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  816. }
  817. //+---------------------------------------------------------------------------
  818. //
  819. // GetDisplayName
  820. //
  821. //----------------------------------------------------------------------------
  822. STDAPI CKorIMX::GetDisplayName(BSTR *pbstrName)
  823. {
  824. *pbstrName = SysAllocString(L"Korean Keyboard TIP Configure");
  825. return S_OK;
  826. }
  827. //+---------------------------------------------------------------------------
  828. //
  829. // Show
  830. //
  831. //----------------------------------------------------------------------------
  832. STDAPI CKorIMX::Show(HWND hwnd, LANGID langid, REFGUID rguidProfile)
  833. {
  834. if (ConfigDLG(hwnd))
  835. return S_OK;
  836. else
  837. return E_FAIL;
  838. }
  839. /*---------------------------------------------------------------------------
  840. CKorIMX::GetAIMM
  841. ---------------------------------------------------------------------------*/
  842. BOOL CKorIMX::GetAIMM(ITfContext *pic)
  843. {
  844. CICPriv* picp;
  845. if ((picp = GetInputContextPriv(pic)) == NULL)
  846. {
  847. Assert(0);
  848. return fFalse;
  849. }
  850. // AIMM?
  851. return picp->GetAIMM();
  852. }
  853. /*---------------------------------------------------------------------------
  854. CKorIMX::MySetText
  855. ---------------------------------------------------------------------------*/
  856. BOOL CKorIMX::MySetText(TfEditCookie ec, ITfContext *pic, ITfRange *pRange,
  857. const WCHAR *psz, LONG cchText, LANGID langid, GUID *pattr)
  858. {
  859. // bugbug: sometimes we want to set TFST_CORRECTION
  860. if (cchText != -1) // sometimes we just want to set a property value
  861. pRange->SetText(ec, 0, psz, cchText);
  862. if (cchText != 0)
  863. {
  864. HRESULT hr;
  865. ITfProperty *pProp = NULL;
  866. // set langid
  867. if (SUCCEEDED(hr = pic->GetProperty(GUID_PROP_LANGID, &pProp)))
  868. {
  869. SetLangIdPropertyData(ec, pProp, pRange, langid);
  870. pProp->Release();
  871. }
  872. if (pattr)
  873. {
  874. // set attr
  875. if (SUCCEEDED(hr = pic->GetProperty(GUID_PROP_ATTRIBUTE, &pProp)))
  876. {
  877. hr = SetAttrPropertyData(&m_libTLS, ec, pProp, pRange, *pattr);
  878. pProp->Release();
  879. }
  880. }
  881. }
  882. return fTrue;
  883. }