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.

649 lines
21 KiB

  1. /*************************************************
  2. * compose.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. /* SearchTbl() */
  13. /* Description: */
  14. /* file format can be changed in different version for */
  15. /* performance consideration, ISVs should not assume its format */
  16. /**********************************************************************/
  17. void PASCAL SearchTbl( // searching the standard table files
  18. UINT uTblIndex,
  19. LPCANDIDATELIST lpCandList,
  20. LPPRIVCONTEXT lpImcP)
  21. {
  22. UINT uCode;
  23. uCode = (lpImcP->bSeq[0] - 1) << 12;
  24. uCode |= (lpImcP->bSeq[1] - 1) << 8;
  25. uCode |= (lpImcP->bSeq[2] - 1) << 4;
  26. uCode |= (lpImcP->bSeq[3] - 1);
  27. if (uCode <= 0x001F ||
  28. (uCode >= 0x007F && uCode <=0x009F))
  29. {
  30. //
  31. // We want to block control code to avoid confusion.
  32. //
  33. return;
  34. }
  35. AddCodeIntoCand(lpCandList, uCode);
  36. return;
  37. }
  38. /**********************************************************************/
  39. /* AddCodeIntoCand() */
  40. /**********************************************************************/
  41. void PASCAL AddCodeIntoCand(
  42. LPCANDIDATELIST lpCandList,
  43. UINT uCode)
  44. {
  45. if (lpCandList->dwCount >= MAXCAND) {
  46. // Grow memory here and do something,
  47. // if you still want to process it.
  48. return;
  49. }
  50. // add this string into candidate list
  51. *(LPWSTR)((LPBYTE)lpCandList + lpCandList->dwOffset[
  52. lpCandList->dwCount]) = (WCHAR)uCode;
  53. // null terminator
  54. *(LPTSTR)((LPBYTE)lpCandList + lpCandList->dwOffset[
  55. lpCandList->dwCount] + sizeof(WCHAR)) = '\0';
  56. lpCandList->dwCount++;
  57. if (lpCandList->dwCount >= MAXCAND) {
  58. return;
  59. }
  60. lpCandList->dwOffset[lpCandList->dwCount] =
  61. lpCandList->dwOffset[lpCandList->dwCount - 1] +
  62. sizeof(WCHAR) + sizeof(TCHAR);
  63. return;
  64. }
  65. /**********************************************************************/
  66. /* CompEscapeKey() */
  67. /**********************************************************************/
  68. void PASCAL CompEscapeKey(
  69. LPINPUTCONTEXT lpIMC,
  70. LPCOMPOSITIONSTRING lpCompStr,
  71. LPPRIVCONTEXT lpImcP)
  72. {
  73. if (lpImcP->fdwImeMsg & MSG_OPEN_CANDIDATE) {
  74. // we have candidate window, so keep composition
  75. } else if ((lpImcP->fdwImeMsg & (MSG_ALREADY_OPEN|MSG_CLOSE_CANDIDATE)) ==
  76. (MSG_ALREADY_OPEN)) {
  77. // we have candidate window, so keep composition
  78. } else if (lpImcP->fdwImeMsg & MSG_ALREADY_START) {
  79. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg|MSG_END_COMPOSITION) &
  80. ~(MSG_START_COMPOSITION);
  81. } else {
  82. lpImcP->fdwImeMsg &= ~(MSG_END_COMPOSITION|MSG_START_COMPOSITION);
  83. }
  84. lpImcP->iImeState = CST_INIT;
  85. *(LPDWORD)lpImcP->bSeq = 0;
  86. if (lpCompStr) {
  87. InitCompStr(lpCompStr);
  88. lpImcP->fdwImeMsg |= MSG_COMPOSITION;
  89. lpImcP->dwCompChar = VK_ESCAPE;
  90. lpImcP->fdwGcsFlag |= (GCS_COMPREAD|GCS_COMP|GCS_CURSORPOS|
  91. GCS_DELTASTART);
  92. }
  93. return;
  94. }
  95. /**********************************************************************/
  96. /* CompBackSpaceKey() */
  97. /**********************************************************************/
  98. void PASCAL CompBackSpaceKey(
  99. HIMC hIMC,
  100. LPINPUTCONTEXT lpIMC,
  101. LPCOMPOSITIONSTRING lpCompStr,
  102. LPPRIVCONTEXT lpImcP)
  103. {
  104. if (lpCompStr->dwCursorPos < sizeof(WCHAR) / sizeof(TCHAR)) {
  105. lpCompStr->dwCursorPos = sizeof(WCHAR) / sizeof(TCHAR);
  106. }
  107. // go back a compsoition char
  108. lpCompStr->dwCursorPos -= sizeof(WCHAR) / sizeof(TCHAR);
  109. // clean the sequence code
  110. lpImcP->bSeq[lpCompStr->dwCursorPos / (sizeof(WCHAR) / sizeof(TCHAR))] = 0;
  111. lpImcP->fdwImeMsg |= MSG_COMPOSITION;
  112. lpImcP->dwCompChar = '\b';
  113. lpImcP->fdwGcsFlag |= (GCS_COMPREAD|GCS_COMP|GCS_CURSORPOS|
  114. GCS_DELTASTART);
  115. if (!lpCompStr->dwCursorPos) {
  116. if (lpImcP->fdwImeMsg & (MSG_ALREADY_OPEN)) {
  117. ClearCand(lpIMC);
  118. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_CLOSE_CANDIDATE) &
  119. ~(MSG_OPEN_CANDIDATE);
  120. }
  121. lpImcP->iImeState = CST_INIT;
  122. if (lpImcP->fdwImeMsg & MSG_ALREADY_START) {
  123. InitCompStr(lpCompStr);
  124. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_END_COMPOSITION) &
  125. ~(MSG_START_COMPOSITION);
  126. return;
  127. }
  128. }
  129. // reading string is composition string for some simple IMEs
  130. // delta start is the same as cursor position for backspace
  131. lpCompStr->dwCompReadAttrLen = lpCompStr->dwCompAttrLen =
  132. lpCompStr->dwCompReadStrLen = lpCompStr->dwCompStrLen =
  133. lpCompStr->dwDeltaStart = lpCompStr->dwCursorPos;
  134. // clause also back one
  135. *(LPDWORD)((LPBYTE)lpCompStr + lpCompStr->dwCompReadClauseOffset +
  136. sizeof(DWORD)) = lpCompStr->dwCompReadStrLen;
  137. return;
  138. }
  139. /**********************************************************************/
  140. /* CompStrInfo() */
  141. /**********************************************************************/
  142. void PASCAL CompStrInfo(
  143. LPCOMPOSITIONSTRING lpCompStr,
  144. LPPRIVCONTEXT lpImcP,
  145. LPGUIDELINE lpGuideLine,
  146. WORD wCharCode)
  147. {
  148. register DWORD dwCursorPos;
  149. if (lpCompStr->dwCursorPos < lpCompStr->dwCompStrLen) {
  150. // for this kind of simple IME, previos is an error case
  151. for (dwCursorPos = lpCompStr->dwCursorPos;
  152. dwCursorPos < lpCompStr->dwCompStrLen;
  153. dwCursorPos += sizeof(WCHAR) / sizeof(TCHAR)) {
  154. lpImcP->bSeq[dwCursorPos / (sizeof(WCHAR) / sizeof(TCHAR))] = 0;
  155. }
  156. lpCompStr->dwCompReadAttrLen = lpCompStr->dwCompAttrLen =
  157. lpCompStr->dwCompReadStrLen = lpCompStr->dwCompStrLen =
  158. lpCompStr->dwDeltaStart = lpCompStr->dwCursorPos;
  159. // tell app, there is a composition char changed
  160. lpImcP->fdwImeMsg |= MSG_COMPOSITION;
  161. lpImcP->fdwGcsFlag |= GCS_COMPREAD|GCS_COMP|
  162. GCS_CURSORPOS|GCS_DELTASTART;
  163. }
  164. if (wCharCode == ' ') {
  165. // finalized char is OK
  166. lpImcP->dwCompChar = ' ';
  167. return;
  168. }
  169. if (lpCompStr->dwCursorPos < lpImeL->nMaxKey * sizeof(WCHAR) /
  170. sizeof(TCHAR)) {
  171. } else if (lpGuideLine) {
  172. // exceed the max input key limitation
  173. lpGuideLine->dwLevel = GL_LEVEL_ERROR;
  174. lpGuideLine->dwIndex = GL_ID_TOOMANYSTROKE;
  175. lpImcP->fdwImeMsg |= MSG_GUIDELINE;
  176. return;
  177. } else {
  178. MessageBeep((UINT)-1);
  179. return;
  180. }
  181. if (lpImeL->fdwErrMsg & NO_REV_LENGTH) {
  182. WORD nRevMaxKey;
  183. nRevMaxKey = (WORD)ImmEscape(lpImeL->hRevKL, (HIMC)NULL,
  184. IME_ESC_MAX_KEY, NULL);
  185. if (nRevMaxKey > lpImeL->nMaxKey) {
  186. lpImeL->nRevMaxKey = nRevMaxKey;
  187. SetCompLocalData(lpImeL);
  188. lpImcP->fdwImeMsg |= MSG_IMN_COMPOSITIONSIZE;
  189. } else {
  190. lpImeL->nRevMaxKey = lpImeL->nMaxKey;
  191. if (!nRevMaxKey) {
  192. lpImeL->hRevKL = NULL;
  193. }
  194. }
  195. lpImeL->fdwErrMsg &= ~(NO_REV_LENGTH);
  196. }
  197. if (lpImcP->fdwImeMsg & MSG_ALREADY_START) {
  198. lpImcP->fdwImeMsg &= ~(MSG_END_COMPOSITION);
  199. } else {
  200. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_START_COMPOSITION) &
  201. ~(MSG_END_COMPOSITION);
  202. }
  203. if (lpImcP->iImeState == CST_INIT) {
  204. // clean the 4 bytes in one time
  205. *(LPDWORD)lpImcP->bSeq = 0;
  206. }
  207. // get the sequence code, you can treat sequence code as a kind
  208. // of compression - bo, po, mo, fo to 1, 2, 3, 4
  209. // phonetic and array table file are in sequence code format
  210. dwCursorPos = lpCompStr->dwCursorPos;
  211. lpImcP->bSeq[dwCursorPos / (sizeof(WCHAR) / sizeof(TCHAR))] =
  212. (BYTE)lpImeL->wChar2SeqTbl[wCharCode - ' '];
  213. // composition/reading string - bo po mo fo, reversed internal code
  214. lpImcP->dwCompChar = (DWORD)lpImeL->wSeq2CompTbl[
  215. lpImcP->bSeq[dwCursorPos / (sizeof(WCHAR) / sizeof(TCHAR))]];
  216. // assign to reading string
  217. *((LPWSTR)((LPBYTE)lpCompStr + lpCompStr->dwCompReadStrOffset +
  218. dwCursorPos * sizeof(TCHAR))) = (WCHAR)lpImcP->dwCompChar;
  219. // add one composition reading for this input key
  220. if (lpCompStr->dwCompReadStrLen <= dwCursorPos) {
  221. lpCompStr->dwCompReadStrLen += sizeof(WCHAR) / sizeof(TCHAR);
  222. }
  223. // composition string is reading string for some simple IMEs
  224. lpCompStr->dwCompStrLen = lpCompStr->dwCompReadStrLen;
  225. // composition/reading attribute length is equal to reading string length
  226. lpCompStr->dwCompReadAttrLen = lpCompStr->dwCompReadStrLen;
  227. lpCompStr->dwCompAttrLen = lpCompStr->dwCompStrLen;
  228. *((LPBYTE)lpCompStr + lpCompStr->dwCompReadAttrOffset +
  229. dwCursorPos) = ATTR_TARGET_CONVERTED;
  230. // composition/reading clause, 1 clause only
  231. lpCompStr->dwCompReadClauseLen = 2 * sizeof(DWORD);
  232. lpCompStr->dwCompClauseLen = lpCompStr->dwCompReadClauseLen;
  233. *(LPDWORD)((LPBYTE)lpCompStr + lpCompStr->dwCompReadClauseOffset +
  234. sizeof(DWORD)) = lpCompStr->dwCompReadStrLen;
  235. // delta start from previous cursor position
  236. lpCompStr->dwDeltaStart = lpCompStr->dwCursorPos;
  237. // cursor is next to the composition string
  238. lpCompStr->dwCursorPos = lpCompStr->dwCompStrLen;
  239. lpImcP->iImeState = CST_INPUT;
  240. // tell app, there is a composition char generated
  241. lpImcP->fdwImeMsg |= MSG_COMPOSITION;
  242. lpImcP->fdwGcsFlag |= GCS_COMPREAD|GCS_COMP|GCS_CURSORPOS|GCS_DELTASTART;
  243. return;
  244. }
  245. /**********************************************************************/
  246. /* Finalize() */
  247. /* Return vlaue */
  248. /* the number of candidates in the candidate list */
  249. /**********************************************************************/
  250. UINT PASCAL Finalize( // finalize Chinese word(s) by searching table
  251. HIMC hIMC,
  252. LPINPUTCONTEXT lpIMC,
  253. LPCOMPOSITIONSTRING lpCompStr,
  254. LPPRIVCONTEXT lpImcP,
  255. BOOL fFinalized)
  256. {
  257. LPCANDIDATEINFO lpCandInfo;
  258. LPCANDIDATELIST lpCandList;
  259. UINT nCand;
  260. // quick key case
  261. if (!lpImcP->bSeq[1]) {
  262. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_CLOSE_CANDIDATE) &
  263. ~(MSG_OPEN_CANDIDATE|MSG_CHANGE_CANDIDATE);
  264. return (0);
  265. }
  266. if (!lpIMC->hCandInfo) {
  267. return (0);
  268. }
  269. lpCandInfo = (LPCANDIDATEINFO)ImmLockIMCC(lpIMC->hCandInfo);
  270. if (!lpCandInfo) {
  271. return (0);
  272. }
  273. lpCandList = (LPCANDIDATELIST)
  274. ((LPBYTE)lpCandInfo + lpCandInfo->dwOffset[0]);
  275. // start from 0
  276. lpCandList->dwCount = 0;
  277. // default start from 0
  278. lpCandList->dwPageStart = lpCandList->dwSelection = 0;
  279. // search the IME tables
  280. SearchTbl( 0, lpCandList, lpImcP);
  281. nCand = lpCandList->dwCount;
  282. if (!fFinalized) {
  283. // for quick key
  284. lpCandInfo->dwCount = 1;
  285. // open composition candidate UI window for the string(s)
  286. if (lpImcP->fdwImeMsg & MSG_ALREADY_OPEN) {
  287. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_CHANGE_CANDIDATE) &
  288. ~(MSG_CLOSE_CANDIDATE);
  289. } else {
  290. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_OPEN_CANDIDATE) &
  291. ~(MSG_CLOSE_CANDIDATE);
  292. }
  293. } else if (nCand == 0) { // nothing found, error
  294. // move cursor back because this is wrong
  295. if (lpCompStr->dwCursorPos > sizeof(WCHAR) / sizeof(TCHAR)) {
  296. lpCompStr->dwCursorPos = lpCompStr->dwCompReadStrLen -
  297. sizeof(WCHAR) / sizeof(TCHAR);
  298. } else {
  299. lpCompStr->dwCursorPos = 0;
  300. lpImcP->iImeState = CST_INIT;
  301. }
  302. lpCompStr->dwDeltaStart = lpCompStr->dwCursorPos;
  303. if (lpImcP->fdwImeMsg & MSG_ALREADY_START) {
  304. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_COMPOSITION) &
  305. ~(MSG_END_COMPOSITION);
  306. } else {
  307. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_START_COMPOSITION) &
  308. ~(MSG_END_COMPOSITION);
  309. }
  310. // for quick key
  311. lpCandInfo->dwCount = 0;
  312. // close the quick key
  313. if (lpImcP->fdwImeMsg & MSG_ALREADY_OPEN) {
  314. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_CLOSE_CANDIDATE) &
  315. ~(MSG_OPEN_CANDIDATE|MSG_CHANGE_CANDIDATE);
  316. } else {
  317. lpImcP->fdwImeMsg &= ~(MSG_OPEN_CANDIDATE|MSG_CLOSE_CANDIDATE);
  318. }
  319. lpImcP->fdwGcsFlag |= GCS_CURSORPOS|GCS_DELTASTART;
  320. } else if (nCand == 1) { // only one choice
  321. SelectOneCand(
  322. hIMC, lpIMC, lpCompStr, lpImcP, lpCandList);
  323. } else {
  324. lpCandInfo->dwCount = 1;
  325. // there are more than one strings, open composition candidate UI window
  326. if (lpImcP->fdwImeMsg & MSG_ALREADY_OPEN) {
  327. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_CHANGE_CANDIDATE) &
  328. ~(MSG_CLOSE_CANDIDATE);
  329. } else {
  330. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_OPEN_CANDIDATE) &
  331. ~(MSG_CLOSE_CANDIDATE);
  332. }
  333. lpImcP->iImeState = CST_CHOOSE;
  334. }
  335. if (fFinalized) {
  336. LPGUIDELINE lpGuideLine;
  337. lpGuideLine = ImmLockIMCC(lpIMC->hGuideLine);
  338. if (!lpGuideLine) {
  339. } else if (!nCand) {
  340. // nothing found, end user, you have an error now
  341. lpGuideLine->dwLevel = GL_LEVEL_ERROR;
  342. lpGuideLine->dwIndex = GL_ID_TYPINGERROR;
  343. lpImcP->fdwImeMsg |= MSG_GUIDELINE;
  344. } else if (nCand == 1) {
  345. } else if (lpImeL->fwProperties1 & IMEPROP_CAND_NOBEEP_GUIDELINE) {
  346. } else {
  347. lpGuideLine->dwLevel = GL_LEVEL_WARNING;
  348. // multiple selection
  349. lpGuideLine->dwIndex = GL_ID_CHOOSECANDIDATE;
  350. lpImcP->fdwImeMsg |= MSG_GUIDELINE;
  351. }
  352. if (lpGuideLine) {
  353. ImmUnlockIMCC(lpIMC->hGuideLine);
  354. }
  355. }
  356. ImmUnlockIMCC(lpIMC->hCandInfo);
  357. return (nCand);
  358. }
  359. /**********************************************************************/
  360. /* CompWord() */
  361. /**********************************************************************/
  362. void PASCAL CompWord( // compose the Chinese word(s) according to
  363. // input key
  364. WORD wCharCode,
  365. HIMC hIMC,
  366. LPINPUTCONTEXT lpIMC,
  367. LPCOMPOSITIONSTRING lpCompStr,
  368. LPGUIDELINE lpGuideLine,
  369. LPPRIVCONTEXT lpImcP)
  370. {
  371. if (!lpCompStr) {
  372. MessageBeep((UINT)-1);
  373. return;
  374. }
  375. // escape key
  376. if (wCharCode == VK_ESCAPE) { // not good to use VK as char, but...
  377. CompEscapeKey(lpIMC, lpCompStr, lpImcP);
  378. return;
  379. }
  380. if (wCharCode == '\b') {
  381. CompBackSpaceKey(hIMC, lpIMC, lpCompStr, lpImcP);
  382. return;
  383. }
  384. if (wCharCode >= 'a' && wCharCode <= 'z') {
  385. wCharCode ^= 0x20;
  386. }
  387. // build up composition string info
  388. CompStrInfo(lpCompStr, lpImcP, lpGuideLine, wCharCode);
  389. if (lpIMC->fdwConversion & IME_CMODE_EUDC) {
  390. if (lpCompStr->dwCompReadStrLen >= sizeof(WCHAR) / sizeof(TCHAR) *
  391. lpImeL->nMaxKey) {
  392. lpImcP->fdwImeMsg |= MSG_COMPOSITION;
  393. lpImcP->fdwGcsFlag |= GCS_RESULTREAD|GCS_RESULTSTR;
  394. }
  395. } else {
  396. if (lpCompStr->dwCompReadStrLen < sizeof(WCHAR) / sizeof(TCHAR) *
  397. lpImeL->nMaxKey) {
  398. return;
  399. }
  400. Finalize( hIMC, lpIMC, lpCompStr, lpImcP, TRUE);
  401. }
  402. return;
  403. }
  404. /**********************************************************************/
  405. /* SelectOneCand() */
  406. /**********************************************************************/
  407. void PASCAL SelectOneCand(
  408. HIMC hIMC,
  409. LPINPUTCONTEXT lpIMC,
  410. LPCOMPOSITIONSTRING lpCompStr,
  411. LPPRIVCONTEXT lpImcP,
  412. LPCANDIDATELIST lpCandList)
  413. {
  414. DWORD dwCompStrLen;
  415. DWORD dwReadClauseLen, dwReadStrLen;
  416. LPTSTR lpSelectStr;
  417. LPGUIDELINE lpGuideLine;
  418. if (!lpCompStr) {
  419. MessageBeep((UINT)-1);
  420. return;
  421. }
  422. if (!lpImcP) {
  423. MessageBeep((UINT)-1);
  424. return;
  425. }
  426. // backup the dwCompStrLen, this value decide whether
  427. // we go for phrase prediction
  428. dwCompStrLen = lpCompStr->dwCompStrLen;
  429. // backup the value, this value will be destroyed in InitCompStr
  430. dwReadClauseLen = lpCompStr->dwCompReadClauseLen;
  431. dwReadStrLen = lpCompStr->dwCompReadStrLen;
  432. lpSelectStr = (LPTSTR)((LPBYTE)lpCandList + lpCandList->dwOffset[
  433. lpCandList->dwSelection]);
  434. InitCompStr(lpCompStr);
  435. // the result reading clause = compsotion reading clause
  436. CopyMemory((LPBYTE)lpCompStr + lpCompStr->dwResultReadClauseOffset,
  437. (LPBYTE)lpCompStr + lpCompStr->dwCompReadClauseOffset,
  438. dwReadClauseLen * sizeof(TCHAR) + sizeof(TCHAR));
  439. lpCompStr->dwResultReadClauseLen = dwReadClauseLen;
  440. // the result reading string = compsotion reading string
  441. CopyMemory((LPBYTE)lpCompStr + lpCompStr->dwResultReadStrOffset,
  442. (LPBYTE)lpCompStr + lpCompStr->dwCompReadStrOffset,
  443. dwReadStrLen * sizeof(TCHAR) + sizeof(TCHAR));
  444. lpCompStr->dwResultReadStrLen = dwReadStrLen;
  445. // calculate result string length
  446. lpCompStr->dwResultStrLen = lstrlen(lpSelectStr);
  447. // the result string = the selected candidate;
  448. CopyMemory((LPBYTE)lpCompStr + lpCompStr->dwResultStrOffset, lpSelectStr,
  449. lpCompStr->dwResultStrLen * sizeof(TCHAR) + sizeof(TCHAR));
  450. lpCompStr->dwResultClauseLen = 2 * sizeof(DWORD);
  451. *(LPDWORD)((LPBYTE)lpCompStr + lpCompStr->dwResultClauseOffset +
  452. sizeof(DWORD)) = lpCompStr->dwResultStrLen;
  453. // tell application, there is a reslut string
  454. lpImcP->fdwImeMsg |= MSG_COMPOSITION;
  455. lpImcP->dwCompChar = 0;
  456. lpImcP->fdwGcsFlag |= GCS_COMPREAD|GCS_COMP|GCS_CURSORPOS|
  457. GCS_DELTASTART|GCS_RESULTREAD|GCS_RESULT;
  458. if (lpImcP->fdwImeMsg & MSG_ALREADY_OPEN) {
  459. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_CLOSE_CANDIDATE) &
  460. ~(MSG_OPEN_CANDIDATE|MSG_CHANGE_CANDIDATE);
  461. } else {
  462. lpImcP->fdwImeMsg &= ~(MSG_CLOSE_CANDIDATE|MSG_OPEN_CANDIDATE);
  463. }
  464. // no candidate now, the right candidate string already be finalized
  465. lpCandList->dwCount = 0;
  466. lpImcP->iImeState = CST_INIT;
  467. *(LPDWORD)lpImcP->bSeq = 0;
  468. //if ((WORD)lpIMC->fdwSentence != IME_SMODE_PHRASEPREDICT) {
  469. if (!(lpIMC->fdwSentence & IME_SMODE_PHRASEPREDICT)) {
  470. // not in phrase prediction mode
  471. } else if (!dwCompStrLen) {
  472. } else if (lpCompStr->dwResultStrLen != sizeof(WCHAR) / sizeof(TCHAR)) {
  473. }
  474. if (!lpCandList->dwCount) {
  475. if (lpImcP->fdwImeMsg & MSG_ALREADY_START) {
  476. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_END_COMPOSITION) &
  477. ~(MSG_START_COMPOSITION);
  478. } else {
  479. lpImcP->fdwImeMsg &= ~(MSG_END_COMPOSITION|MSG_START_COMPOSITION);
  480. }
  481. }
  482. if (!lpImeL->hRevKL) {
  483. return;
  484. }
  485. if (lpCompStr->dwResultStrLen != sizeof(WCHAR) / sizeof(TCHAR)) {
  486. // we only can reverse convert one DBCS character for now
  487. if (lpImcP->fdwImeMsg & MSG_GUIDELINE) {
  488. return;
  489. }
  490. }
  491. lpGuideLine = ImmLockIMCC(lpIMC->hGuideLine);
  492. if (!lpGuideLine) {
  493. return;
  494. }
  495. if (lpCompStr->dwResultStrLen != sizeof(WCHAR) / sizeof(TCHAR)) {
  496. // we only can reverse convert one DBCS character for now
  497. lpGuideLine->dwLevel = GL_LEVEL_NOGUIDELINE;
  498. lpGuideLine->dwIndex = GL_ID_UNKNOWN;
  499. } else {
  500. TCHAR szStrBuf[4];
  501. UINT uSize;
  502. *(LPDWORD)szStrBuf = 0;
  503. *(LPWSTR)szStrBuf = *(LPWSTR)((LPBYTE)lpCompStr +
  504. lpCompStr->dwResultStrOffset);
  505. uSize = ImmGetConversionList(lpImeL->hRevKL, (HIMC)NULL, szStrBuf,
  506. (LPCANDIDATELIST)((LPBYTE)lpGuideLine + lpGuideLine->dwPrivateOffset),
  507. lpGuideLine->dwPrivateSize, GCL_REVERSECONVERSION);
  508. if (uSize) {
  509. lpGuideLine->dwLevel = GL_LEVEL_INFORMATION;
  510. lpGuideLine->dwIndex = GL_ID_REVERSECONVERSION;
  511. lpImcP->fdwImeMsg |= MSG_GUIDELINE;
  512. if (lpImcP->fdwImeMsg & MSG_ALREADY_START) {
  513. lpImcP->fdwImeMsg &= ~(MSG_END_COMPOSITION|
  514. MSG_START_COMPOSITION);
  515. } else {
  516. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg|
  517. MSG_START_COMPOSITION) & ~(MSG_END_COMPOSITION);
  518. }
  519. } else {
  520. lpGuideLine->dwLevel = GL_LEVEL_NOGUIDELINE;
  521. lpGuideLine->dwIndex = GL_ID_UNKNOWN;
  522. }
  523. }
  524. ImmUnlockIMCC(lpIMC->hGuideLine);
  525. return;
  526. }