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.

627 lines
16 KiB

  1. /*************************************************
  2. * toascii.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. /* ProcessKey() */
  13. /* Return Value: */
  14. /* different state which input key will change IME to */
  15. /**********************************************************************/
  16. UINT PASCAL ProcessKey( // this key will cause the IME go to what state
  17. WORD wCharCode,
  18. UINT uVirtKey,
  19. UINT uScanCode,
  20. CONST LPBYTE lpbKeyState,
  21. LPINPUTCONTEXT lpIMC,
  22. LPPRIVCONTEXT lpImcP)
  23. {
  24. if (!lpIMC)
  25. {
  26. return (CST_INVALID);
  27. }
  28. if (!lpImcP)
  29. {
  30. return (CST_INVALID);
  31. }
  32. if (uVirtKey == VK_MENU)
  33. {
  34. //
  35. // no ALT key
  36. //
  37. return (CST_INVALID);
  38. }
  39. else if (uScanCode & KF_ALTDOWN)
  40. {
  41. //
  42. // no ALT-xx key
  43. //
  44. return (CST_INVALID);
  45. }
  46. else if (uVirtKey == VK_CONTROL)
  47. {
  48. //
  49. // no CTRL key
  50. //
  51. return (CST_INVALID);
  52. }
  53. else if (lpbKeyState[VK_CONTROL] & 0x80)
  54. {
  55. //
  56. // no CTRL-xx key
  57. //
  58. return (CST_INVALID);
  59. }
  60. else if (uVirtKey == VK_SHIFT)
  61. {
  62. //
  63. // no SHIFT key
  64. //
  65. return (CST_INVALID);
  66. }
  67. else if (!lpIMC->fOpen)
  68. {
  69. //
  70. // don't compose in close status
  71. //
  72. return (CST_INVALID);
  73. }
  74. else if (lpIMC->fdwConversion & IME_CMODE_NOCONVERSION)
  75. {
  76. //
  77. // don't compose in no coversion status
  78. //
  79. return (CST_INVALID);
  80. }
  81. else if (lpIMC->fdwConversion & IME_CMODE_CHARCODE)
  82. {
  83. //
  84. // not support
  85. //
  86. return (CST_INVALID);
  87. }
  88. if (uVirtKey >= VK_NUMPAD0 && uVirtKey <= VK_DIVIDE)
  89. {
  90. //
  91. // A PM decision: all numpad should be past to app
  92. //
  93. return (CST_ALPHANUMERIC);
  94. }
  95. if (!(lpIMC->fdwConversion & IME_CMODE_NATIVE))
  96. {
  97. return (CST_INVALID);
  98. }
  99. else if (!(lpbKeyState[VK_SHIFT] & 0x80))
  100. {
  101. //
  102. // need more check for IME_CMODE_NATIVE
  103. //
  104. }
  105. else if (wCharCode < ' ' && wCharCode > '~')
  106. {
  107. return (CST_INVALID);
  108. }
  109. //
  110. // need more check for IME_CMODE_NATIVE
  111. //
  112. if (wCharCode >= ' ' && wCharCode <= 'z')
  113. {
  114. wCharCode = bUpper[wCharCode - ' '];
  115. }
  116. if (uVirtKey == VK_ESCAPE)
  117. {
  118. register LPGUIDELINE lpGuideLine;
  119. register UINT iImeState;
  120. if (lpImcP->fdwImeMsg & MSG_ALREADY_START)
  121. {
  122. return (CST_INPUT);
  123. }
  124. lpGuideLine = ImmLockIMCC(lpIMC->hGuideLine);
  125. if (!lpGuideLine)
  126. {
  127. return (CST_INVALID);
  128. }
  129. else if (lpGuideLine->dwLevel == GL_LEVEL_NOGUIDELINE)
  130. {
  131. iImeState = CST_INVALID;
  132. }
  133. else
  134. {
  135. //
  136. // need this key to clean information string or guideline state
  137. //
  138. iImeState = CST_INPUT;
  139. }
  140. ImmUnlockIMCC(lpIMC->hGuideLine);
  141. return (iImeState);
  142. }
  143. else if (uVirtKey == VK_BACK)
  144. {
  145. if (lpImcP->fdwImeMsg & MSG_ALREADY_START)
  146. {
  147. return (CST_INPUT);
  148. }
  149. else
  150. {
  151. return (CST_INVALID);
  152. }
  153. }
  154. //
  155. // check finalize char
  156. //
  157. if (wCharCode == ' ' && lpImcP->iImeState == CST_INIT)
  158. {
  159. return (CST_INVALID);
  160. }
  161. else if (lpImeL->fCompChar[(wCharCode - ' ') >> 4] &
  162. fMask[wCharCode & 0x000F])
  163. {
  164. return (CST_INPUT);
  165. }
  166. else if (wCharCode >= 'G' && wCharCode <= 'Z' ||
  167. wCharCode >= 'g' && wCharCode <= 'z')
  168. {
  169. //
  170. // PM decision says we should not send these letters to input
  171. // to avoid confusing users. We special handle this case by
  172. // introducing CST_BLOCKINPUT flag.
  173. //
  174. return (CST_BLOCKINPUT);
  175. }
  176. return (CST_INVALID);
  177. }
  178. /**********************************************************************/
  179. /* ImeProcessKey() / UniImeProcessKey() */
  180. /* Return Value: */
  181. /* TRUE - successful, FALSE - failure */
  182. /**********************************************************************/
  183. // if this key is need by IME?
  184. BOOL WINAPI ImeProcessKey(
  185. HIMC hIMC,
  186. UINT uVirtKey,
  187. LPARAM lParam,
  188. CONST LPBYTE lpbKeyState)
  189. {
  190. LPINPUTCONTEXT lpIMC;
  191. LPPRIVCONTEXT lpImcP;
  192. BYTE szAscii[4];
  193. int nChars;
  194. BOOL fRet;
  195. //
  196. // can't compose in NULL hIMC
  197. //
  198. if (!hIMC)
  199. {
  200. return (FALSE);
  201. }
  202. lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
  203. if (!lpIMC)
  204. {
  205. return (FALSE);
  206. }
  207. lpImcP = (LPPRIVCONTEXT)ImmLockIMCC(lpIMC->hPrivate);
  208. if (!lpImcP)
  209. {
  210. ImmUnlockIMC(hIMC);
  211. return (FALSE);
  212. }
  213. nChars = ToAscii(uVirtKey, HIWORD(lParam), lpbKeyState, (LPVOID)szAscii, 0);
  214. if (!nChars)
  215. {
  216. szAscii[0] = 0;
  217. }
  218. if (ProcessKey( (WORD)szAscii[0],
  219. uVirtKey,
  220. HIWORD(lParam),
  221. lpbKeyState,
  222. lpIMC,
  223. lpImcP) == CST_INVALID)
  224. {
  225. fRet = FALSE;
  226. }
  227. else
  228. {
  229. fRet = TRUE;
  230. }
  231. ImmUnlockIMCC(lpIMC->hPrivate);
  232. ImmUnlockIMC(hIMC);
  233. return (fRet);
  234. }
  235. /**********************************************************************/
  236. /* TranslateToAscii() */
  237. /* Translates the key input to WM_CHAR as keyboard drivers does */
  238. /* */
  239. /* Return Value: */
  240. /* the number of translated chars */
  241. /**********************************************************************/
  242. UINT PASCAL TranslateToAscii(
  243. UINT uScanCode,
  244. LPTRANSMSG lpTransMsg,
  245. WORD wCharCode)
  246. {
  247. if (wCharCode)
  248. {
  249. //
  250. // one char code
  251. //
  252. lpTransMsg->message = WM_CHAR;
  253. lpTransMsg->wParam = wCharCode;
  254. lpTransMsg->lParam = (uScanCode << 16) | 1UL;
  255. return (1);
  256. }
  257. //
  258. // no char code case
  259. //
  260. return (0);
  261. }
  262. /**********************************************************************/
  263. /* TranslateImeMessage() */
  264. /* Return Value: */
  265. /* the number of translated messages */
  266. /**********************************************************************/
  267. UINT PASCAL TranslateImeMessage(
  268. LPTRANSMSGLIST lpTransBuf,
  269. LPINPUTCONTEXT lpIMC,
  270. LPPRIVCONTEXT lpImcP)
  271. {
  272. UINT uNumMsg;
  273. UINT i;
  274. BOOL bLockMsgBuf;
  275. LPTRANSMSG lpTransMsg;
  276. uNumMsg = 0;
  277. bLockMsgBuf = FALSE;
  278. for (i = 0; i < 2; i++)
  279. {
  280. if (lpImcP->fdwImeMsg & MSG_IMN_COMPOSITIONSIZE)
  281. {
  282. if (!i)
  283. {
  284. uNumMsg++;
  285. }
  286. else
  287. {
  288. lpTransMsg->message = WM_IME_NOTIFY;
  289. lpTransMsg->wParam = IMN_PRIVATE;
  290. lpTransMsg->lParam = IMN_PRIVATE_COMPOSITION_SIZE;
  291. lpTransMsg += 1;
  292. }
  293. }
  294. if (lpImcP->fdwImeMsg & MSG_START_COMPOSITION)
  295. {
  296. if (!(lpImcP->fdwImeMsg & MSG_ALREADY_START))
  297. {
  298. if (!i)
  299. {
  300. uNumMsg++;
  301. }
  302. else
  303. {
  304. lpTransMsg->message = WM_IME_STARTCOMPOSITION;
  305. lpTransMsg->wParam = 0;
  306. lpTransMsg->lParam = 0;
  307. lpTransMsg += 1;
  308. lpImcP->fdwImeMsg |= MSG_ALREADY_START;
  309. }
  310. }
  311. }
  312. if (lpImcP->fdwImeMsg & MSG_IMN_COMPOSITIONPOS)
  313. {
  314. if (!i)
  315. {
  316. uNumMsg++;
  317. }
  318. else
  319. {
  320. lpTransMsg->message = WM_IME_NOTIFY;
  321. lpTransMsg->wParam = IMN_SETCOMPOSITIONWINDOW;
  322. lpTransMsg->lParam = 0;
  323. lpTransMsg += 1;
  324. }
  325. }
  326. if (lpImcP->fdwImeMsg & MSG_COMPOSITION)
  327. {
  328. if (!i)
  329. {
  330. uNumMsg++;
  331. }
  332. else
  333. {
  334. lpTransMsg->message = WM_IME_COMPOSITION;
  335. lpTransMsg->wParam = lpImcP->dwCompChar;
  336. lpTransMsg->lParam = lpImcP->fdwGcsFlag;
  337. lpTransMsg += 1;
  338. }
  339. }
  340. if (lpImcP->fdwImeMsg & MSG_GUIDELINE)
  341. {
  342. if (!i)
  343. {
  344. uNumMsg++;
  345. }
  346. else
  347. {
  348. lpTransMsg->message = WM_IME_NOTIFY;
  349. lpTransMsg->wParam = IMN_GUIDELINE;
  350. lpTransMsg->lParam = 0;
  351. lpTransMsg += 1;
  352. }
  353. }
  354. if (lpImcP->fdwImeMsg & MSG_IMN_PAGEUP)
  355. {
  356. if (!i)
  357. {
  358. uNumMsg++;
  359. }
  360. else
  361. {
  362. lpTransMsg->message = WM_IME_NOTIFY;
  363. lpTransMsg->wParam = IMN_PRIVATE;
  364. lpTransMsg->lParam = IMN_PRIVATE_PAGEUP;
  365. lpTransMsg += 1;
  366. }
  367. }
  368. if (lpImcP->fdwImeMsg & MSG_END_COMPOSITION)
  369. {
  370. if (lpImcP->fdwImeMsg & MSG_ALREADY_START)
  371. {
  372. if (!i)
  373. {
  374. uNumMsg++;
  375. }
  376. else
  377. {
  378. lpTransMsg->message = WM_IME_ENDCOMPOSITION;
  379. lpTransMsg->wParam = 0;
  380. lpTransMsg->lParam = 0;
  381. lpTransMsg += 1;
  382. lpImcP->fdwImeMsg &= ~(MSG_ALREADY_START);
  383. }
  384. }
  385. }
  386. if (lpImcP->fdwImeMsg & MSG_IMN_TOGGLE_UI)
  387. {
  388. if (!i)
  389. {
  390. uNumMsg++;
  391. }
  392. else
  393. {
  394. lpTransMsg->message = WM_IME_NOTIFY;
  395. lpTransMsg->wParam = IMN_PRIVATE;
  396. lpTransMsg->lParam = IMN_PRIVATE_TOGGLE_UI;
  397. lpTransMsg += 1;
  398. }
  399. }
  400. if (!i)
  401. {
  402. HIMCC hMem;
  403. if (!uNumMsg)
  404. {
  405. return (uNumMsg);
  406. }
  407. if (lpImcP->fdwImeMsg & MSG_IN_IMETOASCIIEX)
  408. {
  409. UINT uNumMsgLimit;
  410. // ++ for the start position of buffer to strore the messages
  411. uNumMsgLimit = lpTransBuf->uMsgCount;
  412. if (uNumMsg <= uNumMsgLimit)
  413. {
  414. lpTransMsg = lpTransBuf->TransMsg;
  415. continue;
  416. }
  417. }
  418. // we need to use message buffer
  419. if (!lpIMC->hMsgBuf)
  420. {
  421. lpIMC->hMsgBuf = ImmCreateIMCC(uNumMsg * sizeof(TRANSMSG));
  422. lpIMC->dwNumMsgBuf = 0;
  423. }
  424. else if (hMem = ImmReSizeIMCC(lpIMC->hMsgBuf,
  425. (lpIMC->dwNumMsgBuf + uNumMsg) * sizeof(TRANSMSG)))
  426. {
  427. if (hMem != lpIMC->hMsgBuf)
  428. {
  429. ImmDestroyIMCC(lpIMC->hMsgBuf);
  430. lpIMC->hMsgBuf = hMem;
  431. }
  432. }
  433. else
  434. {
  435. return (0);
  436. }
  437. lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf);
  438. if (!lpTransMsg)
  439. {
  440. return (0);
  441. }
  442. lpTransMsg += lpIMC->dwNumMsgBuf;
  443. bLockMsgBuf = TRUE;
  444. }
  445. else
  446. {
  447. if (bLockMsgBuf)
  448. {
  449. ImmUnlockIMCC(lpIMC->hMsgBuf);
  450. }
  451. }
  452. }
  453. return (uNumMsg);
  454. }
  455. /**********************************************************************/
  456. /* ImeToAsciiEx() / UniImeToAsciiex() */
  457. /* Return Value: */
  458. /* the number of translated message */
  459. /**********************************************************************/
  460. UINT WINAPI ImeToAsciiEx(
  461. UINT uVirtKey,
  462. UINT uScanCode,
  463. CONST LPBYTE lpbKeyState,
  464. LPTRANSMSGLIST lpTransBuf,
  465. UINT fuState,
  466. HIMC hIMC)
  467. {
  468. WORD wCharCode;
  469. LPINPUTCONTEXT lpIMC;
  470. LPCOMPOSITIONSTRING lpCompStr;
  471. LPGUIDELINE lpGuideLine;
  472. LPPRIVCONTEXT lpImcP;
  473. UINT uNumMsg;
  474. int iRet;
  475. wCharCode = HIWORD(uVirtKey);
  476. uVirtKey = LOBYTE(uVirtKey);
  477. if (!hIMC)
  478. {
  479. return TranslateToAscii(uScanCode,
  480. &lpTransBuf->TransMsg[0],
  481. wCharCode);
  482. }
  483. lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
  484. if (!lpIMC)
  485. {
  486. return TranslateToAscii(uScanCode,
  487. &lpTransBuf->TransMsg[0],
  488. wCharCode);
  489. }
  490. lpImcP = (LPPRIVCONTEXT)ImmLockIMCC(lpIMC->hPrivate);
  491. if (!lpImcP)
  492. {
  493. ImmUnlockIMC(hIMC);
  494. return TranslateToAscii(uScanCode,
  495. &lpTransBuf->TransMsg[0],
  496. wCharCode);
  497. }
  498. // Now all composition realated information already pass to app
  499. // a brand new start
  500. lpImcP->fdwImeMsg = lpImcP->fdwImeMsg & (MSG_STATIC_STATE) |
  501. MSG_IN_IMETOASCIIEX;
  502. iRet = ProcessKey(wCharCode,
  503. uVirtKey,
  504. uScanCode,
  505. lpbKeyState,
  506. lpIMC,
  507. lpImcP);
  508. if (iRet == CST_ALPHABET)
  509. {
  510. // A-Z convert to a-z, a-z convert to A-Z
  511. wCharCode ^= 0x20;
  512. iRet = CST_ALPHANUMERIC;
  513. }
  514. if (iRet == CST_ALPHANUMERIC)
  515. {
  516. uNumMsg = TranslateImeMessage(lpTransBuf, lpIMC, lpImcP);
  517. uNumMsg += TranslateToAscii(uScanCode,
  518. &lpTransBuf->TransMsg[uNumMsg],
  519. wCharCode);
  520. }
  521. else if (iRet == CST_INPUT)
  522. {
  523. lpCompStr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
  524. lpGuideLine = (LPGUIDELINE)ImmLockIMCC(lpIMC->hGuideLine);
  525. CompWord(wCharCode, hIMC, lpIMC, lpCompStr, lpGuideLine, lpImcP);
  526. if (lpGuideLine)
  527. {
  528. ImmUnlockIMCC(lpIMC->hGuideLine);
  529. }
  530. if (lpCompStr)
  531. {
  532. ImmUnlockIMCC(lpIMC->hCompStr);
  533. }
  534. uNumMsg = TranslateImeMessage(lpTransBuf, lpIMC, lpImcP);
  535. }
  536. else if (iRet == CST_BLOCKINPUT)
  537. {
  538. //
  539. // This codepoint should be blocked. We don't compose it for IME.
  540. // Nor do we pass it to normal input. Instead, we beep.
  541. //
  542. MessageBeep(-1);
  543. uNumMsg = 0;
  544. }
  545. else
  546. {
  547. uNumMsg = TranslateToAscii(uScanCode,
  548. &lpTransBuf->TransMsg[0],
  549. wCharCode);
  550. }
  551. lpImcP->fdwImeMsg &= (MSG_STATIC_STATE);
  552. lpImcP->fdwGcsFlag = 0;
  553. ImmUnlockIMCC(lpIMC->hPrivate);
  554. ImmUnlockIMC(hIMC);
  555. return (uNumMsg);
  556. }