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.

1064 lines
33 KiB

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