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.

869 lines
30 KiB

  1. /****************************************************************************
  2. CANDUI.CPP
  3. Owner: cslim
  4. Copyright (c) 1997-1999 Microsoft Corporation
  5. Candidate window UI functions
  6. History:
  7. 14-JUL-1999 cslim Copied from IME98 source tree
  8. *****************************************************************************/
  9. #include "precomp.h"
  10. #include "debug.h"
  11. #include "ui.h"
  12. #include "lexheader.h"
  13. #include "names.h"
  14. #include "escape.h"
  15. #include "imedefs.h"
  16. #include "hanja.h"
  17. #include "winex.h"
  18. ///////////////////////////////////////////////////////////////////////////////
  19. // Private data
  20. // =====-- START OF SHARED DATA --=====
  21. #pragma data_seg(".MSIMESHR")
  22. PRIVATE RECT rcCandCli = { 0, 0, 319, 29 },
  23. rcLArrow = { 15, 4, 27, 25 }, rcRArrow = { 292, 4, 304, 25 },
  24. s_rcCandBtn[CAND_PAGE_SIZE] = {
  25. { 30, 4, 57, 25 }, { 59, 4, 86, 25 },
  26. { 88, 4, 115, 25 }, { 117, 4, 144, 25 },
  27. { 146, 4, 173, 25 }, { 175, 4, 202, 25 },
  28. { 204, 4, 231, 25 }, { 233, 4, 260, 25 },
  29. { 262, 4, 289, 25 } };
  30. #pragma data_seg()
  31. // =====-- END OF SHARED DATA --=====
  32. ///////////////////////////////////////////////////////////////////////////////
  33. // Private functions
  34. PRIVATE VOID PASCAL PaintCandWindow(HWND hCandWnd, HDC hDC);
  35. PRIVATE BOOL PASCAL CandOnSetCursor(HWND hCandWnd, WORD Message);
  36. PRIVATE VOID PASCAL AdjustCandBoundry(LPPOINT lpptCandWnd);
  37. PRIVATE VOID PASCAL AdjustCandRectBoundry(PCIMECtx pImeCtx, LPPOINT lpptCaret);
  38. #ifdef NOTUSED
  39. PRIVATE VOID NotifyTooltip( HWND hCandWnd, UINT message, WPARAM wParam, LPARAM lParam )
  40. {
  41. HGLOBAL hUIPrivate;
  42. LPUIPRIV lpUIPrivate;
  43. HWND hUIWnd;
  44. MSG msg;
  45. POINT ptCur;
  46. hUIWnd = GetWindow(hCandWnd, GW_OWNER);
  47. hUIPrivate = GethUIPrivateFromHwnd(hUIWnd);
  48. if (!hUIPrivate)
  49. return;
  50. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  51. if (!lpUIPrivate) // can not draw candidate window
  52. return;
  53. ZeroMemory(&msg, sizeof(MSG));
  54. msg.hwnd = hCandWnd; msg.message = message;
  55. msg.wParam = 0; //msg.lParam = 0x00050023L;
  56. if (message == WM_SETCURSOR)
  57. {
  58. GetCursorPos(&ptCur);
  59. ScreenToClient(hCandWnd, &ptCur);
  60. msg.lParam = (ptCur.y << 16) | ptCur.x;
  61. }
  62. else
  63. {
  64. msg.message = message;
  65. msg.wParam = wParam;
  66. msg.lParam = lParam;
  67. }
  68. Dbg(DBGID_Cand, TEXT("CandOnSetCursor(): WM_MOUSEMOVE - msg.lParam= 0x%08lX"), msg.lParam),
  69. OurSendMessage(lpUIPrivate->hCandTTWnd, TTM_RELAYEVENT, 0, (LPARAM) (LPMSG) &msg);
  70. GlobalUnlock(hUIPrivate);
  71. }
  72. #endif
  73. ///////////////////////////////////////////////////////////////////////////////
  74. LRESULT CALLBACK CandWndProc(HWND hCandWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  75. {
  76. Dbg(DBGID_UI, TEXT("CandWndProc():uMessage = 0x%08lX, wParam = 0x%04X, lParam = 0x%08lX"), uMessage, wParam, lParam);
  77. switch (uMessage)
  78. {
  79. case WM_IME_CHAR : case WM_IME_COMPOSITIONFULL :
  80. case WM_IME_COMPOSITION : case WM_IME_CONTROL :
  81. case WM_IME_SELECT :
  82. case WM_IME_SETCONTEXT : case WM_IME_STARTCOMPOSITION :
  83. case WM_IME_ENDCOMPOSITION :
  84. return 0;
  85. case WM_SETCURSOR:
  86. CandOnSetCursor( (HWND) wParam, HIWORD(lParam) );
  87. return 1;
  88. case WM_PAINT:
  89. {
  90. HDC hDC;
  91. PAINTSTRUCT ps;
  92. hDC = BeginPaint(hCandWnd, &ps);
  93. PaintCandWindow(hCandWnd, hDC);
  94. EndPaint(hCandWnd, &ps);
  95. }
  96. break;
  97. default :
  98. return DefWindowProc(hCandWnd, uMessage, wParam, lParam);
  99. }
  100. return (0L);
  101. }
  102. VOID PASCAL OpenCand(HWND hUIWnd)
  103. {
  104. HGLOBAL hUIPrivate;
  105. LPUIPRIV lpUIPrivate;
  106. HIMC hIMC;
  107. PCIMECtx pImeCtx;
  108. POINT ptWnd, ptClientWnd;
  109. CIMEData ImeData;
  110. #if 1 // MultiMonitor
  111. RECT rcWorkArea;
  112. #endif
  113. Dbg(DBGID_Cand, TEXT("OpenCand():"));
  114. hUIPrivate = GethUIPrivateFromHwnd(hUIWnd);
  115. if (!hUIPrivate) // can not draw candidate window
  116. {
  117. DbgAssert(0);
  118. return;
  119. }
  120. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  121. if (!lpUIPrivate) // can not draw candidate window
  122. return;
  123. // Check WM_IME_SETCONTEXT lParam
  124. if ((lpUIPrivate->uiShowParam & ISC_SHOWUICANDIDATEWINDOW)==0)
  125. {
  126. Dbg(DBGID_Cand, TEXT("!!! No ISC_SHOWUICANDIDATEWINDOW bit exit OpenCand()"));
  127. goto OpenCandUnlockUIPriv;
  128. }
  129. hIMC = GethImcFromHwnd(hUIWnd);
  130. if ((pImeCtx = GetIMECtx(hIMC)) == NULL)
  131. {
  132. DbgAssert(0);
  133. goto OpenCandUnlockUIPriv;
  134. }
  135. //if (!(fdwImeMsg & MSG_ALREADY_OPEN))
  136. // {
  137. // Sometime the application call ImmNotifyIME to cancel the
  138. // composition before it process IMN_OPENCANDIDATE.
  139. // We should avoid to process this kind of IMN_OPENCANDIDATE.
  140. // goto OpenCandUnlockIMC;
  141. // }
  142. if (pImeCtx->GetCompBufLen() == 0)
  143. {
  144. DbgAssert(0);
  145. goto OpenCandUnlockUIPriv;
  146. }
  147. if (pImeCtx->GetCandidateFormIndex(0) == 0)
  148. {
  149. //ptWnd = lpIMC->cfCandForm[0].ptCurrentPos;
  150. pImeCtx->GetCandidateFormPos(&ptWnd, 0);
  151. ClientToScreen(pImeCtx->GetAppWnd(), &ptWnd);
  152. if (pImeCtx->GetCandidateFormStyle(0) & CFS_FORCE_POSITION)
  153. {
  154. Dbg(DBGID_Cand, TEXT("OpenCand(): CFS_FORCE_POSITION"));
  155. }
  156. else
  157. if (pImeCtx->GetCandidateFormStyle(0) == CFS_EXCLUDE)
  158. {
  159. //RECT rcCand;
  160. Dbg(DBGID_Cand, TEXT("OpenCand(): CFS_EXCLUDE"));
  161. //if (lpUIPrivate->hCandWnd) {
  162. // GetWindowRect(lpUIPrivate->hCandWnd, &rcCand);
  163. //} else {
  164. // *(LPPOINT)&rcCand = ptWnd;
  165. //}
  166. AdjustCandRectBoundry(pImeCtx, &ptWnd);
  167. }
  168. else
  169. if (pImeCtx->GetCandidateFormStyle(0) == CFS_CANDIDATEPOS)
  170. {
  171. Dbg(DBGID_Cand, TEXT("OpenCand(): CFS_CANDIDATEPOS"));
  172. AdjustCandBoundry(&ptWnd);
  173. }
  174. else
  175. {
  176. goto OpenCandDefault;
  177. }
  178. }
  179. else // if (lpIMC->cfCandForm[0].dwIndex != 0)
  180. {
  181. OpenCandDefault:
  182. Dbg(DBGID_Cand, TEXT("OpenCand(): OpenCandDefault"));
  183. /*
  184. if (lpUIPrivate->nShowCompCmd != SW_HIDE) {
  185. ptWnd.x = ptWnd.y = 0;
  186. ClientToScreen(lpUIPrivate->hCompWnd, &ptWnd);
  187. ptWnd.x -= lpImeL->cxCompBorder;
  188. ptWnd.y -= lpImeL->cyCompBorder;
  189. } else {
  190. POINT ptNew;
  191. ptWnd = lpIMC->cfCompForm.ptCurrentPos;
  192. ClientToScreen(lpIMC->hWnd, &ptWnd);
  193. ptWnd.x -= lpImeL->cxCompBorder;
  194. ptWnd.y -= lpImeL->cyCompBorder;
  195. ptNew = ptWnd;
  196. // try to simulate the position of composition window
  197. AdjustCompPosition(lpIMC, &ptWnd, &ptNew);
  198. }
  199. */
  200. // CalcCandPos(lpIMC, &ptWnd);
  201. #if 1 // MultiMonitor
  202. ImeMonitorWorkAreaFromWindow(pImeCtx->GetAppWnd(), &rcWorkArea);
  203. ptWnd.x = rcWorkArea.right - ImeData->xCandWi;
  204. ptWnd.y = rcWorkArea.bottom - ImeData->yCandHi;
  205. #else
  206. ptWnd.x = ImeData->rcWorkArea.right - ImeData->xCandWi;
  207. ptWnd.y = ImeData->rcWorkArea.bottom - ImeData->yCandHi;
  208. #endif
  209. pImeCtx->SetCandidateFormStyle(CFS_CANDIDATEPOS);
  210. ptClientWnd = ptWnd;
  211. ScreenToClient(pImeCtx->GetAppWnd(), &ptClientWnd);
  212. pImeCtx->SetCandidateFormPos(ptClientWnd);
  213. }
  214. if (lpUIPrivate->hCandWnd)
  215. {
  216. Dbg(DBGID_Cand, TEXT("OpenCand - SetWindowPos"), ptWnd.x, ptWnd.y);
  217. SetWindowPos(lpUIPrivate->hCandWnd, NULL,
  218. ptWnd.x, ptWnd.y,
  219. 0, 0, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER);
  220. }
  221. else
  222. {
  223. Dbg(DBGID_Cand, TEXT("OpenCand - CreateWindowEx x=%d, y=%d"), ptWnd.x, ptWnd.y);
  224. // Create Candidate window
  225. lpUIPrivate->hCandWnd = CreateWindowEx(0,
  226. szCandClassName, NULL,
  227. WS_POPUP|WS_DISABLED,
  228. ptWnd.x, ptWnd.y,
  229. ImeData->xCandWi, ImeData->yCandHi,
  230. hUIWnd,
  231. (HMENU)NULL,
  232. vpInstData->hInst,
  233. NULL);
  234. if (lpUIPrivate->hCandWnd == NULL)
  235. goto OpenCandUnlockUIPriv;
  236. // Create candidate TT
  237. if (IsWinNT())
  238. lpUIPrivate->hCandTTWnd = CreateWindowW(
  239. wszTooltipClassName,
  240. NULL,
  241. TTS_ALWAYSTIP|WS_DISABLED,
  242. CW_USEDEFAULT, CW_USEDEFAULT,
  243. CW_USEDEFAULT, CW_USEDEFAULT,
  244. lpUIPrivate->hCandWnd,
  245. (HMENU) NULL,
  246. vpInstData->hInst,
  247. NULL);
  248. else
  249. lpUIPrivate->hCandTTWnd = CreateWindow(
  250. szTooltipClassName,
  251. NULL,
  252. TTS_ALWAYSTIP|WS_DISABLED,
  253. CW_USEDEFAULT, CW_USEDEFAULT,
  254. CW_USEDEFAULT, CW_USEDEFAULT,
  255. lpUIPrivate->hCandWnd,
  256. (HMENU) NULL,
  257. vpInstData->hInst,
  258. NULL);
  259. DbgAssert(lpUIPrivate->hCandTTWnd != 0);
  260. if (lpUIPrivate->hCandTTWnd)
  261. {
  262. TOOLINFO ti;
  263. ZeroMemory(&ti, sizeof(TOOLINFO));
  264. ti.cbSize = sizeof(TOOLINFO);
  265. ti.uFlags = 0;
  266. ti.hwnd = lpUIPrivate->hCandWnd;
  267. ti.hinst = vpInstData->hInst;
  268. // Reset Tooltip data
  269. for (INT i=0; i<CAND_PAGE_SIZE; i++)
  270. {
  271. ti.uId = i;
  272. ti.lpszText = "";
  273. ti.rect = s_rcCandBtn[i];
  274. OurSendMessage(lpUIPrivate->hCandTTWnd, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
  275. }
  276. }
  277. }
  278. ShowCand(hUIWnd, SW_SHOWNOACTIVATE);
  279. OpenCandUnlockUIPriv:
  280. GlobalUnlock(hUIPrivate);
  281. return;
  282. }
  283. ///////////////////////////////////////////////////////////////////////////////
  284. //
  285. VOID PASCAL AdjustCandBoundry(LPPOINT lpptCandWnd)
  286. {
  287. CIMEData ImeData;
  288. #if 1 // MultiMonitor
  289. RECT rcWorkArea;
  290. RECT rcCandWnd;
  291. #endif
  292. Dbg(DBGID_UI, TEXT("AdjustCandBoundry():"));
  293. #if 1 // MultiMonitor
  294. *(LPPOINT)&rcCandWnd = *(LPPOINT)lpptCandWnd;
  295. rcCandWnd.right = rcCandWnd.left + ImeData->xCandWi;
  296. rcCandWnd.bottom = rcCandWnd.top + ImeData->yCandHi;
  297. ImeMonitorWorkAreaFromRect(&rcCandWnd, &rcWorkArea);
  298. if (lpptCandWnd->x < rcWorkArea.left) {
  299. lpptCandWnd->x = rcWorkArea.left;
  300. } else if (lpptCandWnd->x + ImeData->xCandWi > rcWorkArea.right) {
  301. lpptCandWnd->x = rcWorkArea.right - ImeData->xCandWi;
  302. } else {
  303. }
  304. if (lpptCandWnd->y < rcWorkArea.top) {
  305. lpptCandWnd->y = rcWorkArea.top;
  306. } else if (lpptCandWnd->y + ImeData->yCandHi > rcWorkArea.bottom) {
  307. lpptCandWnd->y = rcWorkArea.bottom - ImeData->yCandHi;
  308. } else {
  309. }
  310. #else
  311. if (lpptCandWnd->x < ImeData->rcWorkArea.left) {
  312. lpptCandWnd->x = ImeData->rcWorkArea.left;
  313. } else if (lpptCandWnd->x + ImeData->xCandWi > ImeData->rcWorkArea.right) {
  314. lpptCandWnd->x = ImeData->rcWorkArea.right - ImeData->xCandWi;
  315. } else {
  316. }
  317. if (lpptCandWnd->y < ImeData->rcWorkArea.top) {
  318. lpptCandWnd->y = ImeData->rcWorkArea.top;
  319. } else if (lpptCandWnd->y + ImeData->yCandHi > ImeData->rcWorkArea.bottom) {
  320. lpptCandWnd->y = ImeData->rcWorkArea.bottom - ImeData->yCandHi;
  321. } else {
  322. }
  323. #endif
  324. }
  325. VOID PASCAL AdjustCandRectBoundry(PCIMECtx pImeCtx, LPPOINT lpptCaret) // the caret position. Screen coord
  326. {
  327. RECT rcExclude, rcCandRect, rcInterSect;
  328. POINT ptCurrentPos;
  329. CIMEData ImeData;
  330. // translate from client coordinate to screen coordinate
  331. // rcExclude = lpIMC->cfCandForm[0].rcArea;
  332. pImeCtx->GetCandidateForm(&rcExclude);
  333. pImeCtx->GetCandidateFormPos(&ptCurrentPos);
  334. rcExclude.left += lpptCaret->x - ptCurrentPos.x;
  335. rcExclude.right += lpptCaret->x - ptCurrentPos.x;
  336. rcExclude.top += lpptCaret->y - ptCurrentPos.y;
  337. rcExclude.bottom += lpptCaret->y - ptCurrentPos.y;
  338. AdjustCandBoundry(lpptCaret);
  339. *(LPPOINT)&rcCandRect = *lpptCaret;
  340. rcCandRect.right = rcCandRect.left + ImeData->xCandWi;
  341. rcCandRect.bottom = rcCandRect.top + ImeData->yCandHi;
  342. if (IntersectRect(&rcInterSect, &rcCandRect, &rcExclude))
  343. {
  344. #if 1 // MultiMonitor
  345. RECT rcWorkArea;
  346. ImeMonitorWorkAreaFromWindow(pImeCtx->GetAppWnd(), &rcWorkArea);
  347. // Adjust y-axis only
  348. if ( (rcExclude.bottom + ImeData->yCandHi) < rcWorkArea.bottom )
  349. lpptCaret->y = rcExclude.bottom;
  350. else
  351. lpptCaret->y = rcExclude.top - ImeData->yCandHi;
  352. #else
  353. // Adjust y-axis only
  354. if ( (rcExclude.bottom + ImeData->yCandHi) < ImeData->rcWorkArea.bottom )
  355. lpptCaret->y = rcExclude.bottom;
  356. else
  357. lpptCaret->y = rcExclude.top - ImeData->yCandHi;
  358. #endif
  359. }
  360. }
  361. BOOL fSetCandWindowPos(HWND hCandWnd)
  362. {
  363. HWND hUIWnd;
  364. HIMC hIMC;
  365. PCIMECtx pImeCtx;
  366. POINT ptWnd;
  367. CIMEData ImeData;
  368. if (hCandWnd == 0)
  369. {
  370. DbgAssert(0);
  371. return fTrue;
  372. }
  373. hUIWnd = GetWindow(hCandWnd, GW_OWNER);
  374. hIMC = GethImcFromHwnd(hUIWnd);
  375. //if (!hIMC)
  376. // {
  377. // DbgAssert(0);
  378. // return fFalse;
  379. // }
  380. //lpIMC = (LPINPUTCONTEXT)OurImmLockIMC(hIMC);
  381. //if (!lpIMC)
  382. // {
  383. // DbgAssert(0);
  384. // return fFalse;
  385. // }
  386. if ((pImeCtx = GetIMECtx(hIMC)) == NULL)
  387. return fFalse;
  388. //ptWnd = lpIMC->cfCandForm[0].ptCurrentPos;
  389. pImeCtx->GetCandidateFormPos(&ptWnd);
  390. ClientToScreen(pImeCtx->GetAppWnd(), &ptWnd);
  391. if (pImeCtx->GetCandidateFormStyle() & CFS_FORCE_POSITION)
  392. {
  393. }
  394. else
  395. if (pImeCtx->GetCandidateFormStyle() == CFS_EXCLUDE)
  396. {
  397. RECT rcCand;
  398. GetWindowRect(hCandWnd, &rcCand);
  399. AdjustCandRectBoundry(pImeCtx, &ptWnd);
  400. if (ptWnd.x == rcCand.left && ptWnd.y == rcCand.right)
  401. return (0L);
  402. }
  403. else
  404. if (pImeCtx->GetCandidateFormStyle() == CFS_CANDIDATEPOS)
  405. {
  406. AdjustCandBoundry(&ptWnd);
  407. }
  408. else
  409. if (pImeCtx->GetCandidateFormStyle() == CFS_DEFAULT)
  410. {
  411. #if 1 // MultiMonitor
  412. RECT rcWorkArea;
  413. ImeMonitorWorkAreaFromWindow(pImeCtx->GetAppWnd(), &rcWorkArea);
  414. ptWnd.x = rcWorkArea.right - ImeData->xCandWi;
  415. ptWnd.y = rcWorkArea.bottom - ImeData->yCandHi;
  416. #else
  417. ptWnd.x = ImeData->rcWorkArea.right - ImeData->xCandWi;
  418. ptWnd.y = ImeData->rcWorkArea.bottom - ImeData->yCandHi;
  419. #endif
  420. }
  421. SetWindowPos(hCandWnd, NULL, ptWnd.x, ptWnd.y, 0, 0, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER);
  422. return (0L);
  423. }
  424. // Show the candidate window
  425. VOID ShowCand(HWND hUIWnd, INT nShowCandCmd)
  426. {
  427. HGLOBAL hUIPrivate;
  428. LPUIPRIV lpUIPrivate;
  429. Dbg(DBGID_Cand, TEXT("ShowCand(): nShowCandCmd = %d"), nShowCandCmd);
  430. hUIPrivate = GethUIPrivateFromHwnd(hUIWnd);
  431. if (!hUIPrivate) // can not darw candidate window
  432. return;
  433. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  434. if (!lpUIPrivate) // can not draw candidate window
  435. return;
  436. if (nShowCandCmd == SW_SHOWNOACTIVATE)
  437. nShowCandCmd = vfWndOpen[CAND_WINDOW] ? SW_SHOWNOACTIVATE : SW_HIDE;
  438. if (lpUIPrivate->nShowCandCmd == nShowCandCmd)
  439. goto SwCandNoChange;
  440. if (lpUIPrivate->hCandWnd)
  441. {
  442. ShowWindow(lpUIPrivate->hCandWnd, nShowCandCmd);
  443. lpUIPrivate->nShowCandCmd = nShowCandCmd;
  444. }
  445. else
  446. lpUIPrivate->nShowCandCmd = SW_HIDE;
  447. SwCandNoChange:
  448. GlobalUnlock(hUIPrivate);
  449. return;
  450. }
  451. BOOL PASCAL CandOnSetCursor(HWND hCandWnd, WORD message)
  452. {
  453. INT iLoop;
  454. POINT ptPos;
  455. SetCursor(LoadCursor(vpInstData->hInst, MAKEINTRESOURCE(IDC_IME_HAND)));
  456. switch (message)
  457. {
  458. case WM_LBUTTONDOWN:
  459. GetCursorPos(&ptPos);
  460. ScreenToClient(hCandWnd, &ptPos);
  461. if (PtInRect((LPRECT)&rcCandCli, ptPos))
  462. {
  463. if (!PtInRect((LPRECT)&rcLArrow, ptPos)
  464. && !PtInRect((LPRECT)&rcRArrow, ptPos)
  465. && !PtInRect((LPRECT)&s_rcCandBtn[0], ptPos)
  466. && !PtInRect((LPRECT)&s_rcCandBtn[1], ptPos)
  467. && !PtInRect((LPRECT)&s_rcCandBtn[2], ptPos)
  468. && !PtInRect((LPRECT)&s_rcCandBtn[3], ptPos)
  469. && !PtInRect((LPRECT)&s_rcCandBtn[4], ptPos)
  470. && !PtInRect((LPRECT)&s_rcCandBtn[5], ptPos)
  471. && !PtInRect((LPRECT)&s_rcCandBtn[6], ptPos)
  472. && !PtInRect((LPRECT)&s_rcCandBtn[7], ptPos)
  473. && !PtInRect((LPRECT)&s_rcCandBtn[8], ptPos))
  474. MessageBeep(MB_ICONEXCLAMATION);
  475. }
  476. break;
  477. case WM_LBUTTONUP:
  478. GetCursorPos(&ptPos);
  479. ScreenToClient(hCandWnd, &ptPos);
  480. if (PtInRect((LPRECT)&rcLArrow, ptPos))
  481. {
  482. keybd_event(VK_LEFT, 0, KEYEVENTF_EXTENDEDKEY, 0);
  483. keybd_event(VK_LEFT, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  484. }
  485. else if (PtInRect((LPRECT)&rcRArrow, ptPos))
  486. {
  487. keybd_event(VK_RIGHT, 0, KEYEVENTF_EXTENDEDKEY, 0);
  488. keybd_event(VK_RIGHT, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  489. }
  490. else
  491. {
  492. for (iLoop = 0; iLoop < CAND_PAGE_SIZE; iLoop++)
  493. if (PtInRect((LPRECT)&s_rcCandBtn[iLoop], ptPos))
  494. {
  495. keybd_event((BYTE)(iLoop + '1'), 0, 0, 0);
  496. keybd_event((BYTE)(iLoop + '1'), 0, KEYEVENTF_KEYUP, 0);
  497. break;
  498. }
  499. }
  500. break;
  501. case WM_MOUSEMOVE:
  502. //case WM_LBUTTONDOWN:
  503. //case WM_LBUTTONUP:
  504. {
  505. HGLOBAL hUIPrivate;
  506. LPUIPRIV lpUIPrivate;
  507. HWND hUIWnd;
  508. MSG msg;
  509. POINT ptCur;
  510. hUIWnd = GetWindow(hCandWnd, GW_OWNER);
  511. hUIPrivate = GethUIPrivateFromHwnd(hUIWnd);
  512. if (!hUIPrivate) {
  513. break;
  514. }
  515. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  516. if (!lpUIPrivate) { // can not draw candidate window
  517. break;
  518. }
  519. ZeroMemory(&msg, sizeof(MSG));
  520. msg.message = message;
  521. msg.hwnd = hCandWnd;
  522. msg.wParam = 0; //msg.lParam = 0x00050023L;
  523. GetCursorPos(&ptCur);
  524. ScreenToClient(hCandWnd, &ptCur);
  525. msg.lParam = MAKELONG(ptCur.x, ptCur.y);
  526. Dbg(DBGID_Cand|DBGID_UI, TEXT("CandOnSetCursor(): WM_MOUSEMOVE - msg.lParam= 0x%08lX"), msg.lParam),
  527. OurSendMessage(lpUIPrivate->hCandTTWnd, TTM_RELAYEVENT, 0, (LPARAM) (LPMSG) &msg);
  528. GlobalUnlock(hUIPrivate);
  529. }
  530. break;
  531. }
  532. return fTrue;
  533. }
  534. VOID PASCAL PaintCandWindow(HWND hCandWnd, HDC hDC)
  535. {
  536. HWND hUIWnd;
  537. HIMC hIMC;
  538. PCIMECtx pImeCtx;
  539. LPCANDIDATEINFO lpCandInfo;
  540. LPCANDIDATELIST lpCandList;
  541. // LPSTR lpCandStr;
  542. HFONT hFontFix, hOldFont;
  543. DWORD iLoop, iStart;
  544. HBITMAP hBMCand, hBMCandNum, hBMCandArr1, hBMCandArr2;
  545. INT iSaveBkMode;
  546. TOOLINFO ti;
  547. HGLOBAL hUIPrivate;
  548. LPUIPRIV lpUIPrivate;
  549. Dbg(DBGID_UI, TEXT("PaintCandWindow"));
  550. hUIWnd = GetWindow(hCandWnd, GW_OWNER);
  551. hIMC = GethImcFromHwnd(hUIWnd);
  552. hUIPrivate = GethUIPrivateFromHwnd(hUIWnd);
  553. if (!hUIPrivate)
  554. {
  555. DbgAssert(0);
  556. return;
  557. }
  558. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  559. if (!lpUIPrivate)
  560. return;
  561. if ((pImeCtx = GetIMECtx(hIMC)) == NULL)
  562. {
  563. DbgAssert(0);
  564. goto PaintCandWindowExit;
  565. }
  566. lpCandInfo = pImeCtx->GetPCandInfo();
  567. if (lpCandInfo == NULL)
  568. {
  569. DbgAssert(0);
  570. goto PaintCandWindowExit;
  571. }
  572. lpCandList = (LPCANDIDATELIST)((LPBYTE)lpCandInfo + sizeof(CANDIDATEINFO));
  573. Dbg(DBGID_UI, TEXT("PaintCandWindow - dwCount = %d"), lpCandList->dwCount);
  574. if (lpCandList->dwCount)
  575. {
  576. if (IsWinNT())
  577. hFontFix = CreateFontW(
  578. -16,0,0,0,
  579. 0,0,0,0,
  580. HANGUL_CHARSET,
  581. OUT_DEFAULT_PRECIS,
  582. CLIP_DEFAULT_PRECIS,
  583. DEFAULT_QUALITY,
  584. FIXED_PITCH,
  585. wzIMECompFont);
  586. else
  587. hFontFix = CreateFontA(
  588. -16,0,0,0,
  589. 0,0,0,0,
  590. HANGUL_CHARSET,
  591. OUT_DEFAULT_PRECIS,
  592. CLIP_DEFAULT_PRECIS,
  593. DEFAULT_QUALITY,
  594. FIXED_PITCH,
  595. szIMECompFont);
  596. hOldFont = (HFONT)SelectObject(hDC, hFontFix);
  597. // Load bitmaps
  598. hBMCand = (HBITMAP)OurLoadImage(MAKEINTRESOURCE(IDB_CAND_WIN),
  599. IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADMAP3DCOLORS );
  600. hBMCandNum = (HBITMAP)OurLoadImage(MAKEINTRESOURCE(IDB_CAND_NUM),
  601. IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADMAP3DCOLORS );
  602. hBMCandArr1 = (HBITMAP)OurLoadImage(MAKEINTRESOURCE(IDB_CAND_ARRY1),
  603. IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADMAP3DCOLORS );
  604. hBMCandArr2 = (HBITMAP)OurLoadImage(MAKEINTRESOURCE(IDB_CAND_ARRY2),
  605. IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADMAP3DCOLORS );
  606. DrawBitmap(hDC, 0, 0, hBMCand);
  607. iSaveBkMode = SetBkMode(hDC, TRANSPARENT);
  608. iStart = (lpCandList->dwSelection / lpCandList->dwPageSize) * lpCandList->dwPageSize;
  609. ZeroMemory(&ti, sizeof(TOOLINFO));
  610. ti.cbSize = sizeof(TOOLINFO);
  611. ti.uFlags = 0;
  612. ti.hwnd = hCandWnd;
  613. ti.hinst = vpInstData->hInst;
  614. // Paint current page 9 candidate chars
  615. for (iLoop = 0; iLoop < CAND_PAGE_SIZE && iStart+iLoop < lpCandList->dwCount; iLoop++)
  616. {
  617. // Set text color
  618. if ( (iStart + iLoop) >= GetNumOfK0() ) // if K1 Hanja set it blue color
  619. {
  620. // If button face is black
  621. if (GetSysColor(COLOR_3DFACE) == RGB(0,0,0))
  622. SetTextColor(hDC, RGB(0, 128, 255));
  623. else
  624. SetTextColor(hDC, RGB(0, 0, 255));
  625. }
  626. else
  627. SetTextColor(hDC, GetSysColor(COLOR_MENUTEXT));
  628. // lpCandStr = (LPSTR)((LPSTR)lpCandList + lpCandList->dwOffset[iStart + iLoop]);
  629. OurTextOutW(hDC, s_rcCandBtn[iLoop].left + 10, s_rcCandBtn[iLoop].top +3,
  630. pImeCtx->GetCandidateStr(iStart + iLoop));
  631. // (LPWSTR)lpCandStr,
  632. // 1);
  633. // Dbg(DBGID_UI, TEXT("PaintCandWindow - Cand Char = 0x%04x"), *(LPWSTR)lpCandStr);
  634. // Set tooltip info
  635. if (IsWin(lpUIPrivate->hCandTTWnd))
  636. {
  637. CIMEData ImeData;
  638. CHAR szCurSense[MAX_SENSE_LENGTH+6+1]; // 6 reserved for Unicode display(Format "U+0000")
  639. WCHAR wszCurSense[MAX_SENSE_LENGTH+6+1]; // 6 reserved for Unicode display(Format "U+0000")
  640. CHAR szHanjaMeaning[MAX_SENSE_LENGTH+1];
  641. WCHAR wzHangulOfHanja[2]; // Need just one character
  642. CHAR szHangulOfHanja[4]; // One DBCS + One Null + extra byte
  643. LPWSTR pwszMeaning;
  644. // Init local vars
  645. szCurSense[0] = '\0';
  646. wszCurSense[0] = L'\0';
  647. szHanjaMeaning[0] = '\0';
  648. wzHangulOfHanja[0] = L'\0';
  649. szHangulOfHanja[0] = '\0';
  650. ti.uId = iLoop;
  651. // Get the meaning of current Hanja
  652. if (pwszMeaning = pImeCtx->GetCandidateMeaningStr(iStart+iLoop))
  653. {
  654. // Get Hangul pronounciation of current Hanja
  655. wzHangulOfHanja[0] = GetCurrentHangulOfHanja();
  656. wzHangulOfHanja[1] = L'\0';
  657. if (IsWinNT())
  658. {
  659. if (ImeData->fCandUnicodeTT)
  660. wsprintfW(wszCurSense, L"%s %s\r\nU+%04X",
  661. pwszMeaning,
  662. wzHangulOfHanja,
  663. (WORD)pImeCtx->GetCandidateStr(iStart + iLoop));
  664. else
  665. wsprintfW(wszCurSense, L"%s %s", pwszMeaning, wzHangulOfHanja);
  666. ti.lpszText = (LPSTR)wszCurSense;
  667. }
  668. else // If not NT, convert to ANSI
  669. {
  670. if (WideCharToMultiByte(CP_KOREA, 0,
  671. pwszMeaning,
  672. -1,
  673. (LPSTR)szHanjaMeaning,
  674. sizeof(szHanjaMeaning),
  675. NULL,
  676. NULL) == 0)
  677. szHanjaMeaning[0] = 0;
  678. if (WideCharToMultiByte(CP_KOREA, 0,
  679. wzHangulOfHanja,
  680. -1,
  681. (LPSTR)szHangulOfHanja,
  682. sizeof(szHangulOfHanja),
  683. NULL,
  684. NULL) == 0)
  685. szHangulOfHanja[0] = 0;
  686. if (ImeData->fCandUnicodeTT)
  687. wsprintfA(szCurSense, "%s %s\r\nU+%04X",
  688. szHanjaMeaning,
  689. szHangulOfHanja,
  690. (WORD)pImeCtx->GetCandidateStr(iStart + iLoop));
  691. else
  692. wsprintfA(szCurSense, "%s %s", szHanjaMeaning, szHangulOfHanja);
  693. ti.lpszText = szCurSense;
  694. }
  695. }
  696. else
  697. {
  698. if (ImeData->fCandUnicodeTT)
  699. {
  700. wsprintfA(szCurSense, "U+%04X", (WORD)pImeCtx->GetCandidateStr(iStart + iLoop));
  701. ti.lpszText = szCurSense;
  702. }
  703. }
  704. // Set Tooltip Text
  705. if (ti.lpszText)
  706. {
  707. UINT uiMsgUpdateTxt = TTM_UPDATETIPTEXTW;
  708. if (!IsWinNT())
  709. uiMsgUpdateTxt = TTM_UPDATETIPTEXT;
  710. OurSendMessage(lpUIPrivate->hCandTTWnd, uiMsgUpdateTxt, 0, (LPARAM) (LPTOOLINFO) &ti);
  711. // To force the tooltip control to use multiple lines
  712. OurSendMessage(lpUIPrivate->hCandTTWnd, TTM_SETMAXTIPWIDTH, 0, 300);
  713. }
  714. }
  715. }
  716. SetBkMode(hDC, iSaveBkMode);
  717. // Reset blank cand list tooltip
  718. if (iLoop < CAND_PAGE_SIZE)
  719. {
  720. ti.lpszText = NULL;
  721. for (; iLoop < CAND_PAGE_SIZE; iLoop++)
  722. {
  723. ti.uId = iLoop;
  724. OurSendMessage(lpUIPrivate->hCandTTWnd, TTM_UPDATETIPTEXT, 0, (LPARAM) (LPTOOLINFO) &ti);
  725. DrawBitmap(hDC, s_rcCandBtn[iLoop].left + 3, s_rcCandBtn[iLoop].top + 6, hBMCandNum);
  726. }
  727. }
  728. //
  729. if (iStart)
  730. DrawBitmap(hDC, 19, 8, hBMCandArr1);
  731. if (iStart + CAND_PAGE_SIZE < lpCandList->dwCount)
  732. DrawBitmap(hDC, 296, 8, hBMCandArr2);
  733. DeleteObject(hBMCand);
  734. DeleteObject(hBMCandNum);
  735. DeleteObject(hBMCandArr1);
  736. DeleteObject(hBMCandArr2);
  737. SelectObject(hDC, hOldFont);
  738. DeleteObject(hFontFix);
  739. }
  740. PaintCandWindowExit:
  741. GlobalUnlock(hUIPrivate);
  742. }