Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1170 lines
33 KiB

  1. /*************************************************
  2. * compui.c *
  3. * *
  4. * Copyright (C) 1999 Microsoft Inc. *
  5. * *
  6. *************************************************/
  7. #include <windows.h>
  8. #include <immdev.h>
  9. #include "imeattr.h"
  10. #include "imedefs.h"
  11. /**********************************************************************/
  12. /* GetCompWnd */
  13. /* Return Value : */
  14. /* window handle of composition */
  15. /**********************************************************************/
  16. HWND PASCAL GetCompWnd(
  17. HWND hUIWnd) // UI window
  18. {
  19. HGLOBAL hUIPrivate;
  20. LPUIPRIV lpUIPrivate;
  21. HWND hCompWnd;
  22. hUIPrivate = (HGLOBAL)GetWindowLongPtr(hUIWnd, IMMGWLP_PRIVATE);
  23. if (!hUIPrivate) { // can not darw candidate window
  24. return (HWND)NULL;
  25. }
  26. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  27. if (!lpUIPrivate) { // can not draw candidate window
  28. return (HWND)NULL;
  29. }
  30. hCompWnd = lpUIPrivate->hCompWnd;
  31. GlobalUnlock(hUIPrivate);
  32. return (hCompWnd);
  33. }
  34. /**********************************************************************/
  35. /* GetNearCaretPosition() */
  36. /**********************************************************************/
  37. void PASCAL GetNearCaretPosition( // decide a near caret position according
  38. // to the caret position
  39. LPPOINT lpptFont,
  40. UINT uEsc,
  41. UINT uRot,
  42. LPPOINT lpptCaret,
  43. LPPOINT lpptNearCaret,
  44. BOOL fFlags)
  45. {
  46. LONG lFontSize;
  47. LONG xWidthUI, yHeightUI, xBorder, yBorder;
  48. #ifdef IDEBUG
  49. _DebugOut(DEB_WARNING, "caret position, x - %d, y - %d",
  50. lpptCaret->x, lpptCaret->y);
  51. #endif
  52. if ((uEsc + uRot) & 0x0001) {
  53. lFontSize = lpptFont->x;
  54. } else {
  55. lFontSize = lpptFont->y;
  56. }
  57. if (fFlags & NEAR_CARET_CANDIDATE) {
  58. xWidthUI = lpImeL->xCandWi;
  59. yHeightUI = lpImeL->yCandHi;
  60. xBorder = lpImeL->cxCandBorder;
  61. yBorder = lpImeL->cyCandBorder;
  62. } else {
  63. xWidthUI = lpImeL->xCompWi;
  64. yHeightUI = lpImeL->yCompHi;
  65. xBorder = lpImeL->cxCompBorder;
  66. yBorder = lpImeL->cyCompBorder;
  67. }
  68. if (fFlags & NEAR_CARET_FIRST_TIME) {
  69. lpptNearCaret->x = lpptCaret->x +
  70. lFontSize * ncUIEsc[uEsc].iLogFontFacX +
  71. sImeG.iPara * ncUIEsc[uEsc].iParaFacX +
  72. sImeG.iPerp * ncUIEsc[uEsc].iPerpFacX;
  73. if (ptInputEsc[uEsc].x >= 0) {
  74. lpptNearCaret->x += xBorder * 2;
  75. } else {
  76. lpptNearCaret->x -= xWidthUI - xBorder * 2;
  77. }
  78. lpptNearCaret->y = lpptCaret->y +
  79. lFontSize * ncUIEsc[uEsc].iLogFontFacY +
  80. sImeG.iPara * ncUIEsc[uEsc].iParaFacY +
  81. sImeG.iPerp * ncUIEsc[uEsc].iPerpFacY;
  82. if (ptInputEsc[uEsc].y >= 0) {
  83. lpptNearCaret->y += yBorder * 2;
  84. } else {
  85. lpptNearCaret->y -= yHeightUI - yBorder * 2;
  86. }
  87. } else {
  88. lpptNearCaret->x = lpptCaret->x +
  89. lFontSize * ncAltUIEsc[uEsc].iLogFontFacX +
  90. sImeG.iPara * ncAltUIEsc[uEsc].iParaFacX +
  91. sImeG.iPerp * ncAltUIEsc[uEsc].iPerpFacX;
  92. if (ptAltInputEsc[uEsc].x >= 0) {
  93. lpptNearCaret->x += xBorder * 2;
  94. } else {
  95. lpptNearCaret->x -= xWidthUI - xBorder * 2;
  96. }
  97. lpptNearCaret->y = lpptCaret->y +
  98. lFontSize * ncAltUIEsc[uEsc].iLogFontFacY +
  99. sImeG.iPara * ncAltUIEsc[uEsc].iParaFacY +
  100. sImeG.iPerp * ncAltUIEsc[uEsc].iPerpFacY;
  101. if (ptAltInputEsc[uEsc].y >= 0) {
  102. lpptNearCaret->y += yBorder * 2;
  103. } else {
  104. lpptNearCaret->y -= yHeightUI - yBorder * 2;
  105. }
  106. }
  107. if (lpptNearCaret->x < sImeG.rcWorkArea.left) {
  108. lpptNearCaret->x = sImeG.rcWorkArea.left;
  109. } else if (lpptNearCaret->x + xWidthUI > sImeG.rcWorkArea.right) {
  110. lpptNearCaret->x = sImeG.rcWorkArea.right - xWidthUI;
  111. } else {
  112. }
  113. if (lpptNearCaret->y < sImeG.rcWorkArea.top) {
  114. lpptNearCaret->y = sImeG.rcWorkArea.top;
  115. } else if (lpptNearCaret->y + yHeightUI > sImeG.rcWorkArea.bottom) {
  116. lpptNearCaret->y = sImeG.rcWorkArea.bottom - yHeightUI;
  117. } else {
  118. }
  119. #ifdef IDEBUG
  120. _DebugOut(DEB_WARNING, "Near caret position, x - %d, y - %d",
  121. lpptNearCaret->x, lpptNearCaret->y);
  122. #endif
  123. return;
  124. }
  125. /**********************************************************************/
  126. /* FitInLazyOperation() */
  127. /* Return Value : */
  128. /* TRUE or FALSE */
  129. /**********************************************************************/
  130. BOOL PASCAL FitInLazyOperation( // fit in lazy operation or not
  131. LPPOINT lpptOrg,
  132. LPPOINT lpptNearCaret, // the suggested near caret position
  133. LPRECT lprcInputRect,
  134. UINT uEsc)
  135. {
  136. POINT ptDelta, ptTol;
  137. RECT rcUIRect, rcInterRect;
  138. ptDelta.x = lpptOrg->x - lpptNearCaret->x;
  139. ptDelta.x = (ptDelta.x >= 0) ? ptDelta.x : -ptDelta.x;
  140. ptTol.x = sImeG.iParaTol * ncUIEsc[uEsc].iParaFacX +
  141. sImeG.iPerpTol * ncUIEsc[uEsc].iPerpFacX;
  142. ptTol.x = (ptTol.x >= 0) ? ptTol.x : -ptTol.x;
  143. if (ptDelta.x > ptTol.x) {
  144. return (FALSE);
  145. }
  146. ptDelta.y = lpptOrg->y - lpptNearCaret->y;
  147. ptDelta.y = (ptDelta.y >= 0) ? ptDelta.y : -ptDelta.y;
  148. ptTol.y = sImeG.iParaTol * ncUIEsc[uEsc].iParaFacY +
  149. sImeG.iPerpTol * ncUIEsc[uEsc].iPerpFacY;
  150. ptTol.y = (ptTol.y >= 0) ? ptTol.y : -ptTol.y;
  151. if (ptDelta.y > ptTol.y) {
  152. return (FALSE);
  153. }
  154. // build up the UI rectangle (composition window)
  155. rcUIRect.left = lpptOrg->x;
  156. rcUIRect.top = lpptOrg->y;
  157. rcUIRect.right = rcUIRect.left + lpImeL->xCompWi;
  158. rcUIRect.bottom = rcUIRect.top + lpImeL->yCompHi;
  159. if (IntersectRect(&rcInterRect, &rcUIRect, lprcInputRect)) {
  160. return (FALSE);
  161. }
  162. return (TRUE);
  163. }
  164. /**********************************************************************/
  165. /* AdjustCompPosition() */
  166. /* Return Value : */
  167. /* the position of composition window is changed or not */
  168. /**********************************************************************/
  169. BOOL PASCAL AdjustCompPosition( // IME adjust position according to
  170. // composition form
  171. LPINPUTCONTEXT lpIMC,
  172. LPPOINT lpptOrg, // original composition window
  173. // and final position
  174. LPPOINT lpptNew) // new expect position
  175. {
  176. POINT ptNearCaret, ptOldNearCaret, ptCompWnd;
  177. UINT uEsc, uRot;
  178. RECT rcUIRect, rcInputRect, rcInterRect;
  179. POINT ptFont;
  180. #ifdef IDEBUG
  181. _DebugOut(DEB_WARNING, "Original Position, x - %d, y - %d",
  182. lpptOrg->x, lpptOrg->y);
  183. _DebugOut(DEB_WARNING, "New Position, x - %d, y - %d",
  184. lpptNew->x, lpptNew->y);
  185. #endif
  186. // we need to adjust according to font attribute
  187. if (lpIMC->lfFont.A.lfWidth > 0) {
  188. ptFont.x = lpIMC->lfFont.A.lfWidth * 2;
  189. } else if (lpIMC->lfFont.A.lfWidth < 0) {
  190. ptFont.x = -lpIMC->lfFont.A.lfWidth * 2;
  191. } else if (lpIMC->lfFont.A.lfHeight > 0) {
  192. ptFont.x = lpIMC->lfFont.A.lfHeight;
  193. } else if (lpIMC->lfFont.A.lfHeight < 0) {
  194. ptFont.x = -lpIMC->lfFont.A.lfHeight;
  195. } else {
  196. ptFont.x = lpImeL->yCompHi;
  197. }
  198. if (lpIMC->lfFont.A.lfHeight > 0) {
  199. ptFont.y = lpIMC->lfFont.A.lfHeight;
  200. } else if (lpIMC->lfFont.A.lfHeight < 0) {
  201. ptFont.y = -lpIMC->lfFont.A.lfHeight;
  202. } else {
  203. ptFont.y = ptFont.x;
  204. }
  205. #ifdef IDEBUG
  206. _DebugOut(DEB_WARNING, "All positve, x - %d, y - %d",
  207. ptFont.x, ptFont.y);
  208. #endif
  209. // if the input char is too big, we don't need to consider so much
  210. if (ptFont.x > lpImeL->yCompHi * 8) {
  211. ptFont.x = lpImeL->yCompHi * 8;
  212. }
  213. if (ptFont.y > lpImeL->yCompHi * 8) {
  214. ptFont.y = lpImeL->yCompHi * 8;
  215. }
  216. if (ptFont.x < sImeG.xChiCharWi) {
  217. ptFont.x = sImeG.xChiCharWi;
  218. }
  219. if (ptFont.y < sImeG.yChiCharHi) {
  220. ptFont.y = sImeG.yChiCharHi;
  221. }
  222. #ifdef IDEBUG
  223. _DebugOut(DEB_WARNING, "Not too large or too samll, x - %d, y - %d",
  224. ptFont.x, ptFont.y);
  225. #endif
  226. // -450 to 450 index 0
  227. // 450 to 1350 index 1
  228. // 1350 to 2250 index 2
  229. // 2250 to 3150 index 3
  230. uEsc = (UINT)((lpIMC->lfFont.A.lfEscapement + 450) / 900 % 4);
  231. uRot = (UINT)((lpIMC->lfFont.A.lfOrientation + 450) / 900 % 4);
  232. // decide the input rectangle
  233. rcInputRect.left = lpptNew->x;
  234. rcInputRect.top = lpptNew->y;
  235. // build up an input rectangle from escapemment
  236. rcInputRect.right = rcInputRect.left + ptFont.x * ptInputEsc[uEsc].x;
  237. rcInputRect.bottom = rcInputRect.top + ptFont.y * ptInputEsc[uEsc].y;
  238. // be a normal rectangle, not a negative rectangle
  239. if (rcInputRect.left > rcInputRect.right) {
  240. LONG tmp;
  241. tmp = rcInputRect.left;
  242. rcInputRect.left = rcInputRect.right;
  243. rcInputRect.right = tmp;
  244. }
  245. if (rcInputRect.top > rcInputRect.bottom) {
  246. LONG tmp;
  247. tmp = rcInputRect.top;
  248. rcInputRect.top = rcInputRect.bottom;
  249. rcInputRect.bottom = tmp;
  250. }
  251. #ifdef IDEBUG
  252. _DebugOut(DEB_WARNING, "Input Rect, top - %d, left - %d, bottom %d, right - %d",
  253. rcInputRect.top, rcInputRect.left, rcInputRect.bottom, rcInputRect.right);
  254. #endif
  255. GetNearCaretPosition(
  256. &ptFont, uEsc, uRot, lpptNew, &ptNearCaret, NEAR_CARET_FIRST_TIME);
  257. // 1st, use the adjust point
  258. // build up the new suggest UI rectangle (composition window)
  259. rcUIRect.left = ptNearCaret.x;
  260. rcUIRect.top = ptNearCaret.y;
  261. rcUIRect.right = rcUIRect.left + lpImeL->xCompWi;
  262. rcUIRect.bottom = rcUIRect.top + lpImeL->yCompHi;
  263. #ifdef IDEBUG
  264. _DebugOut(DEB_WARNING, "Near caret UI Rect, top - %d, left - %d, bottom %d, right - %d",
  265. rcUIRect.top, rcUIRect.left, rcUIRect.bottom, rcUIRect.right);
  266. #endif
  267. ptCompWnd = ptOldNearCaret = ptNearCaret;
  268. // OK, no intersect between the near caret position and input char
  269. if (IntersectRect(&rcInterRect, &rcUIRect, &rcInputRect)) {
  270. } else if (FitInLazyOperation(
  271. lpptOrg, &ptNearCaret, &rcInputRect, uEsc)) {
  272. #ifdef IDEBUG
  273. _DebugOut(DEB_WARNING, "Fit in lazy operation");
  274. #endif
  275. // happy ending!!!, don't chaqge position
  276. return (FALSE);
  277. } else {
  278. #ifdef IDEBUG
  279. _DebugOut(DEB_WARNING, "Go to adjust point");
  280. #endif
  281. *lpptOrg = ptNearCaret;
  282. // happy ending!!
  283. return (TRUE);
  284. }
  285. // unhappy case
  286. GetNearCaretPosition(
  287. &ptFont, uEsc, uRot, lpptNew, &ptNearCaret, 0);
  288. // build up the new suggest UI rectangle (composition window)
  289. rcUIRect.left = ptNearCaret.x;
  290. rcUIRect.top = ptNearCaret.y;
  291. rcUIRect.right = rcUIRect.left + lpImeL->xCompWi;
  292. rcUIRect.bottom = rcUIRect.top + lpImeL->yCompHi;
  293. #ifdef IDEBUG
  294. _DebugOut(DEB_WARNING, "Another NearCaret UI Rect, top - %d, left - %d, bottom %d, right - %d",
  295. rcUIRect.top, rcUIRect.left, rcUIRect.bottom, rcUIRect.right);
  296. #endif
  297. ptCompWnd = ptNearCaret;
  298. // OK, no intersect between the adjust position and input char
  299. if (IntersectRect(&rcInterRect, &rcUIRect, &rcInputRect)) {
  300. } else if (FitInLazyOperation(
  301. lpptOrg, &ptNearCaret, &rcInputRect, uEsc)) {
  302. #ifdef IDEBUG
  303. _DebugOut(DEB_WARNING, "Fit in Another lazy operation");
  304. #endif
  305. // happy ending!!!, don't chaqge position
  306. return (FALSE);
  307. } else {
  308. #ifdef IDEBUG
  309. _DebugOut(DEB_WARNING, "Go to Another near caret point");
  310. #endif
  311. *lpptOrg = ptNearCaret;
  312. // happy ending!!
  313. return (TRUE);
  314. }
  315. // unhappy ending! :-(
  316. *lpptOrg = ptOldNearCaret;
  317. return (TRUE);
  318. }
  319. /**********************************************************************/
  320. /* SetCompPosition() */
  321. /**********************************************************************/
  322. void PASCAL SetCompPosition( // set the composition window position
  323. HWND hCompWnd,
  324. LPINPUTCONTEXT lpIMC)
  325. {
  326. POINT ptWnd;
  327. BOOL fChange = FALSE;
  328. HWND hCandWnd;
  329. //
  330. // the client coordinate position (0, 0) of composition window
  331. //
  332. ptWnd.x = 0;
  333. ptWnd.y = 0;
  334. //
  335. // convert to screen coordinates
  336. //
  337. ClientToScreen(hCompWnd, &ptWnd);
  338. ptWnd.x -= lpImeL->cxCompBorder;
  339. ptWnd.y -= lpImeL->cyCompBorder;
  340. if (lpIMC->cfCompForm.dwStyle & CFS_FORCE_POSITION)
  341. {
  342. POINT ptNew; // new position of UI
  343. ptNew = lpIMC->cfCompForm.ptCurrentPos;
  344. ClientToScreen((HWND)lpIMC->hWnd, &ptNew);
  345. if (ptWnd.x != ptNew.x)
  346. {
  347. ptWnd.x = ptNew.x;
  348. fChange = TRUE;
  349. }
  350. if (ptWnd.y != ptNew.y)
  351. {
  352. ptWnd.y = ptNew.y;
  353. fChange = TRUE;
  354. }
  355. if (fChange)
  356. {
  357. ptWnd.x -= lpImeL->cxCompBorder;
  358. ptWnd.y -= lpImeL->cyCompBorder;
  359. }
  360. }
  361. else if (lpIMC->cfCompForm.dwStyle != CFS_DEFAULT)
  362. {
  363. //
  364. // aplication tell us the position, we need to adjust
  365. //
  366. POINT ptNew; // new position of UI
  367. ptNew = lpIMC->cfCompForm.ptCurrentPos;
  368. ClientToScreen((HWND)lpIMC->hWnd, &ptNew);
  369. fChange = AdjustCompPosition(
  370. lpIMC, &ptWnd, &ptNew);
  371. }
  372. else
  373. {
  374. POINT ptNew; // new position of UI
  375. ptNew.x = lpIMC->ptStatusWndPos.x + lpImeL->xStatusWi + UI_MARGIN;
  376. if (ptNew.x + lpImeL->xCompWi > sImeG.rcWorkArea.right)
  377. {
  378. ptNew.x = lpIMC->ptStatusWndPos.x -
  379. lpImeL->xCompWi - lpImeL->cxCompBorder * 2 -
  380. UI_MARGIN;
  381. }
  382. ptNew.y = sImeG.rcWorkArea.bottom - lpImeL->yCompHi - 2 * UI_MARGIN;
  383. if (ptWnd.x != ptNew.x)
  384. {
  385. ptWnd.x = ptNew.x;
  386. fChange = TRUE;
  387. }
  388. if (ptWnd.y != ptNew.y)
  389. {
  390. ptWnd.y = ptNew.y;
  391. fChange = TRUE;
  392. }
  393. if (fChange)
  394. {
  395. lpIMC->cfCompForm.ptCurrentPos = ptNew;
  396. ScreenToClient(lpIMC->hWnd, &lpIMC->cfCompForm.ptCurrentPos);
  397. }
  398. }
  399. if (!fChange)
  400. {
  401. return;
  402. }
  403. SetWindowPos(hCompWnd,
  404. NULL,
  405. ptWnd.x,
  406. ptWnd.y,
  407. 0,
  408. 0,
  409. SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER);
  410. if (lpIMC->cfCandForm[0].dwIndex == 0)
  411. {
  412. //
  413. // application the candidate position by itself
  414. //
  415. return;
  416. }
  417. ScreenToClient(lpIMC->hWnd, &ptWnd);
  418. lpIMC->cfCandForm[0].dwStyle = CFS_CANDIDATEPOS;
  419. lpIMC->cfCandForm[0].ptCurrentPos = ptWnd;
  420. return;
  421. }
  422. /**********************************************************************/
  423. /* SetCompWindow() */
  424. /**********************************************************************/
  425. void PASCAL SetCompWindow( // set the position of composition window
  426. HWND hCompWnd)
  427. {
  428. HIMC hIMC;
  429. LPINPUTCONTEXT lpIMC;
  430. HWND hUIWnd;
  431. hUIWnd = GetWindow(hCompWnd, GW_OWNER);
  432. if (!hUIWnd) {
  433. return;
  434. }
  435. hIMC = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC);
  436. if (!hIMC) {
  437. return;
  438. }
  439. lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
  440. if (!lpIMC) {
  441. return;
  442. }
  443. SetCompPosition(
  444. hCompWnd, lpIMC);
  445. ImmUnlockIMC(hIMC);
  446. return;
  447. }
  448. /**********************************************************************/
  449. /* MoveDefaultCompPosition() */
  450. /**********************************************************************/
  451. void PASCAL MoveDefaultCompPosition( // the default comp position
  452. // need to near the caret
  453. HWND hUIWnd)
  454. {
  455. HIMC hIMC;
  456. LPINPUTCONTEXT lpIMC;
  457. HWND hCompWnd;
  458. hIMC = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC);
  459. if (!hIMC)
  460. {
  461. return;
  462. }
  463. hCompWnd = GetCompWnd(hUIWnd);
  464. if (!hCompWnd)
  465. {
  466. return;
  467. }
  468. lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
  469. if (!lpIMC)
  470. {
  471. return;
  472. }
  473. if (!(lpIMC->cfCompForm.dwStyle & CFS_FORCE_POSITION))
  474. {
  475. SetCompPosition( hCompWnd, lpIMC);
  476. }
  477. ImmUnlockIMC(hIMC);
  478. return;
  479. }
  480. /**********************************************************************/
  481. /* ShowComp() */
  482. /**********************************************************************/
  483. void PASCAL ShowComp( // Show the composition window
  484. HWND hUIWnd,
  485. int nShowCompCmd)
  486. {
  487. HGLOBAL hUIPrivate;
  488. LPUIPRIV lpUIPrivate;
  489. // show or hid the UI window
  490. hUIPrivate = (HGLOBAL)GetWindowLongPtr(hUIWnd, IMMGWLP_PRIVATE);
  491. if (!hUIPrivate) {
  492. return;
  493. }
  494. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  495. if (!lpUIPrivate) {
  496. return;
  497. }
  498. if (lpUIPrivate->nShowCompCmd == nShowCompCmd) {
  499. goto SwCompNoChange;
  500. }
  501. if (nShowCompCmd == SW_HIDE) {
  502. lpUIPrivate->fdwSetContext &= ~(ISC_HIDE_COMP_WINDOW);
  503. }
  504. if (!lpUIPrivate->hCompWnd) {
  505. // not in show candidate window mode
  506. /*
  507. } else if (lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI) {
  508. int nCurrShowState;
  509. lpUIPrivate->nShowCompCmd = nShowCompCmd;
  510. nCurrShowState = lpUIPrivate->nShowStatusCmd;
  511. nCurrShowState |= lpUIPrivate->nShowCandCmd;
  512. if (nCurrShowState == SW_HIDE) {
  513. // if other two are hide, the current show state is determined
  514. // by this composition section
  515. ShowWindow(lpUIPrivate->hCompWnd, lpUIPrivate->nShowCompCmd);
  516. } else {
  517. RECT rcRect;
  518. rcRect = lpImeL->rcCompText;
  519. // off by 1
  520. rcRect.right += 1;
  521. rcRect.bottom += 1;
  522. RedrawWindow(lpUIPrivate->hCompWnd, &rcRect, NULL,
  523. RDW_INVALIDATE);
  524. }
  525. */
  526. } else {
  527. ShowWindow(lpUIPrivate->hCompWnd, nShowCompCmd);
  528. lpUIPrivate->nShowCompCmd = nShowCompCmd;
  529. }
  530. SwCompNoChange:
  531. GlobalUnlock(hUIPrivate);
  532. return;
  533. }
  534. /**********************************************************************/
  535. /* CreateCompWindow() */
  536. /**********************************************************************/
  537. void PASCAL CreateCompWindow(
  538. HWND hUIWnd)
  539. {
  540. HIMC hIMC;
  541. HGLOBAL hUIPrivate;
  542. LPINPUTCONTEXT lpIMC;
  543. LPUIPRIV lpUIPrivate;
  544. LPPRIVCONTEXT lpImcP;
  545. DWORD fdwImeMsg;
  546. hUIPrivate = (HGLOBAL)GetWindowLongPtr(hUIWnd, IMMGWLP_PRIVATE);
  547. if (!hUIPrivate)
  548. {
  549. return;
  550. }
  551. hIMC = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC);
  552. if (!hIMC)
  553. {
  554. return;
  555. }
  556. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  557. if (!lpUIPrivate)
  558. {
  559. return;
  560. }
  561. lpUIPrivate->fdwSetContext |= ISC_SHOWUICOMPOSITIONWINDOW;
  562. lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
  563. if (!lpIMC)
  564. {
  565. goto StartCompUnlockUIPriv;
  566. }
  567. fdwImeMsg = 0;
  568. lpImcP = (LPPRIVCONTEXT)ImmLockIMCC(lpIMC->hPrivate);
  569. if (lpImcP)
  570. {
  571. fdwImeMsg = lpImcP->fdwImeMsg;
  572. ImmUnlockIMCC(lpIMC->hPrivate);
  573. }
  574. #if 0
  575. //
  576. // We want to create comp window when IME starts. So the following
  577. // is not good.
  578. //
  579. if (!(fdwImeMsg & MSG_ALREADY_START))
  580. {
  581. //
  582. // Sometime the application call ImmNotifyIME to cancel the
  583. // composition before it process WM_IME_STARTCOMPOSITION.
  584. // We should avoid to process this kind of WM_IME_STARTCOMPOSITION.
  585. //
  586. goto StartCompUnlockIMC;
  587. }
  588. #endif
  589. if (!lpUIPrivate->hCompWnd)
  590. {
  591. POINT ptNew;
  592. ptNew = lpIMC->cfCompForm.ptCurrentPos;
  593. ClientToScreen((HWND)lpIMC->hWnd, &ptNew);
  594. lpUIPrivate->hCompWnd = CreateWindowEx(0,
  595. lpImeL->szCompClassName, NULL,
  596. WS_POPUP|WS_DISABLED|WS_BORDER,
  597. ptNew.x, ptNew.y, lpImeL->xCompWi, lpImeL->yCompHi,
  598. hUIWnd, (HMENU)NULL, lpInstL->hInst, NULL);
  599. SetWindowLong(lpUIPrivate->hCompWnd, UI_MOVE_OFFSET, WINDOW_NOT_DRAG);
  600. SetWindowLong(lpUIPrivate->hCompWnd, UI_MOVE_XY, lpImeL->nRevMaxKey);
  601. }
  602. //
  603. // try to set the position of composition UI window near the caret
  604. //
  605. SetCompPosition( lpUIPrivate->hCompWnd, lpIMC);
  606. ShowComp(hUIWnd, SW_SHOWNOACTIVATE);
  607. ImmUnlockIMC(hIMC);
  608. StartCompUnlockUIPriv:
  609. GlobalUnlock(hUIPrivate);
  610. return;
  611. }
  612. #if 0
  613. //
  614. // For unicode ime, we always keep the composition windows displayed
  615. // because we don't have a status window to show our presence.
  616. //
  617. /**********************************************************************/
  618. /* EndComp() */
  619. /**********************************************************************/
  620. void PASCAL EndComp(
  621. HWND hUIWnd)
  622. {
  623. ShowComp(hUIWnd, SW_HIDE);
  624. return;
  625. }
  626. #endif
  627. /**********************************************************************/
  628. /* ChangeCompositionSize() */
  629. /**********************************************************************/
  630. void PASCAL ChangeCompositionSize(
  631. HWND hUIWnd)
  632. {
  633. HWND hCompWnd, hCandWnd;
  634. RECT rcWnd;
  635. UINT nMaxKey;
  636. HIMC hIMC;
  637. LPINPUTCONTEXT lpIMC;
  638. hCompWnd = GetCompWnd(hUIWnd);
  639. if (!hCompWnd) {
  640. return;
  641. }
  642. GetWindowRect(hCompWnd, &rcWnd);
  643. if ((rcWnd.right - rcWnd.left) != lpImeL->xCompWi) {
  644. } else if ((rcWnd.bottom - rcWnd.top) != lpImeL->yCompHi) {
  645. } else {
  646. return;
  647. }
  648. SetWindowPos(hCompWnd, NULL,
  649. 0, 0, lpImeL->xCompWi, lpImeL->yCompHi,
  650. SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
  651. if (lpImeL->nRevMaxKey >= lpImeL->nMaxKey) {
  652. nMaxKey = lpImeL->nRevMaxKey;
  653. } else {
  654. nMaxKey = lpImeL->nMaxKey;
  655. }
  656. SetWindowLong(hCompWnd, UI_MOVE_XY, nMaxKey);
  657. return;
  658. }
  659. /**********************************************************************/
  660. /* DestroyCompWindow() */
  661. /**********************************************************************/
  662. void PASCAL DestroyCompWindow( // destroy composition window
  663. HWND hCompWnd)
  664. {
  665. HGLOBAL hUIPrivate;
  666. LPUIPRIV lpUIPrivate;
  667. if (GetWindowLong(hCompWnd, UI_MOVE_OFFSET) != WINDOW_NOT_DRAG) {
  668. // undo the drag border
  669. DrawDragBorder(hCompWnd,
  670. GetWindowLong(hCompWnd, UI_MOVE_XY),
  671. GetWindowLong(hCompWnd, UI_MOVE_OFFSET));
  672. }
  673. hUIPrivate = (HGLOBAL)GetWindowLongPtr(GetWindow(hCompWnd, GW_OWNER),
  674. IMMGWLP_PRIVATE);
  675. if (!hUIPrivate) { // Oh! Oh!
  676. return;
  677. }
  678. lpUIPrivate = (LPUIPRIV)GlobalLock(hUIPrivate);
  679. if (!lpUIPrivate) { // Oh! Oh!
  680. return;
  681. }
  682. lpUIPrivate->nShowCompCmd = SW_HIDE;
  683. lpUIPrivate->hCompWnd = (HWND)NULL;
  684. GlobalUnlock(hUIPrivate);
  685. return;
  686. }
  687. /**********************************************************************/
  688. /* CompSetCursor() */
  689. /**********************************************************************/
  690. void PASCAL CompSetCursor(
  691. HWND hCompWnd,
  692. LPARAM lParam)
  693. {
  694. POINT ptCursor;
  695. RECT rcWnd;
  696. // SetCursor(LoadCursor(NULL, IDC_SIZEALL));
  697. if (GetWindowLong(hCompWnd, UI_MOVE_OFFSET) !=
  698. WINDOW_NOT_DRAG) {
  699. return;
  700. }
  701. if (HIWORD(lParam) != WM_LBUTTONDOWN) {
  702. return;
  703. }
  704. // start dragging
  705. SystemParametersInfo(SPI_GETWORKAREA, 0, &sImeG.rcWorkArea, 0);
  706. SetCapture(hCompWnd);
  707. GetCursorPos(&ptCursor);
  708. SetWindowLong(hCompWnd, UI_MOVE_XY,
  709. MAKELONG(ptCursor.x, ptCursor.y));
  710. GetWindowRect(hCompWnd, &rcWnd);
  711. SetWindowLong(hCompWnd, UI_MOVE_OFFSET,
  712. MAKELONG(ptCursor.x - rcWnd.left, ptCursor.y - rcWnd.top));
  713. DrawDragBorder(hCompWnd, MAKELONG(ptCursor.x, ptCursor.y),
  714. GetWindowLong(hCompWnd, UI_MOVE_OFFSET));
  715. return;
  716. }
  717. /**********************************************************************/
  718. /* CompButtonUp() */
  719. /**********************************************************************/
  720. BOOL PASCAL CompButtonUp( // finish drag, set comp window to this
  721. // position
  722. HWND hCompWnd)
  723. {
  724. LONG lTmpCursor, lTmpOffset;
  725. POINT pt;
  726. HWND hUIWnd;
  727. HIMC hIMC;
  728. LPINPUTCONTEXT lpIMC;
  729. if (GetWindowLong(hCompWnd, UI_MOVE_OFFSET) == WINDOW_NOT_DRAG) {
  730. return (FALSE);
  731. }
  732. lTmpCursor = GetWindowLong(hCompWnd, UI_MOVE_XY);
  733. // calculate the org by the offset
  734. lTmpOffset = GetWindowLong(hCompWnd, UI_MOVE_OFFSET);
  735. pt.x = (*(LPPOINTS)&lTmpCursor).x - (*(LPPOINTS)&lTmpOffset).x;
  736. pt.y = (*(LPPOINTS)&lTmpCursor).y - (*(LPPOINTS)&lTmpOffset).y;
  737. DrawDragBorder(hCompWnd, lTmpCursor, lTmpOffset);
  738. SetWindowLong(hCompWnd, UI_MOVE_OFFSET, WINDOW_NOT_DRAG);
  739. SetWindowLong(hCompWnd, UI_MOVE_XY, lpImeL->nRevMaxKey);
  740. ReleaseCapture();
  741. hUIWnd = GetWindow(hCompWnd, GW_OWNER);
  742. hIMC = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC);
  743. if (!hIMC) {
  744. return (FALSE);
  745. }
  746. lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
  747. if (!lpIMC) {
  748. return (FALSE);
  749. }
  750. if (pt.x < sImeG.rcWorkArea.left) {
  751. pt.x = sImeG.rcWorkArea.left;
  752. } else if (pt.x + lpImeL->xCompWi > sImeG.rcWorkArea.right) {
  753. pt.x = sImeG.rcWorkArea.right - lpImeL->xCompWi;
  754. }
  755. if (pt.y < sImeG.rcWorkArea.top) {
  756. pt.y = sImeG.rcWorkArea.top;
  757. } else if (pt.y + lpImeL->yCompHi > sImeG.rcWorkArea.bottom) {
  758. pt.y = sImeG.rcWorkArea.bottom - lpImeL->yCompHi;
  759. }
  760. lpIMC->cfCompForm.dwStyle = CFS_FORCE_POSITION;
  761. lpIMC->cfCompForm.ptCurrentPos.x = pt.x + lpImeL->cxCompBorder;
  762. lpIMC->cfCompForm.ptCurrentPos.y = pt.y + lpImeL->cyCompBorder;
  763. ScreenToClient(lpIMC->hWnd, &lpIMC->cfCompForm.ptCurrentPos);
  764. ImmUnlockIMC(hIMC);
  765. // set composition window to the new poosition
  766. PostMessage(hCompWnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONWINDOW, 0);
  767. return (TRUE);
  768. }
  769. /**********************************************************************/
  770. /* PaintCompWindow() */
  771. /**********************************************************************/
  772. void PASCAL PaintCompWindow(
  773. HWND hUIWnd,
  774. HDC hDC)
  775. {
  776. HIMC hIMC;
  777. LPINPUTCONTEXT lpIMC;
  778. LPCOMPOSITIONSTRING lpCompStr;
  779. HGDIOBJ hOldFont;
  780. LOGFONT lfFont;
  781. // RECT rcSunken;
  782. hIMC = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC);
  783. if (!hIMC) {
  784. return;
  785. }
  786. lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
  787. if (!lpIMC) {
  788. return;
  789. }
  790. lpCompStr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
  791. hOldFont = GetCurrentObject(hDC, OBJ_FONT);
  792. if ( hOldFont == NULL)
  793. {
  794. if (lpCompStr) {
  795. ImmUnlockIMCC(lpIMC->hCompStr);
  796. }
  797. ImmUnlockIMC(hIMC);
  798. return;
  799. }
  800. /*
  801. // GetObject(hOldFont, sizeof(lfFont), &lfFont);
  802. memset (&lfFont, 0, sizeof(LOGFONT));
  803. lfFont.lfHeight = -11;
  804. lfFont.lfCharSet = NATIVE_CHARSET;
  805. lfFont.lfWeight = FW_NORMAL;
  806. lstrcpy(lfFont.lfFaceName,TEXT("MS Shell Dlg"));
  807. //SelectObject(hDC, CreateFontIndirect(&lfFont));
  808. */
  809. SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT));
  810. // light gray background for normal case
  811. SetBkColor(hDC, RGB(0xC0, 0xC0, 0xC0));
  812. if (!lpCompStr) {
  813. goto UpdCompWndShowGuideLine;
  814. } else if (!lpCompStr->dwCompStrLen) {
  815. LPGUIDELINE lpGuideLine;
  816. UpdCompWndShowGuideLine:
  817. lpGuideLine = (LPGUIDELINE)ImmLockIMCC(lpIMC->hGuideLine);
  818. if (lpGuideLine) {
  819. BOOL fReverseConversion;
  820. LPCANDIDATELIST lpCandList;
  821. LPTSTR lpStr;
  822. UINT uStrLen;
  823. fReverseConversion = FALSE;
  824. if (lpGuideLine->dwLevel != GL_LEVEL_INFORMATION) {
  825. goto UpdCompWndUnlockGuideLine;
  826. } else if (lpGuideLine->dwIndex != GL_ID_REVERSECONVERSION) {
  827. goto UpdCompWndUnlockGuideLine;
  828. } else {
  829. }
  830. lpCandList = (LPCANDIDATELIST)((LPBYTE)lpGuideLine +
  831. lpGuideLine->dwPrivateOffset);
  832. if (!lpCandList) {
  833. goto UpdCompWndUnlockGuideLine;
  834. } else if (!lpCandList->dwCount) {
  835. goto UpdCompWndUnlockGuideLine;
  836. } else {
  837. fReverseConversion = TRUE;
  838. }
  839. // green text for information
  840. SetTextColor(hDC, RGB(0x00, 0x80, 0x00));
  841. lpStr = (LPTSTR)((LPBYTE)lpCandList + lpCandList->dwOffset[0]);
  842. uStrLen = lstrlen(lpStr);
  843. ExtTextOut(hDC, lpImeL->rcCompText.left, lpImeL->rcCompText.top,
  844. ETO_OPAQUE, &lpImeL->rcCompText,
  845. lpStr, uStrLen, iDx);
  846. UpdCompWndUnlockGuideLine:
  847. ImmUnlockIMCC(lpIMC->hGuideLine);
  848. if (!fReverseConversion) {
  849. goto UpdCompWndNoString;
  850. }
  851. } else {
  852. UpdCompWndNoString:
  853. // no any information
  854. ExtTextOut(hDC, lpImeL->rcCompText.left, lpImeL->rcCompText.top,
  855. ETO_OPAQUE, &lpImeL->rcCompText,
  856. (LPTSTR)NULL, 0, NULL);
  857. }
  858. } else {
  859. ExtTextOut(hDC, lpImeL->rcCompText.left, lpImeL->rcCompText.top,
  860. ETO_OPAQUE, &lpImeL->rcCompText,
  861. (LPTSTR)((LPBYTE)lpCompStr + lpCompStr->dwCompStrOffset),
  862. (UINT)lpCompStr->dwCompStrLen, iDx);
  863. if (lpCompStr->dwCompStrLen <= lpCompStr->dwCursorPos) {
  864. goto UpdCompWndUnselectObj;
  865. }
  866. // there is error part
  867. // red text for error
  868. SetTextColor(hDC, RGB(0xFF, 0x00, 0x00));
  869. // dark gray background for error
  870. SetBkColor(hDC, RGB(0x80, 0x80, 0x80));
  871. ExtTextOut(hDC, lpImeL->rcCompText.left +
  872. lpCompStr->dwCursorPos * sImeG.xChiCharWi /
  873. (sizeof(WCHAR) / sizeof(TCHAR)),
  874. lpImeL->rcCompText.top,
  875. ETO_OPAQUE, NULL,
  876. (LPTSTR)((LPBYTE)lpCompStr + lpCompStr->dwCompStrOffset +
  877. lpCompStr->dwCursorPos * sizeof(TCHAR)),
  878. (UINT)(lpCompStr->dwCompStrLen - lpCompStr->dwCursorPos), iDx);
  879. }
  880. UpdCompWndUnselectObj:
  881. if (sImeG.fDiffSysCharSet) {
  882. DeleteObject(SelectObject(hDC, hOldFont));
  883. }
  884. if (lpCompStr) {
  885. ImmUnlockIMCC(lpIMC->hCompStr);
  886. }
  887. ImmUnlockIMC(hIMC);
  888. #if 0
  889. rcSunken = lpImeL->rcCompText;
  890. rcSunken.left -= lpImeL->cxCompBorder;
  891. rcSunken.top -= lpImeL->cyCompBorder;
  892. rcSunken.right += lpImeL->cxCompBorder;
  893. rcSunken.bottom += lpImeL->cyCompBorder;
  894. DrawEdge(hDC, &rcSunken, BDR_SUNKENOUTER, BF_RECT);
  895. #endif
  896. return;
  897. }
  898. /**********************************************************************/
  899. /* CompWndProc() / UniCompWndProc() */
  900. /**********************************************************************/
  901. // composition window proc
  902. LRESULT CALLBACK CompWndProc(
  903. HWND hCompWnd,
  904. UINT uMsg,
  905. WPARAM wParam,
  906. LPARAM lParam)
  907. {
  908. switch (uMsg) {
  909. case WM_DESTROY:
  910. DestroyCompWindow(hCompWnd);
  911. break;
  912. case WM_SETCURSOR:
  913. CompSetCursor(hCompWnd, lParam);
  914. break;
  915. case WM_MOUSEMOVE:
  916. if (GetWindowLong(hCompWnd, UI_MOVE_OFFSET) != WINDOW_NOT_DRAG) {
  917. POINT ptCursor;
  918. DrawDragBorder(hCompWnd,
  919. GetWindowLong(hCompWnd, UI_MOVE_XY),
  920. GetWindowLong(hCompWnd, UI_MOVE_OFFSET));
  921. GetCursorPos(&ptCursor);
  922. SetWindowLong(hCompWnd, UI_MOVE_XY,
  923. MAKELONG(ptCursor.x, ptCursor.y));
  924. DrawDragBorder(hCompWnd, MAKELONG(ptCursor.x, ptCursor.y),
  925. GetWindowLong(hCompWnd, UI_MOVE_OFFSET));
  926. } else {
  927. return DefWindowProc(hCompWnd, uMsg, wParam, lParam);
  928. }
  929. break;
  930. case WM_LBUTTONUP:
  931. if (!CompButtonUp(
  932. hCompWnd)) {
  933. return DefWindowProc(hCompWnd, uMsg, wParam, lParam);
  934. }
  935. break;
  936. case WM_IME_NOTIFY:
  937. if (wParam != IMN_SETCOMPOSITIONWINDOW) {
  938. /*
  939. } else if (lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI) {
  940. */
  941. } else {
  942. SetCompWindow(
  943. hCompWnd);
  944. }
  945. break;
  946. case WM_PAINT:
  947. {
  948. HDC hDC;
  949. PAINTSTRUCT ps;
  950. hDC = BeginPaint(hCompWnd, &ps);
  951. PaintCompWindow(
  952. GetWindow(hCompWnd, GW_OWNER), hDC);
  953. EndPaint(hCompWnd, &ps);
  954. }
  955. break;
  956. case WM_MOUSEACTIVATE:
  957. return (MA_NOACTIVATE);
  958. default:
  959. return DefWindowProc(hCompWnd, uMsg, wParam, lParam);
  960. }
  961. return (0L);
  962. }