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.

1742 lines
48 KiB

  1. /*++
  2. Copyright (c) 1990-1999 Microsoft Corporation, All Rights Reserved
  3. Module Name:
  4. CANDUI.c
  5. ++*/
  6. #include <windows.h>
  7. #include <immdev.h>
  8. #include "imeattr.h"
  9. #include "imedefs.h"
  10. #include "imerc.h"
  11. #if defined(UNIIME)
  12. #include "uniime.h"
  13. #endif
  14. #if !defined(ROMANIME)
  15. /**********************************************************************/
  16. /* GetCandWnd */
  17. /* Return Value : */
  18. /* window handle of candidatte */
  19. /**********************************************************************/
  20. HWND PASCAL GetCandWnd(
  21. HWND hUIWnd) // UI window
  22. {
  23. HGLOBAL hUIPrivate;
  24. LPUIPRIV lpUIPrivate;
  25. HWND hCandWnd;
  26. hUIPrivate = (HGLOBAL)GetWindowLongPtr(hUIWnd, IMMGWLP_PRIVATE);
  27. if (!hUIPrivate) { // can not darw candidate window
  28. return (HWND)NULL;
  29. }
  30. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  31. if (!lpUIPrivate) { // can not draw candidate window
  32. return (HWND)NULL;
  33. }
  34. hCandWnd = lpUIPrivate->hCandWnd;
  35. GlobalUnlock(hUIPrivate);
  36. return (hCandWnd);
  37. }
  38. /**********************************************************************/
  39. /* CalcCandPos */
  40. /**********************************************************************/
  41. BOOL PASCAL CalcCandPos(
  42. #if defined (UNIIME)
  43. LPIMEL lpImeL,
  44. #endif
  45. LPINPUTCONTEXT lpIMC,
  46. LPPOINT lpptWnd) // the composition window position
  47. {
  48. UINT uEsc;
  49. POINT ptCurPos, ptNew;
  50. BOOL fAdjust;
  51. RECT rcWorkArea;
  52. #if 1 // MultiMonitor support
  53. rcWorkArea = ImeMonitorWorkAreaFromPoint(*lpptWnd);
  54. #else
  55. rcWorkArea = sImeG.rcWorkArea;
  56. #endif
  57. uEsc = (UINT)((lpIMC->lfFont.A.lfEscapement + 450) / 900 % 4);
  58. ptCurPos = lpIMC->cfCompForm.ptCurrentPos;
  59. ClientToScreen(lpIMC->hWnd, &ptCurPos);
  60. fAdjust = FALSE;
  61. if (uEsc == 0) {
  62. ptNew.x = lpptWnd->x + lpImeL->xCompWi + UI_MARGIN * 2;
  63. if (ptNew.x + lpImeL->xCandWi > rcWorkArea.right) {
  64. // exceed screen width
  65. ptNew.x = lpptWnd->x - lpImeL->xCandWi - UI_MARGIN * 2;
  66. }
  67. if (lpptWnd->y >= ptCurPos.y) {
  68. ptNew.y = lpptWnd->y + lpImeL->cyCompBorder - lpImeL->cyCandBorder;
  69. if (ptNew.y + lpImeL->yCandHi > rcWorkArea.bottom) {
  70. // exceed screen high
  71. ptNew.y = rcWorkArea.bottom - lpImeL->yCandHi;
  72. }
  73. } else {
  74. ptNew.y = lpptWnd->y + lpImeL->yCompHi - lpImeL->yCandHi;
  75. if (ptNew.y < rcWorkArea.top) {
  76. ptNew.y = rcWorkArea.top;
  77. }
  78. }
  79. } else if (uEsc == 1) {
  80. if (lpptWnd->x >= ptCurPos.x) {
  81. ptNew.x = lpptWnd->x + lpImeL->cxCompBorder -
  82. lpImeL->cxCandBorder;
  83. if (ptNew.x + lpImeL->xCandWi > rcWorkArea.right) {
  84. // exceed screen width
  85. ptNew.x = rcWorkArea.right - lpImeL->xCandWi;
  86. fAdjust = TRUE;
  87. }
  88. } else {
  89. ptNew.x = lpptWnd->x + lpImeL->xCompWi - lpImeL->xCandWi;
  90. if (ptNew.x < rcWorkArea.left) {
  91. // exceed screen width
  92. ptNew.x = rcWorkArea.left;
  93. fAdjust = TRUE;
  94. }
  95. }
  96. ptNew.y = lpptWnd->y + lpImeL->yCompHi + UI_MARGIN * 2;
  97. if (ptNew.y + lpImeL->yCandHi > rcWorkArea.bottom) {
  98. // exceed screen high
  99. ptNew.y = lpptWnd->y - lpImeL->yCandHi - UI_MARGIN * 2;
  100. }
  101. } else if (uEsc == 2) {
  102. ptNew.x = lpptWnd->x - lpImeL->xCandWi - UI_MARGIN * 2;
  103. if (ptNew.x < 0) {
  104. ptNew.x = lpptWnd->x + lpImeL->xCompWi + UI_MARGIN * 2;
  105. }
  106. if (lpptWnd->y >= ptCurPos.y) {
  107. ptNew.y = lpptWnd->y + lpImeL->cyCompBorder - lpImeL->cyCandBorder;
  108. if (ptNew.y + lpImeL->yCandHi > rcWorkArea.bottom) {
  109. // exceed screen high
  110. ptNew.y = rcWorkArea.bottom - lpImeL->yCandHi;
  111. }
  112. } else {
  113. ptNew.y = lpptWnd->y + lpImeL->yCompHi - lpImeL->yCandHi;
  114. if (ptNew.y < rcWorkArea.top) {
  115. ptNew.y = rcWorkArea.top;
  116. }
  117. }
  118. } else {
  119. if (lpptWnd->x >= ptCurPos.x) {
  120. ptNew.x = lpptWnd->x + lpImeL->cxCompBorder -
  121. lpImeL->cxCandBorder;
  122. if (ptNew.x + lpImeL->xCandWi > rcWorkArea.right) {
  123. // exceed screen width
  124. ptNew.x = rcWorkArea.right - lpImeL->xCandWi;
  125. fAdjust = TRUE;
  126. }
  127. } else {
  128. ptNew.x = lpptWnd->x + lpImeL->xCompWi - lpImeL->xCandWi;
  129. if (ptNew.x < rcWorkArea.left) {
  130. // exceed screen width
  131. ptNew.x = rcWorkArea.left;
  132. fAdjust = TRUE;
  133. }
  134. }
  135. ptNew.y = lpptWnd->y + lpImeL->yCompHi + UI_MARGIN * 2;
  136. if (ptNew.y + lpImeL->yCandHi > rcWorkArea.bottom) {
  137. // exceed screen high
  138. ptNew.y = lpptWnd->y - lpImeL->yCandHi - UI_MARGIN * 2;
  139. }
  140. }
  141. *lpptWnd = ptNew;
  142. return (fAdjust);
  143. }
  144. /**********************************************************************/
  145. /* AdjustCandBoundry */
  146. /**********************************************************************/
  147. void PASCAL AdjustCandBoundry(
  148. #if defined (UNIIME)
  149. LPIMEL lpImeL,
  150. #endif
  151. LPPOINT lpptCandWnd) // the position
  152. {
  153. RECT rcWorkArea;
  154. #if 1 // MultiMonitor support
  155. {
  156. RECT rcCandWnd;
  157. *(LPPOINT)&rcCandWnd = *(LPPOINT)lpptCandWnd;
  158. rcCandWnd.right = rcCandWnd.left + lpImeL->xCandWi;
  159. rcCandWnd.bottom = rcCandWnd.top + lpImeL->yCandHi;
  160. rcWorkArea = ImeMonitorWorkAreaFromRect(&rcCandWnd);
  161. }
  162. #else
  163. rcWorkArea = sImeG.rcWorkArea;
  164. #endif
  165. if (lpptCandWnd->x < rcWorkArea.left) {
  166. lpptCandWnd->x = rcWorkArea.left;
  167. } else if (lpptCandWnd->x + lpImeL->xCandWi > rcWorkArea.right) {
  168. lpptCandWnd->x = rcWorkArea.right - lpImeL->xCandWi;
  169. } else {
  170. }
  171. if (lpptCandWnd->y < rcWorkArea.top) {
  172. lpptCandWnd->y = rcWorkArea.top;
  173. } else if (lpptCandWnd->y + lpImeL->yCandHi > rcWorkArea.bottom) {
  174. lpptCandWnd->y = rcWorkArea.bottom - lpImeL->yCandHi;
  175. } else {
  176. }
  177. return;
  178. }
  179. /**********************************************************************/
  180. /* FitInCandLazyOperation() */
  181. /* Return Value : */
  182. /* TRUE or FALSE */
  183. /**********************************************************************/
  184. BOOL PASCAL FitInCandLazyOperation( // fit in lazy operation or not
  185. #if defined(UNIIME)
  186. LPIMEL lpImeL,
  187. #endif
  188. LPPOINT lpptOrg,
  189. LPPOINT lpptNearCaret, // the suggested near caret position
  190. LPRECT lprcInputRect,
  191. UINT uEsc)
  192. {
  193. POINT ptDelta, ptTol;
  194. RECT rcUIRect, rcInterRect;
  195. ptDelta.x = lpptOrg->x - lpptNearCaret->x;
  196. ptDelta.x = (ptDelta.x >= 0) ? ptDelta.x : -ptDelta.x;
  197. ptTol.x = sImeG.iParaTol * ncUIEsc[uEsc].iParaFacX +
  198. sImeG.iPerpTol * ncUIEsc[uEsc].iPerpFacX;
  199. ptTol.x = (ptTol.x >= 0) ? ptTol.x : -ptTol.x;
  200. if (ptDelta.x > ptTol.x) {
  201. return (FALSE);
  202. }
  203. ptDelta.y = lpptOrg->y - lpptNearCaret->y;
  204. ptDelta.y = (ptDelta.y >= 0) ? ptDelta.y : -ptDelta.y;
  205. ptTol.y = sImeG.iParaTol * ncUIEsc[uEsc].iParaFacY +
  206. sImeG.iPerpTol * ncUIEsc[uEsc].iPerpFacY;
  207. ptTol.y = (ptTol.y >= 0) ? ptTol.y : -ptTol.y;
  208. if (ptDelta.y > ptTol.y) {
  209. return (FALSE);
  210. }
  211. // build up the UI rectangle (candidate window)
  212. rcUIRect.left = lpptOrg->x;
  213. rcUIRect.top = lpptOrg->y;
  214. rcUIRect.right = rcUIRect.left + lpImeL->xCandWi;
  215. rcUIRect.bottom = rcUIRect.top + lpImeL->yCandHi;
  216. if (IntersectRect(&rcInterRect, &rcUIRect, lprcInputRect)) {
  217. return (FALSE);
  218. }
  219. return (TRUE);
  220. }
  221. /**********************************************************************/
  222. /* AdjustCandRectBoundry */
  223. /**********************************************************************/
  224. void PASCAL AdjustCandRectBoundry(
  225. #if defined (UNIIME)
  226. LPIMEL lpImeL,
  227. #endif
  228. LPINPUTCONTEXT lpIMC,
  229. LPPOINT lpptOrg, // original candidate position
  230. LPPOINT lpptCaret) // the caret position
  231. {
  232. RECT rcExclude, rcUIRect, rcInterSect;
  233. UINT uEsc, uRot;
  234. POINT ptCaret, ptOldNearCaret, ptFont;
  235. // be a normal rectangle, not a negative rectangle
  236. if (lpIMC->cfCandForm[0].rcArea.left > lpIMC->cfCandForm[0].rcArea.right) {
  237. LONG tmp;
  238. tmp = lpIMC->cfCandForm[0].rcArea.left;
  239. lpIMC->cfCandForm[0].rcArea.left = lpIMC->cfCandForm[0].rcArea.right;
  240. lpIMC->cfCandForm[0].rcArea.right = tmp;
  241. }
  242. if (lpIMC->cfCandForm[0].rcArea.top > lpIMC->cfCandForm[0].rcArea.bottom) {
  243. LONG tmp;
  244. tmp = lpIMC->cfCandForm[0].rcArea.top;
  245. lpIMC->cfCandForm[0].rcArea.top = lpIMC->cfCandForm[0].rcArea.bottom;
  246. lpIMC->cfCandForm[0].rcArea.bottom = tmp;
  247. }
  248. // translate from client coordinate to screen coordinate
  249. rcExclude = lpIMC->cfCandForm[0].rcArea;
  250. rcExclude.left += lpptCaret->x - lpIMC->cfCandForm[0].ptCurrentPos.x;
  251. rcExclude.right += lpptCaret->x - lpIMC->cfCandForm[0].ptCurrentPos.x;
  252. rcExclude.top += lpptCaret->y - lpIMC->cfCandForm[0].ptCurrentPos.y;
  253. rcExclude.bottom += lpptCaret->y - lpIMC->cfCandForm[0].ptCurrentPos.y;
  254. uEsc = (UINT)((lpIMC->lfFont.A.lfEscapement + 450) / 900 % 4);
  255. uRot = (UINT)((lpIMC->lfFont.A.lfOrientation + 450) / 900 % 4);
  256. if (uEsc == 0) {
  257. ptCaret.x = lpptCaret->x;
  258. ptCaret.y = rcExclude.top;
  259. } else if (uEsc == 1) {
  260. ptCaret.x = rcExclude.left;
  261. ptCaret.y = lpptCaret->y;
  262. } else if (uEsc == 2) {
  263. ptCaret.x = lpptCaret->x;
  264. ptCaret.y = rcExclude.bottom;
  265. } else {
  266. ptCaret.x = rcExclude.right;
  267. ptCaret.y = lpptCaret->y;
  268. }
  269. ptFont.x = rcExclude.right - rcExclude.left;
  270. ptFont.y = rcExclude.bottom - rcExclude.top;
  271. // the first try
  272. GetNearCaretPosition(
  273. #if defined(UNIIME)
  274. lpImeL,
  275. #endif
  276. &ptFont, uEsc, uRot, &ptCaret, &ptOldNearCaret,
  277. NEAR_CARET_FIRST_TIME|NEAR_CARET_CANDIDATE);
  278. AdjustCandBoundry(
  279. #if defined(UNIIME)
  280. lpImeL,
  281. #endif
  282. &ptOldNearCaret);
  283. *(LPPOINT)&rcUIRect = ptOldNearCaret;
  284. rcUIRect.right = rcUIRect.left + lpImeL->xCandWi;
  285. rcUIRect.bottom = rcUIRect.top + lpImeL->yCandHi;
  286. if (IntersectRect(&rcInterSect, &rcExclude, &rcUIRect)) {
  287. } else if (FitInCandLazyOperation(
  288. #if defined(UNIIME)
  289. lpImeL,
  290. #endif
  291. lpptOrg, (LPPOINT)&rcUIRect, &rcExclude, uEsc)) {
  292. *lpptCaret = *lpptOrg;
  293. return;
  294. } else {
  295. *lpptCaret = *(LPPOINT)&rcUIRect;
  296. return;
  297. }
  298. // the second try
  299. GetNearCaretPosition(
  300. #if defined(UNIIME)
  301. lpImeL,
  302. #endif
  303. &ptFont, uEsc, uRot, &ptCaret, (LPPOINT)&rcUIRect,
  304. NEAR_CARET_CANDIDATE);
  305. AdjustCandBoundry(
  306. #if defined(UNIIME)
  307. lpImeL,
  308. #endif
  309. (LPPOINT)&rcUIRect);
  310. rcUIRect.right = rcUIRect.left + lpImeL->xCandWi;
  311. rcUIRect.bottom = rcUIRect.top + lpImeL->yCandHi;
  312. if (IntersectRect(&rcInterSect, &rcExclude, &rcUIRect)) {
  313. } else if (FitInCandLazyOperation(
  314. #if defined(UNIIME)
  315. lpImeL,
  316. #endif
  317. lpptOrg, (LPPOINT)&rcUIRect, &rcExclude, uEsc)) {
  318. *lpptCaret = *lpptOrg;
  319. return;
  320. } else {
  321. *lpptCaret = *(LPPOINT)&rcUIRect;
  322. return;
  323. }
  324. // unhappy ending! :-(
  325. *lpptCaret = ptOldNearCaret;
  326. return;
  327. }
  328. /**********************************************************************/
  329. /* SetCandPosition() */
  330. /**********************************************************************/
  331. LRESULT PASCAL SetCandPosition(
  332. #if defined(UNIIME)
  333. LPIMEL lpImeL,
  334. #endif
  335. HWND hCandWnd)
  336. {
  337. HWND hUIWnd;
  338. HIMC hIMC;
  339. LPINPUTCONTEXT lpIMC;
  340. POINT ptWnd;
  341. hUIWnd = GetWindow(hCandWnd, GW_OWNER);
  342. hIMC = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC);
  343. if (!hIMC) {
  344. return (1L);
  345. }
  346. lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
  347. if (!lpIMC) {
  348. return (1L);
  349. }
  350. ptWnd = lpIMC->cfCandForm[0].ptCurrentPos;
  351. ClientToScreen((HWND)lpIMC->hWnd, &ptWnd);
  352. if (lpIMC->cfCandForm[0].dwStyle & CFS_FORCE_POSITION) {
  353. } else if (lpIMC->cfCandForm[0].dwStyle == CFS_EXCLUDE) {
  354. RECT rcCand;
  355. GetWindowRect(hCandWnd, &rcCand);
  356. AdjustCandRectBoundry(
  357. #if defined(UNIIME)
  358. lpImeL,
  359. #endif
  360. lpIMC, (LPPOINT)&rcCand, &ptWnd);
  361. if (ptWnd.x != rcCand.left) {
  362. } else if (ptWnd.y != rcCand.right) {
  363. } else {
  364. goto SetCandPosUnlockIMC;
  365. }
  366. } else if (lpIMC->cfCandForm[0].dwStyle == CFS_CANDIDATEPOS) {
  367. HWND hCompWnd;
  368. AdjustCandBoundry(
  369. #if defined(UNIIME)
  370. lpImeL,
  371. #endif
  372. &ptWnd);
  373. if (lpIMC->cfCandForm[0].dwIndex == 0) {
  374. } else if (!(hCompWnd = GetCompWnd(hUIWnd))) {
  375. } else {
  376. RECT rcComp, rcCand, rcInterSect;
  377. GetWindowRect(hCompWnd, &rcComp);
  378. *(LPPOINT)&rcCand = ptWnd;
  379. rcCand.right = rcCand.left + lpImeL->xCandWi;
  380. rcCand.bottom = rcCand.top + lpImeL->yCandHi;
  381. if (IntersectRect(&rcInterSect, &rcComp, &rcCand)) {
  382. ptWnd = *(LPPOINT)&rcComp;
  383. CalcCandPos(
  384. #if defined(UNIIME)
  385. lpImeL,
  386. #endif
  387. lpIMC, &ptWnd);
  388. }
  389. }
  390. } else if (lpIMC->cfCandForm[0].dwStyle == CFS_DEFAULT) {
  391. HWND hCompWnd;
  392. BOOL fUseCompWndPos;
  393. hCompWnd = GetCompWnd(hUIWnd);
  394. if (!hCompWnd) {
  395. fUseCompWndPos = FALSE;
  396. } else if (IsWindowVisible(hCompWnd)) {
  397. fUseCompWndPos = TRUE;
  398. } else {
  399. fUseCompWndPos = FALSE;
  400. }
  401. if (fUseCompWndPos) {
  402. ptWnd.x = 0;
  403. ptWnd.y = 0;
  404. ClientToScreen(hCompWnd, &ptWnd);
  405. ptWnd.x -= lpImeL->cxCompBorder;
  406. ptWnd.y -= lpImeL->cyCompBorder;
  407. } else {
  408. POINT ptNew;
  409. ptWnd = lpIMC->cfCompForm.ptCurrentPos;
  410. ClientToScreen((HWND)lpIMC->hWnd, &ptWnd);
  411. ptWnd.x -= lpImeL->cxCompBorder;
  412. ptWnd.y -= lpImeL->cyCompBorder;
  413. ptNew = ptWnd;
  414. // try to simulate the position of composition window
  415. AdjustCompPosition(
  416. #if defined(UNIIME)
  417. lpImeL,
  418. #endif
  419. lpIMC, &ptWnd, &ptNew);
  420. }
  421. CalcCandPos(
  422. #if defined(UNIIME)
  423. lpImeL,
  424. #endif
  425. lpIMC, &ptWnd);
  426. } else {
  427. }
  428. SetWindowPos(hCandWnd, NULL, ptWnd.x, ptWnd.y,
  429. 0, 0, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER);
  430. SetCandPosUnlockIMC:
  431. ImmUnlockIMC(hIMC);
  432. return (0L);
  433. }
  434. /**********************************************************************/
  435. /* ShowCand() */
  436. /**********************************************************************/
  437. void PASCAL ShowCand( // Show the candidate window
  438. #if defined(UNIIME)
  439. LPIMEL lpImeL,
  440. #endif
  441. HWND hUIWnd,
  442. int nShowCandCmd)
  443. {
  444. HGLOBAL hUIPrivate;
  445. LPUIPRIV lpUIPrivate;
  446. hUIPrivate = (HGLOBAL)GetWindowLongPtr(hUIWnd, IMMGWLP_PRIVATE);
  447. if (!hUIPrivate) { // can not darw candidate window
  448. return;
  449. }
  450. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  451. if (!lpUIPrivate) { // can not draw candidate window
  452. return;
  453. }
  454. if (lpUIPrivate->nShowCandCmd == nShowCandCmd) {
  455. goto SwCandNoChange;
  456. }
  457. if (nShowCandCmd == SW_HIDE) {
  458. lpUIPrivate->fdwSetContext &= ~(ISC_HIDE_CAND_WINDOW);
  459. }
  460. if (!lpUIPrivate->hCandWnd) {
  461. // not in show candidate window mode
  462. } else if (lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI) {
  463. int nCurrShowState;
  464. lpUIPrivate->nShowCandCmd = nShowCandCmd;
  465. nCurrShowState = lpUIPrivate->nShowStatusCmd;
  466. nCurrShowState |= lpUIPrivate->nShowCompCmd;
  467. if (nCurrShowState == SW_HIDE) {
  468. // if other two are hide, the current show state is determined
  469. // by this candidate section
  470. ShowWindow(lpUIPrivate->hCandWnd, nShowCandCmd);
  471. } else {
  472. RedrawWindow(lpUIPrivate->hCandWnd, NULL, NULL,
  473. RDW_INVALIDATE|RDW_ERASE);
  474. }
  475. } else {
  476. ShowWindow(lpUIPrivate->hCandWnd, nShowCandCmd);
  477. lpUIPrivate->nShowCandCmd = nShowCandCmd;
  478. }
  479. SwCandNoChange:
  480. GlobalUnlock(hUIPrivate);
  481. return;
  482. }
  483. /**********************************************************************/
  484. /* CandPageSizeDown */
  485. /**********************************************************************/
  486. void PASCAL CandPageSizeDown(
  487. LPINPUTCONTEXT lpIMC)
  488. {
  489. DWORD dwSize;
  490. LPCANDIDATEINFO lpCandInfo;
  491. LPCANDIDATELIST lpCandList;
  492. DWORD dwStart, dwEnd;
  493. int nChars, iLen;
  494. if (!lpIMC) {
  495. return;
  496. }
  497. if (!lpIMC->hCandInfo) {
  498. return;
  499. }
  500. lpCandInfo = (LPCANDIDATEINFO)ImmLockIMCC(lpIMC->hCandInfo);
  501. if (!lpCandInfo) {
  502. return;
  503. }
  504. lpCandList = (LPCANDIDATELIST)((LPBYTE)lpCandInfo +
  505. lpCandInfo->dwOffset[0]);
  506. dwStart = lpCandList->dwPageStart;
  507. dwEnd = dwStart + CANDPERPAGE;
  508. if (dwEnd > lpCandList->dwCount) {
  509. dwEnd = lpCandList->dwCount;
  510. }
  511. dwSize = 0;
  512. for (nChars = 0; dwStart < dwEnd; dwStart++, dwSize++) {
  513. LPTSTR lpStr;
  514. #ifdef UNICODE
  515. LPTSTR lpTmpStr;
  516. #endif
  517. // for displaying digit
  518. nChars++;
  519. lpStr = (LPTSTR)((LPBYTE)lpCandList + lpCandList->dwOffset[dwStart]);
  520. #ifdef UNICODE
  521. iLen = 0;
  522. for (lpTmpStr = lpStr; *lpTmpStr; lpTmpStr++) {
  523. if (*lpTmpStr < 0x200) {
  524. iLen += 1;
  525. } else {
  526. iLen += 2;
  527. }
  528. }
  529. #else
  530. iLen = lstrlen(lpStr);
  531. #endif
  532. #if defined(WINAR30)
  533. if (!iLen) {
  534. iLen = sizeof(WCHAR)/sizeof(TCHAR);
  535. }
  536. #endif
  537. // buffer is not enough
  538. if ((CANDPERPAGE * 3 - nChars) < iLen) {
  539. if (!dwSize) {
  540. dwSize = 1;
  541. }
  542. break;
  543. }
  544. nChars += iLen;
  545. }
  546. if (!dwSize) {
  547. dwSize = CANDPERPAGE;
  548. }
  549. lpCandList->dwPageSize = dwSize;
  550. ImmUnlockIMCC(lpIMC->hCandInfo);
  551. return;
  552. }
  553. /**********************************************************************/
  554. /* OpenCand */
  555. /**********************************************************************/
  556. void PASCAL OpenCand(
  557. #if defined(UNIIME)
  558. LPINSTDATAL lpInstL,
  559. LPIMEL lpImeL,
  560. #endif
  561. HWND hUIWnd)
  562. {
  563. HGLOBAL hUIPrivate;
  564. LPUIPRIV lpUIPrivate;
  565. HIMC hIMC;
  566. LPINPUTCONTEXT lpIMC;
  567. LPPRIVCONTEXT lpImcP;
  568. DWORD fdwImeMsg;
  569. POINT ptWnd;
  570. hUIPrivate = (HGLOBAL)GetWindowLongPtr(hUIWnd, IMMGWLP_PRIVATE);
  571. if (!hUIPrivate) { // can not darw candidate window
  572. return;
  573. }
  574. hIMC = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC);
  575. if (!hIMC) {
  576. return;
  577. }
  578. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  579. if (!lpUIPrivate) { // can not draw candidate window
  580. return;
  581. }
  582. lpUIPrivate->fdwSetContext |= ISC_SHOWUICANDIDATEWINDOW;
  583. // in the timing of the transition, we will wait
  584. if (lpUIPrivate->fdwSetContext & ISC_OFF_CARET_UI) {
  585. if (!(lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI)) {
  586. PostMessage(hUIWnd, WM_USER_UICHANGE, 0, 0);
  587. goto OpenCandUnlockUIPriv;
  588. }
  589. } else {
  590. if (lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI) {
  591. PostMessage(hUIWnd, WM_USER_UICHANGE, 0, 0);
  592. goto OpenCandUnlockUIPriv;
  593. }
  594. }
  595. lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
  596. if (!lpIMC) {
  597. goto OpenCandUnlockUIPriv;
  598. }
  599. fdwImeMsg = 0;
  600. lpImcP = (LPPRIVCONTEXT)ImmLockIMCC(lpIMC->hPrivate);
  601. if (lpImcP) {
  602. fdwImeMsg = lpImcP->fdwImeMsg;
  603. ImmUnlockIMCC(lpIMC->hPrivate);
  604. }
  605. if (!(fdwImeMsg & MSG_ALREADY_OPEN)) {
  606. // Sometime the application call ImmNotifyIME to cancel the
  607. // composition before it process IMN_OPENCANDIDATE.
  608. // We should avoid to process this kind of IMN_OPENCANDIDATE.
  609. goto OpenCandUnlockIMC;
  610. }
  611. if (lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI) {
  612. if (lpUIPrivate->hCandWnd) {
  613. } else if (lpUIPrivate->hStatusWnd) {
  614. lpUIPrivate->hCandWnd = lpUIPrivate->hStatusWnd;
  615. lpUIPrivate->nShowCandCmd = lpUIPrivate->nShowStatusCmd;
  616. } else if (lpUIPrivate->hCompWnd) {
  617. lpUIPrivate->hCandWnd = lpUIPrivate->hCompWnd;
  618. lpUIPrivate->nShowCandCmd = lpUIPrivate->nShowCompCmd;
  619. } else {
  620. }
  621. CandPageSizeDown(lpIMC);
  622. ptWnd = lpIMC->ptStatusWndPos;
  623. } else if (lpIMC->cfCandForm[0].dwIndex == 0) {
  624. ptWnd = lpIMC->cfCandForm[0].ptCurrentPos;
  625. ClientToScreen(lpIMC->hWnd, &ptWnd);
  626. if (lpIMC->cfCandForm[0].dwStyle & CFS_FORCE_POSITION) {
  627. } else if (lpIMC->cfCandForm[0].dwStyle == CFS_EXCLUDE) {
  628. RECT rcCand;
  629. if (lpUIPrivate->hCandWnd) {
  630. GetWindowRect(lpUIPrivate->hCandWnd, &rcCand);
  631. } else {
  632. *(LPPOINT)&rcCand = ptWnd;
  633. }
  634. AdjustCandRectBoundry(
  635. #if defined(UNIIME)
  636. lpImeL,
  637. #endif
  638. lpIMC, (LPPOINT)&rcCand, &ptWnd);
  639. } else if (lpIMC->cfCandForm[0].dwStyle == CFS_CANDIDATEPOS) {
  640. AdjustCandBoundry(
  641. #if defined(UNIIME)
  642. lpImeL,
  643. #endif
  644. &ptWnd);
  645. } else {
  646. goto OpenCandDefault;
  647. }
  648. } else {
  649. OpenCandDefault:
  650. if (lpUIPrivate->nShowCompCmd != SW_HIDE) {
  651. ptWnd.x = ptWnd.y = 0;
  652. ClientToScreen(lpUIPrivate->hCompWnd, &ptWnd);
  653. ptWnd.x -= lpImeL->cxCompBorder;
  654. ptWnd.y -= lpImeL->cyCompBorder;
  655. } else {
  656. POINT ptNew;
  657. ptWnd = lpIMC->cfCompForm.ptCurrentPos;
  658. ClientToScreen(lpIMC->hWnd, &ptWnd);
  659. ptWnd.x -= lpImeL->cxCompBorder;
  660. ptWnd.y -= lpImeL->cyCompBorder;
  661. ptNew = ptWnd;
  662. // try to simulate the position of composition window
  663. AdjustCompPosition(
  664. #if defined(UNIIME)
  665. lpImeL,
  666. #endif
  667. lpIMC, &ptWnd, &ptNew);
  668. }
  669. CalcCandPos(
  670. #if defined(UNIIME)
  671. lpImeL,
  672. #endif
  673. lpIMC, &ptWnd);
  674. lpIMC->cfCandForm[0].dwStyle = CFS_CANDIDATEPOS;
  675. lpIMC->cfCandForm[0].ptCurrentPos = ptWnd;
  676. ScreenToClient(lpIMC->hWnd, &lpIMC->cfCandForm[0].ptCurrentPos);
  677. }
  678. if (lpUIPrivate->hCandWnd) {
  679. if (lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI) {
  680. RECT rcRect;
  681. rcRect = lpImeL->rcCandText;
  682. // off by 1
  683. rcRect.right += 1;
  684. rcRect.bottom += 1;
  685. InvalidateRect(lpUIPrivate->hCandWnd, &rcRect, FALSE);
  686. rcRect = lpImeL->rcCandPrompt;
  687. // off by 1
  688. rcRect.right += 1;
  689. rcRect.bottom += 1;
  690. InvalidateRect(lpUIPrivate->hCandWnd, &rcRect, TRUE);
  691. rcRect = lpImeL->rcCandPageText;
  692. // off by 1
  693. rcRect.right += 1;
  694. rcRect.bottom += 1;
  695. InvalidateRect(lpUIPrivate->hCandWnd, &rcRect, TRUE);
  696. } else {
  697. SetWindowPos(lpUIPrivate->hCandWnd, NULL,
  698. ptWnd.x, ptWnd.y,
  699. 0, 0, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER);
  700. }
  701. } else {
  702. if (lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI) {
  703. lpUIPrivate->hCandWnd = CreateWindowEx(
  704. WS_EX_WINDOWEDGE|WS_EX_DLGMODALFRAME,
  705. lpImeL->szOffCaretClassName, NULL,
  706. WS_POPUP|WS_DISABLED,
  707. ptWnd.x, ptWnd.y,
  708. lpImeL->xCandWi, lpImeL->yCandHi,
  709. hUIWnd, (HMENU)NULL, lpInstL->hInst, NULL);
  710. if (lpUIPrivate->hSoftKbdWnd) {
  711. // insert soft keyboard in front of other UI
  712. SetWindowPos(lpUIPrivate->hCandWnd,
  713. lpUIPrivate->hSoftKbdWnd,
  714. 0, 0, 0, 0,
  715. SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
  716. }
  717. } else {
  718. lpUIPrivate->hCandWnd = CreateWindowEx(0,
  719. // WS_EX_WINDOWEDGE|WS_EX_DLGMODALFRAME,
  720. lpImeL->szCandClassName, NULL,
  721. WS_POPUP|WS_DISABLED|WS_BORDER,
  722. ptWnd.x, ptWnd.y,
  723. lpImeL->xCandWi, lpImeL->yCandHi,
  724. hUIWnd, (HMENU)NULL, lpInstL->hInst, NULL);
  725. }
  726. SetWindowLong(lpUIPrivate->hCandWnd, UI_MOVE_OFFSET,
  727. WINDOW_NOT_DRAG);
  728. SetWindowLong(lpUIPrivate->hCandWnd, UI_MOVE_XY, 0L);
  729. }
  730. ShowCand(
  731. #if defined(UNIIME)
  732. lpImeL,
  733. #endif
  734. hUIWnd, SW_SHOWNOACTIVATE);
  735. OpenCandUnlockIMC:
  736. ImmUnlockIMC(hIMC);
  737. OpenCandUnlockUIPriv:
  738. GlobalUnlock(hUIPrivate);
  739. return;
  740. }
  741. /**********************************************************************/
  742. /* CloseCand */
  743. /**********************************************************************/
  744. void PASCAL CloseCand(
  745. #if defined(UNIIME)
  746. LPIMEL lpImeL,
  747. #endif
  748. HWND hUIWnd)
  749. {
  750. ShowCand(
  751. #if defined(UNIIME)
  752. lpImeL,
  753. #endif
  754. hUIWnd, SW_HIDE);
  755. return;
  756. }
  757. /**********************************************************************/
  758. /* CandPageSizeUp */
  759. /**********************************************************************/
  760. void PASCAL CandPageSizeUp(
  761. HIMC hIMC,
  762. LPINPUTCONTEXT lpIMC,
  763. DWORD dwPrevPageStart)
  764. {
  765. DWORD dwSize;
  766. LPCANDIDATEINFO lpCandInfo;
  767. LPCANDIDATELIST lpCandList;
  768. int iStart, iEnd;
  769. int nChars, iLen;
  770. if (!lpIMC) {
  771. return;
  772. }
  773. if (!lpIMC->hCandInfo) {
  774. return;
  775. }
  776. lpCandInfo = (LPCANDIDATEINFO)ImmLockIMCC(lpIMC->hCandInfo);
  777. if (!lpCandInfo) {
  778. return;
  779. }
  780. lpCandList = (LPCANDIDATELIST)((LPBYTE)lpCandInfo +
  781. lpCandInfo->dwOffset[0]);
  782. if (dwPrevPageStart) {
  783. iStart = dwPrevPageStart - 1;
  784. } else {
  785. goto CandPageSizeUpUnlockCandInfo;
  786. }
  787. if (iStart > (CANDPERPAGE - 1)) {
  788. iEnd = iStart - (CANDPERPAGE - 1);
  789. } else {
  790. iEnd = 0;
  791. }
  792. dwSize = 0;
  793. for (nChars = 0; iStart >= iEnd; iStart--, dwSize++) {
  794. LPTSTR lpStr;
  795. #ifdef UNICODE
  796. LPTSTR lpTmpStr;
  797. #endif
  798. // for displaying digit
  799. nChars++;
  800. lpStr = (LPTSTR)((LPBYTE)lpCandList + lpCandList->dwOffset[iStart]);
  801. #ifdef UNICODE
  802. iLen = 0;
  803. for (lpTmpStr = lpStr; *lpTmpStr; lpTmpStr++) {
  804. if (*lpTmpStr < 0x200) {
  805. iLen += 1;
  806. } else {
  807. iLen += 2;
  808. }
  809. }
  810. #else
  811. iLen = lstrlen(lpStr);
  812. #endif
  813. #if defined(WINAR30)
  814. if (!iLen) {
  815. iLen = sizeof(WCHAR);
  816. }
  817. #endif
  818. // buffer is not enough
  819. if ((CANDPERPAGE * 3 - nChars) < iLen) {
  820. if (!dwSize) {
  821. dwSize = 1;
  822. }
  823. break;
  824. }
  825. nChars += iLen;
  826. }
  827. if (!dwSize) {
  828. dwSize = CANDPERPAGE;
  829. }
  830. lpCandList->dwPageStart = lpCandList->dwSelection =
  831. dwPrevPageStart - dwSize;
  832. lpCandList->dwPageSize = dwSize;
  833. CandPageSizeUpUnlockCandInfo:
  834. ImmUnlockIMCC(lpIMC->hCandInfo);
  835. return;
  836. }
  837. /**********************************************************************/
  838. /* CandPageSize */
  839. /**********************************************************************/
  840. void PASCAL CandPageSize(
  841. HWND hUIWnd,
  842. BOOL fForward)
  843. {
  844. HGLOBAL hUIPrivate;
  845. LPUIPRIV lpUIPrivate;
  846. HIMC hIMC;
  847. LPINPUTCONTEXT lpIMC;
  848. LPPRIVCONTEXT lpImcP;
  849. hUIPrivate = (HGLOBAL)GetWindowLongPtr(hUIWnd, IMMGWLP_PRIVATE);
  850. if (!hUIPrivate) { // can not darw candidate window
  851. return;
  852. }
  853. hIMC = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC);
  854. if (!hIMC) {
  855. return;
  856. }
  857. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  858. if (!lpUIPrivate) { // can not draw candidate window
  859. return;
  860. }
  861. if (!(lpUIPrivate->fdwSetContext & ISC_SHOWUICANDIDATEWINDOW)) {
  862. goto CandPageDownUnlockUIPriv;
  863. }
  864. lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
  865. if (!lpIMC) {
  866. goto CandPageDownUnlockUIPriv;
  867. }
  868. lpImcP = (LPPRIVCONTEXT)ImmLockIMCC(lpIMC->hPrivate);
  869. if (!lpImcP) {
  870. goto CandPageDownUnlockIMC;
  871. }
  872. if (fForward) {
  873. CandPageSizeDown(lpIMC);
  874. } else {
  875. CandPageSizeUp(hIMC, lpIMC, lpImcP->dwPrevPageStart);
  876. }
  877. ImmUnlockIMCC(lpIMC->hPrivate);
  878. CandPageDownUnlockIMC:
  879. ImmUnlockIMC(hIMC);
  880. CandPageDownUnlockUIPriv:
  881. GlobalUnlock(hUIPrivate);
  882. return;
  883. }
  884. /**********************************************************************/
  885. /* DestroyCandWindow */
  886. /**********************************************************************/
  887. void PASCAL DestroyCandWindow(
  888. HWND hCandWnd)
  889. {
  890. HGLOBAL hUIPrivate;
  891. LPUIPRIV lpUIPrivate;
  892. if (GetWindowLong(hCandWnd, UI_MOVE_OFFSET) != WINDOW_NOT_DRAG) {
  893. // undo the drag border
  894. DrawDragBorder(hCandWnd,
  895. GetWindowLong(hCandWnd, UI_MOVE_XY),
  896. GetWindowLong(hCandWnd, UI_MOVE_OFFSET));
  897. }
  898. hUIPrivate = (HGLOBAL)GetWindowLongPtr(GetWindow(hCandWnd, GW_OWNER),
  899. IMMGWLP_PRIVATE);
  900. if (!hUIPrivate) { // can not darw candidate window
  901. return;
  902. }
  903. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  904. if (!lpUIPrivate) { // can not draw candidate window
  905. return;
  906. }
  907. lpUIPrivate->nShowCandCmd = SW_HIDE;
  908. lpUIPrivate->hCandWnd = (HWND)NULL;
  909. GlobalUnlock(hUIPrivate);
  910. return;
  911. }
  912. /**********************************************************************/
  913. /* MouseSelectCandStr() */
  914. /**********************************************************************/
  915. void PASCAL MouseSelectCandStr(
  916. #if defined(UNIIME)
  917. LPINSTDATAL lpInstL,
  918. LPIMEL lpImeL,
  919. #endif
  920. HWND hCandWnd,
  921. LPPOINT lpCursor)
  922. {
  923. HIMC hIMC;
  924. LPINPUTCONTEXT lpIMC;
  925. LPCANDIDATEINFO lpCandInfo;
  926. LPCANDIDATELIST lpCandList;
  927. DWORD dwValue;
  928. hIMC = (HIMC)GetWindowLongPtr(GetWindow(hCandWnd, GW_OWNER), IMMGWLP_IMC);
  929. if (!hIMC) {
  930. return;
  931. }
  932. lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
  933. if (!lpIMC) {
  934. return;
  935. }
  936. if (!lpIMC->hCandInfo) {
  937. ImmUnlockIMC(hIMC);
  938. return;
  939. }
  940. lpCandInfo = (LPCANDIDATEINFO)ImmLockIMCC(lpIMC->hCandInfo);
  941. if (!lpCandInfo) {
  942. ImmUnlockIMC(hIMC);
  943. return;
  944. }
  945. dwValue = (lpCursor->y - lpImeL->rcCandText.top) / sImeG.yChiCharHi;
  946. lpCandList = (LPCANDIDATELIST)((LPBYTE)lpCandInfo +
  947. lpCandInfo->dwOffset[0]);
  948. dwValue = dwValue + lpCandList->dwPageStart;
  949. if (dwValue >= lpCandList->dwCount) {
  950. // invalid choice
  951. MessageBeep((UINT)-1);
  952. } else {
  953. #if defined(UNIIME)
  954. UniNotifyIME(lpInstL, lpImeL, hIMC, NI_SELECTCANDIDATESTR,
  955. 0, dwValue);
  956. #else
  957. NotifyIME(hIMC, NI_SELECTCANDIDATESTR, 0, dwValue);
  958. #endif
  959. }
  960. ImmUnlockIMCC(lpIMC->hCandInfo);
  961. ImmUnlockIMC(hIMC);
  962. return;
  963. }
  964. /**********************************************************************/
  965. /* CandSetCursor() */
  966. /**********************************************************************/
  967. void PASCAL CandSetCursor(
  968. #if defined(UNIIME)
  969. LPINSTDATAL lpInstL,
  970. LPIMEL lpImeL,
  971. #endif
  972. HWND hCandWnd,
  973. LPARAM lParam)
  974. {
  975. POINT ptCursor, ptSavCursor;
  976. RECT rcWnd;
  977. if (GetWindowLong(hCandWnd, UI_MOVE_OFFSET) !=
  978. WINDOW_NOT_DRAG) {
  979. SetCursor(LoadCursor(NULL, IDC_SIZEALL));
  980. return;
  981. }
  982. GetCursorPos(&ptCursor);
  983. ptSavCursor = ptCursor;
  984. ScreenToClient(hCandWnd, &ptCursor);
  985. if (PtInRect(&lpImeL->rcCandText, ptCursor)) {
  986. SetCursor(LoadCursor(hInst, MAKEINTRESOURCE(IDCR_HAND_CURSOR)));
  987. if (HIWORD(lParam) == WM_LBUTTONDOWN) {
  988. MouseSelectCandStr(
  989. #if defined(UNIIME)
  990. lpInstL, lpImeL,
  991. #endif
  992. hCandWnd, &ptCursor);
  993. }
  994. return;
  995. } else if (PtInRect(&lpImeL->rcCandPageUp, ptCursor)) {
  996. if (HIWORD(lParam) != WM_LBUTTONDOWN) {
  997. SetCursor(LoadCursor(hInst, MAKEINTRESOURCE(IDCR_HAND_CURSOR)));
  998. return;
  999. }
  1000. if (MouseSelectCandPage(
  1001. #if defined(UNIIME)
  1002. lpImeL,
  1003. #endif
  1004. hCandWnd, CHOOSE_PREVPAGE)) {
  1005. return;
  1006. }
  1007. SetCursor(LoadCursor(NULL, IDC_SIZEALL));
  1008. } else if (PtInRect(&lpImeL->rcCandPageDn, ptCursor)) {
  1009. if (HIWORD(lParam) != WM_LBUTTONDOWN) {
  1010. SetCursor(LoadCursor(hInst, MAKEINTRESOURCE(IDCR_HAND_CURSOR)));
  1011. return;
  1012. }
  1013. if (MouseSelectCandPage(
  1014. #if defined(UNIIME)
  1015. lpImeL,
  1016. #endif
  1017. hCandWnd, CHOOSE_NEXTPAGE)) {
  1018. return;
  1019. }
  1020. SetCursor(LoadCursor(NULL, IDC_SIZEALL));
  1021. } else {
  1022. SetCursor(LoadCursor(NULL, IDC_SIZEALL));
  1023. if (HIWORD(lParam) == WM_LBUTTONDOWN) {
  1024. // start drag
  1025. SystemParametersInfo(SPI_GETWORKAREA, 0, &sImeG.rcWorkArea, 0);
  1026. } else {
  1027. return;
  1028. }
  1029. }
  1030. SetCapture(hCandWnd);
  1031. SetWindowLong(hCandWnd, UI_MOVE_XY,
  1032. MAKELONG(ptSavCursor.x, ptSavCursor.y));
  1033. GetWindowRect(hCandWnd, &rcWnd);
  1034. SetWindowLong(hCandWnd, UI_MOVE_OFFSET,
  1035. MAKELONG(ptSavCursor.x - rcWnd.left, ptSavCursor.y - rcWnd.top));
  1036. DrawDragBorder(hCandWnd, MAKELONG(ptSavCursor.x, ptSavCursor.y),
  1037. GetWindowLong(hCandWnd, UI_MOVE_OFFSET));
  1038. return;
  1039. }
  1040. /**********************************************************************/
  1041. /* CandButtonUp() */
  1042. /**********************************************************************/
  1043. BOOL PASCAL CandButtonUp(
  1044. #if defined(UNIIME)
  1045. LPIMEL lpImeL,
  1046. #endif
  1047. HWND hCandWnd)
  1048. {
  1049. LONG lTmpCursor, lTmpOffset;
  1050. POINT pt;
  1051. HWND hUIWnd;
  1052. HIMC hIMC;
  1053. LPINPUTCONTEXT lpIMC;
  1054. if (GetWindowLong(hCandWnd, UI_MOVE_OFFSET) == WINDOW_NOT_DRAG) {
  1055. return (FALSE);
  1056. }
  1057. lTmpCursor = GetWindowLong(hCandWnd, UI_MOVE_XY);
  1058. // calculate the org by the offset
  1059. lTmpOffset = GetWindowLong(hCandWnd, UI_MOVE_OFFSET);
  1060. pt.x = (*(LPPOINTS)&lTmpCursor).x - (*(LPPOINTS)&lTmpOffset).x;
  1061. pt.y = (*(LPPOINTS)&lTmpCursor).y - (*(LPPOINTS)&lTmpOffset).y;
  1062. DrawDragBorder(hCandWnd, lTmpCursor, lTmpOffset);
  1063. SetWindowLong(hCandWnd, UI_MOVE_OFFSET, WINDOW_NOT_DRAG);
  1064. ReleaseCapture();
  1065. hUIWnd = GetWindow(hCandWnd, GW_OWNER);
  1066. hIMC = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC);
  1067. if (!hIMC) {
  1068. return (FALSE);
  1069. }
  1070. lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
  1071. if (!lpIMC) {
  1072. return (FALSE);
  1073. }
  1074. AdjustCandBoundry(
  1075. #if defined(UNIIME)
  1076. lpImeL,
  1077. #endif
  1078. &pt);
  1079. ScreenToClient(lpIMC->hWnd, &pt);
  1080. lpIMC->cfCandForm[0].dwStyle = CFS_CANDIDATEPOS;
  1081. lpIMC->cfCandForm[0].ptCurrentPos = pt;
  1082. ImmUnlockIMC(hIMC);
  1083. PostMessage(hCandWnd, WM_IME_NOTIFY, IMN_SETCANDIDATEPOS, 0x0001);
  1084. return (TRUE);
  1085. }
  1086. /**********************************************************************/
  1087. /* PaintCandPage() */
  1088. /**********************************************************************/
  1089. void PASCAL PaintCandPage(
  1090. #if defined(UNIIME)
  1091. LPIMEL lpImeL,
  1092. #endif
  1093. HDC hDC,
  1094. UINT uCandMode,
  1095. LPCANDIDATELIST lpCandList)
  1096. {
  1097. HBITMAP hCandPromptBmp;
  1098. HBITMAP hPageUpBmp, hPageDnBmp, hOldBmp;
  1099. HDC hMemDC;
  1100. hMemDC = CreateCompatibleDC(hDC);
  1101. if ( hMemDC == NULL )
  1102. return;
  1103. if (uCandMode == CAND_PROMPT_PHRASE) {
  1104. hCandPromptBmp = LoadBitmap(hInst,
  1105. MAKEINTRESOURCE(IDBM_CAND_PROMPT_PHRASE));
  1106. #if defined(WINAR30)
  1107. } else if (uCandMode == CAND_PROMPT_QUICK_VIEW) {
  1108. hCandPromptBmp = LoadBitmap(hInst,
  1109. MAKEINTRESOURCE(IDBM_CAND_PROMPT_QUICK_VIEW));
  1110. #endif
  1111. } else {
  1112. hCandPromptBmp = LoadBitmap(hInst,
  1113. MAKEINTRESOURCE(IDBM_CAND_PROMPT_NORMAL));
  1114. }
  1115. if ( hCandPromptBmp == NULL )
  1116. {
  1117. DeleteDC(hMemDC);
  1118. return;
  1119. }
  1120. hOldBmp = SelectObject(hMemDC, hCandPromptBmp);
  1121. BitBlt(hDC, lpImeL->rcCandPrompt.left, lpImeL->rcCandPrompt.top,
  1122. lpImeL->rcCandPrompt.right - lpImeL->rcCandPrompt.left,
  1123. lpImeL->rcCandPrompt.bottom - lpImeL->rcCandPrompt.top,
  1124. hMemDC, 0, 0, SRCCOPY);
  1125. if (lpCandList->dwCount <= lpCandList->dwPageSize) {
  1126. goto PaintCandPageOvr;
  1127. }
  1128. if (lpCandList->dwPageStart > 0) {
  1129. hPageUpBmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDBM_PAGEUP_VERT));
  1130. } else {
  1131. hPageUpBmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDBM_NO_PAGEUP_VERT));
  1132. }
  1133. if ( hPageUpBmp == NULL )
  1134. {
  1135. goto PaintCandPageOvr;
  1136. }
  1137. if ((lpCandList->dwPageStart + lpCandList->dwPageSize) <
  1138. lpCandList->dwCount) {
  1139. hPageDnBmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDBM_PAGEDN_VERT));
  1140. } else {
  1141. hPageDnBmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDBM_NO_PAGEDN_VERT));
  1142. }
  1143. if ( hPageDnBmp == NULL )
  1144. {
  1145. DeleteObject(hPageUpBmp);
  1146. goto PaintCandPageOvr;
  1147. }
  1148. SelectObject(hMemDC, hPageUpBmp);
  1149. BitBlt(hDC, lpImeL->rcCandPageUp.left, lpImeL->rcCandPageUp.top,
  1150. lpImeL->rcCandPageUp.right - lpImeL->rcCandPageUp.left,
  1151. lpImeL->rcCandPageUp.bottom - lpImeL->rcCandPageUp.top,
  1152. hMemDC, 0, 0, SRCCOPY);
  1153. SelectObject(hMemDC, hPageDnBmp);
  1154. BitBlt(hDC, lpImeL->rcCandPageDn.left, lpImeL->rcCandPageDn.top,
  1155. lpImeL->rcCandPageDn.right - lpImeL->rcCandPageDn.left,
  1156. lpImeL->rcCandPageDn.bottom - lpImeL->rcCandPageDn.top,
  1157. hMemDC, 0, 0, SRCCOPY);
  1158. SelectObject(hMemDC, hOldBmp);
  1159. DeleteObject(hPageUpBmp);
  1160. DeleteObject(hPageDnBmp);
  1161. PaintCandPageOvr:
  1162. SelectObject(hMemDC, hOldBmp);
  1163. DeleteDC(hMemDC);
  1164. DeleteObject(hCandPromptBmp);
  1165. return;
  1166. }
  1167. /**********************************************************************/
  1168. /* PaintCompWindow() */
  1169. /**********************************************************************/
  1170. void PASCAL PaintCandWindow(
  1171. #if defined(UNIIME)
  1172. LPIMEL lpImeL,
  1173. #endif
  1174. HWND hCandWnd,
  1175. HDC hDC)
  1176. {
  1177. HIMC hIMC;
  1178. LPINPUTCONTEXT lpIMC;
  1179. LPCANDIDATEINFO lpCandInfo;
  1180. LPCANDIDATELIST lpCandList;
  1181. LPPRIVCONTEXT lpImcP;
  1182. HGDIOBJ hOldFont;
  1183. DWORD dwStart, dwEnd;
  1184. UINT uCandMode;
  1185. TCHAR szStrBuf[16];
  1186. int i;
  1187. RECT rcSunken;
  1188. LOGFONT lfFont;
  1189. hIMC = (HIMC)GetWindowLongPtr(GetWindow(hCandWnd, GW_OWNER), IMMGWLP_IMC);
  1190. if (!hIMC) {
  1191. return;
  1192. }
  1193. lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
  1194. if (!lpIMC) {
  1195. return;
  1196. }
  1197. rcSunken = lpImeL->rcCandText;
  1198. rcSunken.left -= lpImeL->cxCandMargin;
  1199. rcSunken.top -= lpImeL->cyCandMargin;
  1200. rcSunken.right += lpImeL->cxCandMargin;
  1201. rcSunken.bottom += lpImeL->cyCandMargin;
  1202. DrawEdge(hDC, &rcSunken, BDR_SUNKENOUTER, BF_RECT);
  1203. if (!lpIMC->hCandInfo) {
  1204. goto UpCandW2UnlockIMC;
  1205. }
  1206. if (!lpIMC->hPrivate) {
  1207. goto UpCandW2UnlockIMC;
  1208. }
  1209. lpCandInfo = (LPCANDIDATEINFO)ImmLockIMCC(lpIMC->hCandInfo);
  1210. if (!lpCandInfo) {
  1211. goto UpCandW2UnlockIMC;
  1212. }
  1213. lpImcP = (LPPRIVCONTEXT)ImmLockIMCC(lpIMC->hPrivate);
  1214. if (!lpImcP) {
  1215. goto UpCandW2UnlockCandInfo;
  1216. }
  1217. hOldFont = GetCurrentObject(hDC, OBJ_FONT);
  1218. GetObject(hOldFont, sizeof(lfFont), &lfFont);
  1219. if (sImeG.fDiffSysCharSet) {
  1220. lfFont.lfCharSet = NATIVE_CHARSET;
  1221. lfFont.lfFaceName[0] = TEXT('\0');
  1222. }
  1223. lfFont.lfWeight = FW_DONTCARE;
  1224. SelectObject(hDC, CreateFontIndirect(&lfFont));
  1225. lpCandList = (LPCANDIDATELIST)((LPBYTE)lpCandInfo +
  1226. lpCandInfo->dwOffset[0]);
  1227. dwStart = lpCandList->dwPageStart;
  1228. dwEnd = dwStart + lpCandList->dwPageSize;
  1229. if (dwEnd > lpCandList->dwCount) {
  1230. dwEnd = lpCandList->dwCount;
  1231. }
  1232. if (lpImcP->iImeState == CST_INIT) {
  1233. // phrase prediction
  1234. SetTextColor(hDC, RGB(0x00, 0x80, 0x00));
  1235. uCandMode = CAND_PROMPT_PHRASE;
  1236. #if defined(WINAR30)
  1237. } else if (lpImcP->iImeState != CST_CHOOSE) {
  1238. // quick key
  1239. SetTextColor(hDC, RGB(0x80, 0x00, 0x80));
  1240. uCandMode = CAND_PROMPT_QUICK_VIEW;
  1241. #endif
  1242. } else {
  1243. uCandMode = CAND_PROMPT_NORMAL;
  1244. }
  1245. PaintCandPage(
  1246. #if defined(UNIIME)
  1247. lpImeL,
  1248. #endif
  1249. hDC, uCandMode, lpCandList);
  1250. SetBkColor(hDC, RGB(0xC0, 0xC0, 0xC0));
  1251. ExtTextOut(hDC, lpImeL->rcCandText.left, lpImeL->rcCandText.top,
  1252. ETO_OPAQUE, &lpImeL->rcCandText, NULL, 0, NULL);
  1253. szStrBuf[0] = TEXT('1');
  1254. szStrBuf[1] = TEXT(':');
  1255. for (i = 0; dwStart < dwEnd; dwStart++, i++) {
  1256. LPTSTR lpStr;
  1257. int nCharsInOneStr;
  1258. int nHalfCharsInOneStr; // how many half width chars
  1259. // one full width char ==
  1260. // 2 half width chars
  1261. int nLimit; // the room left to the candidate window
  1262. #ifdef UNICODE
  1263. LPTSTR lpTmpStr;
  1264. int iDx_temp[3 * CANDPERPAGE + 1];
  1265. #endif
  1266. lpStr = (LPTSTR)((LPBYTE)lpCandList + lpCandList->dwOffset[dwStart]);
  1267. // the candidate window width allow 7 + 1 full shape DBCS chars
  1268. // only 8 chars can accomendate the width of three bitmaps.
  1269. nLimit = 16;
  1270. szStrBuf[0] = szDigit[i + lpImeL->wCandStart];
  1271. #ifdef UNICODE
  1272. nCharsInOneStr = 0;
  1273. iDx_temp[nCharsInOneStr++] = sImeG.xChiCharWi / 2;
  1274. iDx_temp[nCharsInOneStr++] = sImeG.xChiCharWi - iDx_temp[0];
  1275. nHalfCharsInOneStr = 2;
  1276. for (lpTmpStr = lpStr; *lpTmpStr; lpTmpStr++, nCharsInOneStr++) {
  1277. if (nHalfCharsInOneStr > nLimit) {
  1278. break;
  1279. } else if (*lpTmpStr < 0x0200) {
  1280. nHalfCharsInOneStr += 1;
  1281. iDx_temp[nCharsInOneStr] = sImeG.xChiCharWi / 2;
  1282. } else {
  1283. nHalfCharsInOneStr += 2;
  1284. iDx_temp[nCharsInOneStr] = sImeG.xChiCharWi;
  1285. }
  1286. }
  1287. #else
  1288. nHalfCharsInOneStr = nCharsInOneStr = lstrlen(lpStr) + 2;
  1289. #endif
  1290. if (nHalfCharsInOneStr <= nLimit) {
  1291. CopyMemory(&szStrBuf[2], lpStr,
  1292. (nCharsInOneStr - 2) * sizeof(TCHAR));
  1293. } else {
  1294. #ifdef UNICODE
  1295. if (lpStr[nCharsInOneStr - 2 - 2] < 0x0200) {
  1296. // we need more room to put ..
  1297. nCharsInOneStr -= 3;
  1298. } else {
  1299. nCharsInOneStr -= 2;
  1300. }
  1301. #else
  1302. nHalfCharsInOneStr = nCharsInOneStr = nLimit - 2;
  1303. #endif
  1304. CopyMemory(&szStrBuf[2], lpStr,
  1305. (nCharsInOneStr - 2) * sizeof(TCHAR));
  1306. #ifdef UNICODE
  1307. // unicode of ..
  1308. iDx_temp[nCharsInOneStr] = sImeG.xChiCharWi;
  1309. szStrBuf[nCharsInOneStr++] = 0x2025;
  1310. #else
  1311. szStrBuf[nCharsInOneStr++] = '.';
  1312. szStrBuf[nCharsInOneStr++] = '.';
  1313. #endif
  1314. }
  1315. #if defined(WINAR30)
  1316. if (nCharsInOneStr <= 2) {
  1317. #ifdef UNICODE
  1318. // add unicode 0x25A1
  1319. *(LPWSTR)&szStrBuf[2] = 0x25A1;
  1320. iDx_temp[2] = sImeG.xChiCharWi;
  1321. #else
  1322. // add big-5 0xA1BC
  1323. *(LPWSTR)&szStrBuf[2] = 0xBCA1;
  1324. #endif
  1325. nCharsInOneStr = 2 + sizeof(WCHAR) / sizeof(TCHAR);
  1326. }
  1327. #endif
  1328. ExtTextOut(hDC, lpImeL->rcCandText.left,
  1329. lpImeL->rcCandText.top + i * sImeG.yChiCharHi,
  1330. (UINT)0, NULL,
  1331. szStrBuf,
  1332. nCharsInOneStr, iDx_temp);
  1333. }
  1334. DeleteObject(SelectObject(hDC, hOldFont));
  1335. ImmUnlockIMCC(lpIMC->hPrivate);
  1336. UpCandW2UnlockCandInfo:
  1337. ImmUnlockIMCC(lpIMC->hCandInfo);
  1338. UpCandW2UnlockIMC:
  1339. ImmUnlockIMC(hIMC);
  1340. return;
  1341. }
  1342. /**********************************************************************/
  1343. /* CandWndProc() */
  1344. /**********************************************************************/
  1345. #if defined(UNIIME)
  1346. LRESULT WINAPI UniCandWndProc(
  1347. LPINSTDATAL lpInstL,
  1348. LPIMEL lpImeL,
  1349. #else
  1350. LRESULT CALLBACK CandWndProc(
  1351. #endif
  1352. HWND hCandWnd,
  1353. UINT uMsg,
  1354. WPARAM wParam,
  1355. LPARAM lParam)
  1356. {
  1357. switch (uMsg) {
  1358. case WM_DESTROY:
  1359. DestroyCandWindow(hCandWnd);
  1360. break;
  1361. case WM_SETCURSOR:
  1362. CandSetCursor(
  1363. #if defined(UNIIME)
  1364. lpInstL, lpImeL,
  1365. #endif
  1366. hCandWnd, lParam);
  1367. break;
  1368. case WM_MOUSEMOVE:
  1369. if (GetWindowLong(hCandWnd, UI_MOVE_OFFSET) != WINDOW_NOT_DRAG) {
  1370. POINT ptCursor;
  1371. DrawDragBorder(hCandWnd,
  1372. GetWindowLong(hCandWnd, UI_MOVE_XY),
  1373. GetWindowLong(hCandWnd, UI_MOVE_OFFSET));
  1374. GetCursorPos(&ptCursor);
  1375. SetWindowLong(hCandWnd, UI_MOVE_XY,
  1376. MAKELONG(ptCursor.x, ptCursor.y));
  1377. DrawDragBorder(hCandWnd, MAKELONG(ptCursor.x, ptCursor.y),
  1378. GetWindowLong(hCandWnd, UI_MOVE_OFFSET));
  1379. } else {
  1380. return DefWindowProc(hCandWnd, uMsg, wParam, lParam);
  1381. }
  1382. break;
  1383. case WM_LBUTTONUP:
  1384. if (!CandButtonUp(
  1385. #if defined(UNIIME)
  1386. lpImeL,
  1387. #endif
  1388. hCandWnd)) {
  1389. return DefWindowProc(hCandWnd, uMsg, wParam, lParam);
  1390. }
  1391. break;
  1392. case WM_IME_NOTIFY:
  1393. if (wParam != IMN_SETCANDIDATEPOS) {
  1394. } else if (lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI) {
  1395. } else if (lParam & 0x0001) {
  1396. return SetCandPosition(
  1397. #if defined(UNIIME)
  1398. lpImeL,
  1399. #endif
  1400. hCandWnd);
  1401. } else {
  1402. }
  1403. break;
  1404. case WM_PAINT:
  1405. {
  1406. HDC hDC;
  1407. PAINTSTRUCT ps;
  1408. hDC = BeginPaint(hCandWnd, &ps);
  1409. PaintCandWindow(
  1410. #if defined(UNIIME)
  1411. lpImeL,
  1412. #endif
  1413. hCandWnd, hDC);
  1414. EndPaint(hCandWnd, &ps);
  1415. }
  1416. break;
  1417. case WM_MOUSEACTIVATE:
  1418. return (MA_NOACTIVATE);
  1419. default:
  1420. return DefWindowProc(hCandWnd, uMsg, wParam, lParam);
  1421. }
  1422. return (0L);
  1423. }
  1424. #endif