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.

1042 lines
30 KiB

  1. /*++
  2. Copyright (c) 1990-1999 Microsoft Corporation, All Rights Reserved
  3. Module Name:
  4. COMPOSE.c
  5. ++*/
  6. #include <windows.h>
  7. #include <immdev.h>
  8. #include "imeattr.h"
  9. #include "imedefs.h"
  10. #if !defined(ROMANIME)
  11. BOOL IsBig5Character( WCHAR wChar )
  12. {
  13. CHAR szBig5[3];
  14. WCHAR wszUnicode[2];
  15. BOOL bUsedDefaultChar;
  16. wszUnicode[0] = wChar;
  17. wszUnicode[1] = 0x0000;
  18. WideCharToMultiByte(NATIVE_ANSI_CP, WC_COMPOSITECHECK,
  19. wszUnicode, -1, szBig5,
  20. sizeof(szBig5), NULL, &bUsedDefaultChar);
  21. if ( bUsedDefaultChar != TRUE )
  22. return TRUE;
  23. else
  24. return FALSE;
  25. }
  26. #endif
  27. #if !defined(ROMANIME)
  28. /**********************************************************************/
  29. /* AddCodeIntoCand() */
  30. /**********************************************************************/
  31. void PASCAL AddCodeIntoCand(
  32. #ifdef UNIIME
  33. LPIMEL lpImeL,
  34. #endif
  35. LPCANDIDATELIST lpCandList,
  36. UINT uCode)
  37. {
  38. if (lpCandList->dwCount >= MAXCAND) {
  39. // Grow memory here and do something,
  40. // if you still want to process it.
  41. return;
  42. }
  43. #ifndef UNICODE
  44. // swap lead byte & second byte, UNICODE don't need it
  45. uCode = HIBYTE(uCode) | (LOBYTE(uCode) << 8);
  46. #endif
  47. // Before add this char, check if BIG5ONLY mode is set
  48. // if BIG5ONLY is set, and the character is out of Big5 Range
  49. // we just ignore this character.
  50. if ( lpImeL->fdwModeConfig & MODE_CONFIG_BIG5ONLY ) {
  51. if ( IsBig5Character( (WCHAR)uCode ) == FALSE ) {
  52. // this character is not in the range of Big5 charset
  53. return ;
  54. }
  55. }
  56. // add this string into candidate list
  57. *(LPWSTR)((LPBYTE)lpCandList + lpCandList->dwOffset[
  58. lpCandList->dwCount]) = (WCHAR)uCode;
  59. // null terminator
  60. *(LPTSTR)((LPBYTE)lpCandList + lpCandList->dwOffset[
  61. lpCandList->dwCount] + sizeof(WCHAR)) = '\0';
  62. lpCandList->dwCount++;
  63. if (lpCandList->dwCount >= MAXCAND) {
  64. return;
  65. }
  66. lpCandList->dwOffset[lpCandList->dwCount] =
  67. lpCandList->dwOffset[lpCandList->dwCount - 1] +
  68. sizeof(WCHAR) + sizeof(TCHAR);
  69. return;
  70. }
  71. /**********************************************************************/
  72. /* ConvertSeqCode2Pattern() */
  73. /**********************************************************************/
  74. DWORD PASCAL ConvertSeqCode2Pattern(
  75. #if defined(UNIIME)
  76. LPIMEL lpImeL,
  77. #endif
  78. LPBYTE lpbSeqCode,
  79. LPPRIVCONTEXT lpImcP)
  80. {
  81. #if defined(CHAJEI) || defined(WINAR30)
  82. int iInputEnd, iGhostCard;
  83. BOOL fGhostCard;
  84. #endif
  85. #if defined(WINAR30)
  86. DWORD dwWildCardMask;
  87. DWORD dwLastWildCard;
  88. BOOL fWildCard;
  89. #endif
  90. DWORD dwPattern;
  91. int i;
  92. // we will convert the sequence codes into compact bits
  93. dwPattern = 0;
  94. #if defined(CHAJEI) || defined(WINAR30)
  95. iInputEnd = iGhostCard = lpImeL->nMaxKey;
  96. fGhostCard = FALSE;
  97. #if defined(WINAR30)
  98. dwWildCardMask = 0;
  99. dwLastWildCard = 0;
  100. fWildCard = FALSE;
  101. #endif
  102. #endif
  103. #if defined(CHAJEI)
  104. // only support X*Y
  105. if (lpbSeqCode[0] == GHOSTCARD_SEQCODE) {
  106. // not support *XY
  107. goto CvtPatOvr;
  108. } else if (lpbSeqCode[1] != GHOSTCARD_SEQCODE) {
  109. } else if (lpbSeqCode[3]) {
  110. // not support X*YZ
  111. goto CvtPatOvr;
  112. } else if (lpbSeqCode[2] == GHOSTCARD_SEQCODE) {
  113. // not support X**
  114. goto CvtPatOvr;
  115. } else if (lpbSeqCode[2]) {
  116. } else {
  117. // not support X*
  118. goto CvtPatOvr;
  119. }
  120. #endif
  121. #if defined(QUICK)
  122. if (lpbSeqCode[1]) {
  123. lpImcP->iInputEnd = 2;
  124. } else {
  125. lpImcP->iInputEnd = 1;
  126. }
  127. #endif
  128. for (i = 0; i < lpImeL->nMaxKey; i++, lpbSeqCode++) {
  129. dwPattern <<= lpImeL->nSeqBits;
  130. #if defined(WINAR30)
  131. dwWildCardMask <<= lpImeL->nSeqBits;
  132. dwLastWildCard <<= lpImeL->nSeqBits;
  133. if (*lpbSeqCode == WILDCARD_SEQCODE) {
  134. // X?Y
  135. if (fGhostCard) {
  136. // can not support wild card with ghost card X*Y?
  137. dwPattern = 0;
  138. break;
  139. }
  140. dwLastWildCard = lpImeL->dwSeqMask;
  141. fWildCard = TRUE;
  142. } else {
  143. dwWildCardMask |= lpImeL->dwSeqMask;
  144. }
  145. #endif
  146. #if defined(CHAJEI) || defined(WINAR30)
  147. if (!*lpbSeqCode) {
  148. if (i < iInputEnd) {
  149. iInputEnd = i;
  150. }
  151. }
  152. if (*lpbSeqCode == GHOSTCARD_SEQCODE) {
  153. // X*Y
  154. if (fGhostCard) {
  155. // can not support multiple ghost cards X*Y*
  156. dwPattern = 0;
  157. break;
  158. }
  159. #if defined(WINAR30)
  160. if (fWildCard) {
  161. // can not support ghost card with wild card X?Y*
  162. dwPattern = 0;
  163. break;
  164. }
  165. dwLastWildCard = lpImeL->dwSeqMask;
  166. #endif
  167. iGhostCard = i;
  168. }
  169. #endif
  170. #if defined(CHAJEI) || defined(WINAR30)
  171. if (*lpbSeqCode == GHOSTCARD_SEQCODE) {
  172. continue;
  173. #if defined(WINAR30)
  174. } else if (*lpbSeqCode == WILDCARD_SEQCODE) {
  175. continue;
  176. #endif
  177. } else {
  178. }
  179. #endif
  180. dwPattern |= *lpbSeqCode;
  181. }
  182. #if defined(CHAJEI)
  183. CvtPatOvr:
  184. #endif
  185. if (lpImcP) {
  186. lpImcP->dwPattern = dwPattern;
  187. #if defined(QUICK)
  188. lpImcP->iGhostCard = 1;
  189. #endif
  190. #if defined(CHAJEI) || defined(WINAR30)
  191. if (dwPattern) {
  192. lpImcP->iInputEnd = iInputEnd;
  193. lpImcP->iGhostCard = iGhostCard;
  194. #if defined(WINAR30)
  195. lpImcP->dwWildCardMask = dwWildCardMask;
  196. lpImcP->dwLastWildCard = dwLastWildCard;
  197. #endif
  198. } else {
  199. lpImcP->iInputEnd = lpImcP->iGhostCard = lpImeL->nMaxKey;
  200. #if defined(WINAR30)
  201. lpImcP->dwWildCardMask = lpImeL->dwPatternMask;
  202. lpImcP->dwLastWildCard = 0;
  203. #endif
  204. }
  205. #endif
  206. }
  207. return (dwPattern);
  208. }
  209. /**********************************************************************/
  210. /* CompEscapeKey() */
  211. /**********************************************************************/
  212. void PASCAL CompEscapeKey(
  213. LPINPUTCONTEXT lpIMC,
  214. LPCOMPOSITIONSTRING lpCompStr,
  215. LPGUIDELINE lpGuideLine,
  216. LPPRIVCONTEXT lpImcP)
  217. {
  218. if (!lpGuideLine) {
  219. MessageBeep((UINT)-1);
  220. } else if (lpGuideLine->dwLevel != GL_LEVEL_NOGUIDELINE) {
  221. InitGuideLine(lpGuideLine);
  222. lpImcP->fdwImeMsg |= MSG_GUIDELINE;
  223. } else {
  224. }
  225. if (lpImcP->fdwImeMsg & MSG_OPEN_CANDIDATE) {
  226. // we have candidate window, so keep composition
  227. } else if ((lpImcP->fdwImeMsg & (MSG_ALREADY_OPEN|MSG_CLOSE_CANDIDATE)) ==
  228. (MSG_ALREADY_OPEN)) {
  229. // we have candidate window, so keep composition
  230. } else if (lpImcP->fdwImeMsg & MSG_ALREADY_START) {
  231. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg|MSG_END_COMPOSITION) &
  232. ~(MSG_START_COMPOSITION);
  233. } else {
  234. lpImcP->fdwImeMsg &= ~(MSG_END_COMPOSITION|MSG_START_COMPOSITION);
  235. }
  236. lpImcP->iImeState = CST_INIT;
  237. *(LPDWORD)lpImcP->bSeq = 0;
  238. #if defined(CHAJEI) || defined(WINAR30) || defined(UNIIME)
  239. *(LPDWORD)&lpImcP->bSeq[4] = 0;
  240. #endif
  241. if (lpCompStr) {
  242. InitCompStr(lpCompStr);
  243. lpImcP->fdwImeMsg |= MSG_COMPOSITION;
  244. lpImcP->dwCompChar = VK_ESCAPE;
  245. lpImcP->fdwGcsFlag |= (GCS_COMPREAD|GCS_COMP|GCS_CURSORPOS|
  246. GCS_DELTASTART);
  247. }
  248. return;
  249. }
  250. /**********************************************************************/
  251. /* CompBackSpaceKey() */
  252. /**********************************************************************/
  253. void PASCAL CompBackSpaceKey(
  254. HIMC hIMC,
  255. LPINPUTCONTEXT lpIMC,
  256. LPCOMPOSITIONSTRING lpCompStr,
  257. LPPRIVCONTEXT lpImcP)
  258. {
  259. if (lpCompStr->dwCursorPos < sizeof(WCHAR) / sizeof(TCHAR)) {
  260. lpCompStr->dwCursorPos = sizeof(WCHAR) / sizeof(TCHAR);
  261. }
  262. // go back a compsoition char
  263. lpCompStr->dwCursorPos -= sizeof(WCHAR) / sizeof(TCHAR);
  264. // clean the sequence code
  265. lpImcP->bSeq[lpCompStr->dwCursorPos / (sizeof(WCHAR) / sizeof(TCHAR))] = 0;
  266. #if defined(PHON)
  267. // phonetic has index (position) for each symbol, if it is
  268. // no symbol for this position we back more
  269. for (; lpCompStr->dwCursorPos > 0; ) {
  270. if (lpImcP->bSeq[lpCompStr->dwCursorPos / (sizeof(WCHAR) /
  271. sizeof(TCHAR)) - 1]) {
  272. break;
  273. } else {
  274. // no symbol in this position skip
  275. lpCompStr->dwCursorPos -= sizeof(WCHAR) / sizeof(TCHAR);
  276. }
  277. }
  278. #endif
  279. lpImcP->fdwImeMsg |= MSG_COMPOSITION;
  280. lpImcP->dwCompChar = '\b';
  281. lpImcP->fdwGcsFlag |= (GCS_COMPREAD|GCS_COMP|GCS_CURSORPOS|
  282. GCS_DELTASTART);
  283. if (!lpCompStr->dwCursorPos) {
  284. if (lpImcP->fdwImeMsg & (MSG_ALREADY_OPEN)) {
  285. ClearCand(lpIMC);
  286. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_CLOSE_CANDIDATE) &
  287. ~(MSG_OPEN_CANDIDATE);
  288. }
  289. lpImcP->iImeState = CST_INIT;
  290. if (lpImcP->fdwImeMsg & MSG_ALREADY_START) {
  291. InitCompStr(lpCompStr);
  292. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_END_COMPOSITION) &
  293. ~(MSG_START_COMPOSITION);
  294. return;
  295. }
  296. }
  297. // reading string is composition string for some simple IMEs
  298. // delta start is the same as cursor position for backspace
  299. lpCompStr->dwCompReadAttrLen = lpCompStr->dwCompAttrLen =
  300. lpCompStr->dwCompReadStrLen = lpCompStr->dwCompStrLen =
  301. lpCompStr->dwDeltaStart = lpCompStr->dwCursorPos;
  302. // clause also back one
  303. *(LPDWORD)((LPBYTE)lpCompStr + lpCompStr->dwCompReadClauseOffset +
  304. sizeof(DWORD)) = lpCompStr->dwCompReadStrLen;
  305. #if defined(WINAR30)
  306. // for quick key
  307. if (lpIMC->fdwConversion & IME_CMODE_EUDC) {
  308. } else if (lpImeL->fdwModeConfig & MODE_CONFIG_QUICK_KEY) {
  309. Finalize(hIMC, lpIMC, lpCompStr, lpImcP, FALSE);
  310. } else {
  311. }
  312. #endif
  313. return;
  314. }
  315. #if defined(WINIME)
  316. /**********************************************************************/
  317. /* InternalCodeRange() */
  318. /**********************************************************************/
  319. BOOL PASCAL InternalCodeRange(
  320. LPPRIVCONTEXT lpImcP,
  321. WORD wCharCode)
  322. {
  323. if (!lpImcP->bSeq[0]) {
  324. if (wCharCode >= '8' && wCharCode <= 'F') {
  325. // 0x8??? - 0xF??? is OK
  326. return (TRUE);
  327. } else {
  328. // there is no 0x0??? - 0x7???
  329. return (FALSE);
  330. }
  331. } else if (!lpImcP->bSeq[1]) {
  332. if (lpImcP->bSeq[0] == (0x08 + 1)) {
  333. if (wCharCode <= '0') {
  334. // there is no 0x80??
  335. return (FALSE);
  336. } else {
  337. return (TRUE);
  338. }
  339. } else if (lpImcP->bSeq[0] == (0x0F + 1)) {
  340. if (wCharCode >= 'F') {
  341. // there is no 0xFF??
  342. return (FALSE);
  343. } else {
  344. return (TRUE);
  345. }
  346. } else {
  347. return (TRUE);
  348. }
  349. } else if (!lpImcP->bSeq[2]) {
  350. if (wCharCode < '4') {
  351. // there is no 0x??0?, 0x??1?, 0x??2?, 0x??3?
  352. return (FALSE);
  353. } else if (wCharCode < '8') {
  354. return (TRUE);
  355. } else if (wCharCode < 'A') {
  356. // there is no 0x??8? & 0x??9?
  357. return (FALSE);
  358. } else {
  359. return (TRUE);
  360. }
  361. } else if (!lpImcP->bSeq[3]) {
  362. if (lpImcP->bSeq[2] == (0x07 + 1)) {
  363. if (wCharCode >= 'F') {
  364. // there is no 0x??7F
  365. return (FALSE);
  366. } else {
  367. return (TRUE);
  368. }
  369. } else if (lpImcP->bSeq[2] == (0x0A + 1)) {
  370. if (wCharCode <= '0') {
  371. // there is no 0x??A0
  372. return (FALSE);
  373. } else {
  374. return (TRUE);
  375. }
  376. } else if (lpImcP->bSeq[2] == (0x0F + 1)) {
  377. if (wCharCode >= 'F') {
  378. // there is no 0x??FF
  379. return (FALSE);
  380. } else {
  381. return (TRUE);
  382. }
  383. } else {
  384. return (TRUE);
  385. }
  386. } else {
  387. return (TRUE);
  388. }
  389. }
  390. #endif
  391. /**********************************************************************/
  392. /* CompStrInfo() */
  393. /**********************************************************************/
  394. void PASCAL CompStrInfo(
  395. #if defined(UNIIME)
  396. LPIMEL lpImeL,
  397. #endif
  398. LPCOMPOSITIONSTRING lpCompStr,
  399. LPPRIVCONTEXT lpImcP,
  400. LPGUIDELINE lpGuideLine,
  401. WORD wCharCode)
  402. {
  403. #if defined(PHON)
  404. DWORD i;
  405. int cIndex;
  406. #endif
  407. register DWORD dwCursorPos;
  408. if (lpCompStr->dwCursorPos < lpCompStr->dwCompStrLen) {
  409. // for this kind of simple IME, previos is an error case
  410. for (dwCursorPos = lpCompStr->dwCursorPos;
  411. dwCursorPos < lpCompStr->dwCompStrLen;
  412. dwCursorPos += sizeof(WCHAR) / sizeof(TCHAR)) {
  413. lpImcP->bSeq[dwCursorPos / (sizeof(WCHAR) / sizeof(TCHAR))] = 0;
  414. }
  415. lpCompStr->dwCompReadAttrLen = lpCompStr->dwCompAttrLen =
  416. lpCompStr->dwCompReadStrLen = lpCompStr->dwCompStrLen =
  417. lpCompStr->dwDeltaStart = lpCompStr->dwCursorPos;
  418. // tell app, there is a composition char changed
  419. lpImcP->fdwImeMsg |= MSG_COMPOSITION;
  420. lpImcP->fdwGcsFlag |= GCS_COMPREAD|GCS_COMP|
  421. GCS_CURSORPOS|GCS_DELTASTART;
  422. }
  423. #if defined(PHON)
  424. if (lpCompStr->dwCursorPos >= lpImeL->nMaxKey * sizeof(WCHAR) /
  425. sizeof(TCHAR)) {
  426. // this is for ImeSetCompositionString case
  427. if (wCharCode == ' ') {
  428. // finalized char is OK
  429. lpImcP->dwCompChar = ' ';
  430. return;
  431. }
  432. }
  433. #else
  434. if (wCharCode == ' ') {
  435. // finalized char is OK
  436. lpImcP->dwCompChar = ' ';
  437. return;
  438. }
  439. #if defined(WINAR30) //**** 1996/2/5
  440. if (wCharCode == 0x27) {
  441. // finalized char is OK
  442. lpImcP->dwCompChar = 0x27;
  443. return;
  444. }
  445. #endif
  446. if (lpCompStr->dwCursorPos < lpImeL->nMaxKey * sizeof(WCHAR) /
  447. sizeof(TCHAR)) {
  448. } else if (lpGuideLine) {
  449. // exceed the max input key limitation
  450. lpGuideLine->dwLevel = GL_LEVEL_ERROR;
  451. lpGuideLine->dwIndex = GL_ID_TOOMANYSTROKE;
  452. lpImcP->fdwImeMsg |= MSG_GUIDELINE;
  453. #if defined(WINAR30) //1996/3/4
  454. dwCursorPos = lpCompStr->dwCursorPos;
  455. lpImcP->bSeq[dwCursorPos / (sizeof(WCHAR) / sizeof(TCHAR))] =
  456. (BYTE)lpImeL->wChar2SeqTbl[wCharCode - ' '];
  457. #endif
  458. return;
  459. } else {
  460. MessageBeep((UINT)-1);
  461. return;
  462. }
  463. #endif
  464. if (lpImeL->fdwErrMsg & NO_REV_LENGTH) {
  465. WORD nRevMaxKey;
  466. nRevMaxKey = (WORD)ImmEscape(lpImeL->hRevKL, (HIMC)NULL,
  467. IME_ESC_MAX_KEY, NULL);
  468. if (nRevMaxKey > lpImeL->nMaxKey) {
  469. lpImeL->nRevMaxKey = nRevMaxKey;
  470. SetCompLocalData(lpImeL);
  471. lpImcP->fdwImeMsg |= MSG_IMN_COMPOSITIONSIZE;
  472. } else {
  473. lpImeL->nRevMaxKey = lpImeL->nMaxKey;
  474. if (!nRevMaxKey) {
  475. lpImeL->hRevKL = NULL;
  476. }
  477. }
  478. lpImeL->fdwErrMsg &= ~(NO_REV_LENGTH);
  479. }
  480. if (lpImcP->fdwImeMsg & MSG_ALREADY_START) {
  481. lpImcP->fdwImeMsg &= ~(MSG_END_COMPOSITION);
  482. } else {
  483. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_START_COMPOSITION) &
  484. ~(MSG_END_COMPOSITION);
  485. }
  486. if (lpImcP->iImeState == CST_INIT) {
  487. // clean the 4 bytes in one time
  488. *(LPDWORD)lpImcP->bSeq = 0;
  489. #if defined(CHAJEI) || defined(WINAR30) || defined(UNIIME)
  490. *(LPDWORD)&lpImcP->bSeq[4] = 0;
  491. #endif
  492. }
  493. // get the sequence code, you can treat sequence code as a kind
  494. // of compression - bo, po, mo, fo to 1, 2, 3, 4
  495. // phonetic and array table file are in sequence code format
  496. dwCursorPos = lpCompStr->dwCursorPos;
  497. #if defined(PHON)
  498. cIndex = cIndexTable[wCharCode - ' '];
  499. if (cIndex * sizeof(WCHAR) / sizeof(TCHAR) >= dwCursorPos) {
  500. } else if (lpGuideLine) {
  501. lpGuideLine->dwLevel = GL_LEVEL_WARNING;
  502. lpGuideLine->dwIndex = GL_ID_READINGCONFLICT;
  503. lpImcP->fdwImeMsg |= MSG_GUIDELINE;
  504. } else {
  505. }
  506. if (lpImcP->iImeState != CST_INIT) {
  507. } else if (cIndex != 3) {
  508. } else if (lpGuideLine) {
  509. lpGuideLine->dwLevel = GL_LEVEL_WARNING;
  510. lpGuideLine->dwIndex = GL_ID_TYPINGERROR;
  511. lpImcP->fdwImeMsg |= MSG_GUIDELINE;
  512. return;
  513. } else {
  514. MessageBeep((UINT)-1);
  515. return;
  516. }
  517. lpImcP->bSeq[cIndex] = (BYTE)lpImeL->wChar2SeqTbl[wCharCode - ' '];
  518. for (i = lpCompStr->dwCompReadStrLen; i < cIndex * sizeof(WCHAR) /
  519. sizeof(TCHAR); i += sizeof(WCHAR) / sizeof(TCHAR)) {
  520. // clean sequence code
  521. lpImcP->bSeq[i / (sizeof(WCHAR) / sizeof(TCHAR))] = 0;
  522. // add full shape space among the blank part
  523. *((LPWSTR)((LPBYTE)lpCompStr + lpCompStr->dwCompReadStrOffset +
  524. sizeof(TCHAR) * i)) = sImeG.wFullSpace;
  525. }
  526. dwCursorPos = cIndex * sizeof(WCHAR) / sizeof(TCHAR);
  527. #else
  528. lpImcP->bSeq[dwCursorPos / (sizeof(WCHAR) / sizeof(TCHAR))] =
  529. (BYTE)lpImeL->wChar2SeqTbl[wCharCode - ' '];
  530. #endif
  531. // composition/reading string - bo po mo fo, reversed internal code
  532. lpImcP->dwCompChar = (DWORD)lpImeL->wSeq2CompTbl[
  533. lpImcP->bSeq[dwCursorPos / (sizeof(WCHAR) / sizeof(TCHAR))]];
  534. // assign to reading string
  535. *((LPWSTR)((LPBYTE)lpCompStr + lpCompStr->dwCompReadStrOffset +
  536. dwCursorPos * sizeof(TCHAR))) = (WCHAR)lpImcP->dwCompChar;
  537. #if defined(PHON)
  538. // if the index greater, reading should be the same with index
  539. if (lpCompStr->dwCompReadStrLen < (cIndex + 1) * (sizeof(WCHAR) /
  540. sizeof(TCHAR))) {
  541. lpCompStr->dwCompReadStrLen = (cIndex + 1) * (sizeof(WCHAR) /
  542. sizeof(TCHAR));
  543. }
  544. #else
  545. // add one composition reading for this input key
  546. if (lpCompStr->dwCompReadStrLen <= dwCursorPos) {
  547. lpCompStr->dwCompReadStrLen += sizeof(WCHAR) / sizeof(TCHAR);
  548. }
  549. #endif
  550. // composition string is reading string for some simple IMEs
  551. lpCompStr->dwCompStrLen = lpCompStr->dwCompReadStrLen;
  552. // composition/reading attribute length is equal to reading string length
  553. lpCompStr->dwCompReadAttrLen = lpCompStr->dwCompReadStrLen;
  554. lpCompStr->dwCompAttrLen = lpCompStr->dwCompStrLen;
  555. #ifdef UNICODE
  556. *((LPBYTE)lpCompStr + lpCompStr->dwCompReadAttrOffset +
  557. dwCursorPos) = ATTR_TARGET_CONVERTED;
  558. #else
  559. // composition/reading attribute - IME has converted these chars
  560. *((LPWORD)((LPBYTE)lpCompStr + lpCompStr->dwCompReadAttrOffset +
  561. dwCursorPos)) = ((ATTR_TARGET_CONVERTED << 8)|ATTR_TARGET_CONVERTED);
  562. #endif
  563. // composition/reading clause, 1 clause only
  564. lpCompStr->dwCompReadClauseLen = 2 * sizeof(DWORD);
  565. lpCompStr->dwCompClauseLen = lpCompStr->dwCompReadClauseLen;
  566. *(LPDWORD)((LPBYTE)lpCompStr + lpCompStr->dwCompReadClauseOffset +
  567. sizeof(DWORD)) = lpCompStr->dwCompReadStrLen;
  568. // delta start from previous cursor position
  569. lpCompStr->dwDeltaStart = lpCompStr->dwCursorPos;
  570. #if defined(PHON)
  571. if (dwCursorPos < lpCompStr->dwDeltaStart) {
  572. lpCompStr->dwDeltaStart = dwCursorPos;
  573. }
  574. #endif
  575. // cursor is next to the composition string
  576. lpCompStr->dwCursorPos = lpCompStr->dwCompStrLen;
  577. lpImcP->iImeState = CST_INPUT;
  578. // tell app, there is a composition char generated
  579. lpImcP->fdwImeMsg |= MSG_COMPOSITION;
  580. #if !defined(UNICODE)
  581. // swap the char from reversed internal code to internal code
  582. lpImcP->dwCompChar = HIBYTE(lpImcP->dwCompChar) |
  583. (LOBYTE(lpImcP->dwCompChar) << 8);
  584. #endif
  585. lpImcP->fdwGcsFlag |= GCS_COMPREAD|GCS_COMP|GCS_CURSORPOS|GCS_DELTASTART;
  586. return;
  587. }
  588. /**********************************************************************/
  589. /* Finalize() */
  590. /* Return vlaue */
  591. /* the number of candidates in the candidate list */
  592. /**********************************************************************/
  593. UINT PASCAL Finalize( // finalize Chinese word(s) by searching table
  594. #if defined(UNIIME)
  595. LPINSTDATAL lpInstL,
  596. LPIMEL lpImeL,
  597. #endif
  598. HIMC hIMC,
  599. LPINPUTCONTEXT lpIMC,
  600. LPCOMPOSITIONSTRING lpCompStr,
  601. LPPRIVCONTEXT lpImcP,
  602. BOOL fFinalized)
  603. {
  604. LPCANDIDATEINFO lpCandInfo;
  605. LPCANDIDATELIST lpCandList;
  606. UINT nCand;
  607. #if defined(WINIME) || defined(UNICDIME)
  608. // quick key case
  609. if (!lpImcP->bSeq[1]) {
  610. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_CLOSE_CANDIDATE) &
  611. ~(MSG_OPEN_CANDIDATE|MSG_CHANGE_CANDIDATE);
  612. return (0);
  613. }
  614. #endif
  615. if (!lpIMC->hCandInfo) {
  616. return (0);
  617. }
  618. lpCandInfo = (LPCANDIDATEINFO)ImmLockIMCC(lpIMC->hCandInfo);
  619. if (!lpCandInfo) {
  620. return (0);
  621. }
  622. lpCandList = (LPCANDIDATELIST)
  623. ((LPBYTE)lpCandInfo + lpCandInfo->dwOffset[0]);
  624. // start from 0
  625. lpCandList->dwCount = 0;
  626. // default start from 0
  627. lpCandList->dwPageStart = lpCandList->dwSelection = 0;
  628. #if defined(PHON)
  629. if (!fFinalized) {
  630. lpImcP->bSeq[3] = 0x26; // ' '
  631. }
  632. #endif
  633. if (!ConvertSeqCode2Pattern(
  634. #if defined(UNIIME)
  635. lpImeL,
  636. #endif
  637. lpImcP->bSeq, lpImcP)) {
  638. goto FinSrchOvr;
  639. }
  640. #if defined(WINAR30)
  641. if (!fFinalized) {
  642. if (lpImcP->iGhostCard != lpImeL->nMaxKey) {
  643. // do not preview the ghost card '*'
  644. goto FinSrchOvr;
  645. } else if (lpImcP->dwLastWildCard) {
  646. // do not preview the wild card '?'
  647. goto FinSrchOvr;
  648. } else if (!lpImcP->bSeq[2]) {
  649. SearchQuickKey(lpCandList, lpImcP);
  650. } else {
  651. // search the IME tables
  652. SearchTbl(0, lpCandList, lpImcP);
  653. }
  654. } else {
  655. #else
  656. {
  657. #endif
  658. // search the IME tables
  659. SearchTbl(
  660. #if defined(UNIIME)
  661. lpImeL,
  662. #endif
  663. 0, lpCandList, lpImcP);
  664. }
  665. #if !defined(WINIME) && !defined(UNICDIME) && !defined(ROMANIME)
  666. #if defined(WINAR30)
  667. if (!fFinalized) {
  668. // quick key is not in fault tolerance table & user dictionary
  669. goto FinSrchOvr;
  670. }
  671. #endif
  672. if (lpInstL->hUsrDicMem) {
  673. SearchUsrDic(
  674. #if defined(UNIIME)
  675. lpImeL,
  676. #endif
  677. lpCandList, lpImcP);
  678. }
  679. #endif
  680. FinSrchOvr:
  681. nCand = lpCandList->dwCount;
  682. if (!fFinalized) {
  683. #if defined(PHON)
  684. lpImcP->bSeq[3] = 0x00; // clean previous assign one
  685. #endif
  686. // for quick key
  687. lpCandInfo->dwCount = 1;
  688. // open composition candidate UI window for the string(s)
  689. if (lpImcP->fdwImeMsg & MSG_ALREADY_OPEN) {
  690. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_CHANGE_CANDIDATE) &
  691. ~(MSG_CLOSE_CANDIDATE);
  692. } else {
  693. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_OPEN_CANDIDATE) &
  694. ~(MSG_CLOSE_CANDIDATE);
  695. }
  696. } else if (nCand == 0) { // nothing found, error
  697. // move cursor back because this is wrong
  698. #if defined(PHON)
  699. // go back a compsoition char
  700. lpCompStr->dwCursorPos -= sizeof(WCHAR) / sizeof(TCHAR);
  701. for (; lpCompStr->dwCursorPos > 0; ) {
  702. if (lpImcP->bSeq[lpCompStr->dwCursorPos / (sizeof(WCHAR) /
  703. sizeof(TCHAR)) - 1]) {
  704. break;
  705. } else {
  706. // no symbol in this position skip
  707. lpCompStr->dwCursorPos -= sizeof(WCHAR) / sizeof(TCHAR);
  708. }
  709. }
  710. if (lpCompStr->dwCursorPos < sizeof(WCHAR) / sizeof(TCHAR)) {
  711. lpCompStr->dwCursorPos = 0;
  712. lpImcP->iImeState = CST_INIT;
  713. }
  714. #elif defined(QUICK) || defined(WINIME) || defined(UNICDIME)
  715. if (lpCompStr->dwCursorPos > sizeof(WCHAR) / sizeof(TCHAR)) {
  716. lpCompStr->dwCursorPos = lpCompStr->dwCompReadStrLen -
  717. sizeof(WCHAR) / sizeof(TCHAR);
  718. } else {
  719. lpCompStr->dwCursorPos = 0;
  720. lpImcP->iImeState = CST_INIT;
  721. }
  722. #else
  723. lpCompStr->dwCursorPos = 0;
  724. lpImcP->iImeState = CST_INIT;
  725. #endif
  726. lpCompStr->dwDeltaStart = lpCompStr->dwCursorPos;
  727. if (lpImcP->fdwImeMsg & MSG_ALREADY_START) {
  728. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_COMPOSITION) &
  729. ~(MSG_END_COMPOSITION);
  730. } else {
  731. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_START_COMPOSITION) &
  732. ~(MSG_END_COMPOSITION);
  733. }
  734. // for quick key
  735. lpCandInfo->dwCount = 0;
  736. // close the quick key
  737. if (lpImcP->fdwImeMsg & MSG_ALREADY_OPEN) {
  738. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_CLOSE_CANDIDATE) &
  739. ~(MSG_OPEN_CANDIDATE|MSG_CHANGE_CANDIDATE);
  740. } else {
  741. lpImcP->fdwImeMsg &= ~(MSG_OPEN_CANDIDATE|MSG_CLOSE_CANDIDATE);
  742. }
  743. lpImcP->fdwGcsFlag |= GCS_CURSORPOS|GCS_DELTASTART;
  744. } else if (nCand == 1) { // only one choice
  745. SelectOneCand(
  746. #if defined(UNIIME)
  747. lpImeL,
  748. #endif
  749. hIMC, lpIMC, lpCompStr, lpImcP, lpCandList);
  750. } else {
  751. lpCandInfo->dwCount = 1;
  752. // there are more than one strings, open composition candidate UI window
  753. if (lpImcP->fdwImeMsg & MSG_ALREADY_OPEN) {
  754. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_CHANGE_CANDIDATE) &
  755. ~(MSG_CLOSE_CANDIDATE);
  756. } else {
  757. lpImcP->fdwImeMsg = (lpImcP->fdwImeMsg | MSG_OPEN_CANDIDATE) &
  758. ~(MSG_CLOSE_CANDIDATE);
  759. }
  760. lpImcP->iImeState = CST_CHOOSE;
  761. }
  762. if (fFinalized) {
  763. LPGUIDELINE lpGuideLine;
  764. lpGuideLine = ImmLockIMCC(lpIMC->hGuideLine);
  765. if (!lpGuideLine) {
  766. } else if (!nCand) {
  767. // nothing found, end user, you have an error now
  768. lpGuideLine->dwLevel = GL_LEVEL_ERROR;
  769. lpGuideLine->dwIndex = GL_ID_TYPINGERROR;
  770. lpImcP->fdwImeMsg |= MSG_GUIDELINE;
  771. } else if (nCand == 1) {
  772. } else if (lpImeL->fwProperties1 & IMEPROP_CAND_NOBEEP_GUIDELINE) {
  773. } else {
  774. lpGuideLine->dwLevel = GL_LEVEL_WARNING;
  775. // multiple selection
  776. lpGuideLine->dwIndex = GL_ID_CHOOSECANDIDATE;
  777. lpImcP->fdwImeMsg |= MSG_GUIDELINE;
  778. }
  779. if (lpGuideLine) {
  780. ImmUnlockIMCC(lpIMC->hGuideLine);
  781. }
  782. }
  783. ImmUnlockIMCC(lpIMC->hCandInfo);
  784. return (nCand);
  785. }
  786. /**********************************************************************/
  787. /* CompWord() */
  788. /**********************************************************************/
  789. void PASCAL CompWord( // compose the Chinese word(s) according to
  790. // input key
  791. #if defined(UNIIME)
  792. LPINSTDATAL lpInstL,
  793. LPIMEL lpImeL,
  794. #endif
  795. WORD wCharCode,
  796. HIMC hIMC,
  797. LPINPUTCONTEXT lpIMC,
  798. LPCOMPOSITIONSTRING lpCompStr,
  799. LPGUIDELINE lpGuideLine,
  800. LPPRIVCONTEXT lpImcP)
  801. {
  802. if (!lpCompStr) {
  803. MessageBeep((UINT)-1);
  804. return;
  805. }
  806. // escape key
  807. if (wCharCode == VK_ESCAPE) { // not good to use VK as char, but...
  808. CompEscapeKey(lpIMC, lpCompStr, lpGuideLine, lpImcP);
  809. return;
  810. }
  811. if (wCharCode == '\b') {
  812. CompBackSpaceKey(hIMC, lpIMC, lpCompStr, lpImcP);
  813. return;
  814. }
  815. if (wCharCode >= 'a' && wCharCode <= 'z') {
  816. wCharCode ^= 0x20;
  817. }
  818. #if defined(PHON)
  819. {
  820. // convert to standard phonetic layout
  821. wCharCode = bStandardLayout[lpImeL->nReadLayout][wCharCode - ' '];
  822. }
  823. #endif
  824. #if defined(WINIME)
  825. if (InternalCodeRange(lpImcP, wCharCode)) {
  826. } else if (lpGuideLine) {
  827. lpGuideLine->dwLevel = GL_LEVEL_ERROR;
  828. lpGuideLine->dwIndex = GL_ID_TYPINGERROR;
  829. lpImcP->fdwImeMsg |= MSG_GUIDELINE;
  830. return;
  831. } else {
  832. MessageBeep((UINT)-1);
  833. return;
  834. }
  835. #endif
  836. // build up composition string info
  837. CompStrInfo(
  838. #if defined(UNIIME)
  839. lpImeL,
  840. #endif
  841. lpCompStr, lpImcP, lpGuideLine, wCharCode);
  842. if (lpIMC->fdwConversion & IME_CMODE_EUDC) {
  843. #if defined(PHON) || defined(WINIME) || defined(UNICDIME)
  844. if (lpCompStr->dwCompReadStrLen >= sizeof(WCHAR) / sizeof(TCHAR) *
  845. lpImeL->nMaxKey) {
  846. #else
  847. if (wCharCode == ' ') {
  848. #endif
  849. lpImcP->fdwImeMsg |= MSG_COMPOSITION;
  850. lpImcP->fdwGcsFlag |= GCS_RESULTREAD|GCS_RESULTSTR;
  851. }
  852. } else {
  853. #if defined(PHON) || defined(WINIME) || defined(UNICDIME)
  854. if (lpCompStr->dwCompReadStrLen < sizeof(WCHAR) / sizeof(TCHAR) *
  855. lpImeL->nMaxKey) {
  856. #elif defined(QUICK)
  857. if (wCharCode != ' ' &&
  858. lpCompStr->dwCompReadStrLen < sizeof(WCHAR) / sizeof(TCHAR) * 2) {
  859. #else
  860. if (wCharCode != ' ') {
  861. #endif
  862. #if defined(WINAR30)
  863. // quick key
  864. if(wCharCode != 0x27) //19963/9
  865. {
  866. if (lpImeL->fdwModeConfig & MODE_CONFIG_QUICK_KEY) {
  867. Finalize(hIMC, lpIMC, lpCompStr, lpImcP, FALSE);
  868. }
  869. }
  870. else
  871. {
  872. Finalize(
  873. #if defined(UNIIME)
  874. lpInstL, lpImeL,
  875. #endif
  876. hIMC, lpIMC, lpCompStr, lpImcP, TRUE);
  877. }
  878. #endif
  879. return;
  880. }
  881. Finalize(
  882. #if defined(UNIIME)
  883. lpInstL, lpImeL,
  884. #endif
  885. hIMC, lpIMC, lpCompStr, lpImcP, TRUE);
  886. }
  887. return;
  888. }
  889. #endif