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.

556 lines
18 KiB

  1. /**************************************************************************\
  2. * Module Name: input.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * IME key input management routines for imm32 dll
  7. *
  8. * History:
  9. * 01-Apr-1996 takaok split from hotkey.c
  10. \**************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #ifdef HIRO_DEBUG
  14. #define D(x) x
  15. #else
  16. #define D(x)
  17. #endif
  18. /***************************************************************************\
  19. * ImmProcessKey (Callback from Win32K.SYS)
  20. *
  21. * Call ImeProcessKey and IME hotkey handler
  22. *
  23. * History:
  24. * 01-Mar-1996 TakaoK Created
  25. \***************************************************************************/
  26. DWORD WINAPI ImmProcessKey(
  27. HWND hWnd,
  28. HKL hkl,
  29. UINT uVKey,
  30. LPARAM lParam,
  31. DWORD dwHotKeyID)
  32. {
  33. HIMC hIMC = ImmGetContext(hWnd);
  34. PIMEDPI pImeDpi = ImmLockImeDpi(hkl);
  35. DWORD dwReturn = 0;
  36. #if DBG
  37. if (dwHotKeyID >= IME_KHOTKEY_FIRST && dwHotKeyID <= IME_KHOTKEY_LAST) {
  38. TAGMSG2(DBGTAG_IMM, "ImmProcessKey: Kor IME Hotkeys should not come here: dwHotKeyID=%x, uVKey=%x", dwHotKeyID, uVKey);
  39. }
  40. #endif
  41. ImmAssert(dwHotKeyID != IME_KHOTKEY_ENGLISH &&
  42. dwHotKeyID != IME_KHOTKEY_SHAPE_TOGGLE &&
  43. dwHotKeyID != IME_KHOTKEY_HANJACONVERT);
  44. //
  45. // call ImeProcessKey
  46. //
  47. if (pImeDpi != NULL) {
  48. PINPUTCONTEXT pInputContext = ImmLockIMC(hIMC);
  49. if (pInputContext != NULL) {
  50. BOOLEAN fTruncateWideVK = FALSE;
  51. BOOLEAN fCallIme = TRUE;
  52. BOOLEAN fSkipThisKey = FALSE;
  53. #ifdef LATER
  54. //
  55. // if the current imc is not open and IME doesn't need
  56. // keys when being closed, we don't pass any keyboard
  57. // input to ime except hotkey and keys that change
  58. // the keyboard status.
  59. //
  60. if ((pImeDpi->fdwProperty & IME_PROP_NO_KEYS_ON_CLOSE) &&
  61. !pInputContext->fOpen &&
  62. uVKey != VK_SHIFT &&
  63. uVKey != VK_CONTROL &&
  64. uVKey != VK_CAPITAL &&
  65. uVKey != VK_KANA &&
  66. uVKey != VK_NUMLOCK &&
  67. uVKey != VK_SCROLL) {
  68. // Check if Korea Hanja conversion mode
  69. if(!(pimc->fdwConvMode & IME_CMODE_HANJACONVERT)) {
  70. fCallIme = FALSE;
  71. }
  72. }
  73. else
  74. #endif
  75. //
  76. // Protect IMEs which are unaware of wide virtual keys.
  77. //
  78. if ((BYTE)uVKey == VK_PACKET &&
  79. (pImeDpi->ImeInfo.fdwProperty & IME_PROP_ACCEPT_WIDE_VKEY) == 0) {
  80. if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) {
  81. //
  82. // Since this IME is not ready to accept wide VKey, we should
  83. // truncate it.
  84. //
  85. fTruncateWideVK = TRUE;
  86. }
  87. else {
  88. //
  89. // Hmm, this guy is ANSI IME, and does not declare Wide Vkey awareness.
  90. // Let's guess this one is not ready to accept Wide Vkey, so let's not
  91. // pass it to this guy.
  92. // And if it is opened, we'd better skip this key for safety.
  93. //
  94. fCallIme = FALSE;
  95. if (pInputContext->fOpen) {
  96. fSkipThisKey = TRUE;
  97. }
  98. }
  99. }
  100. if (fCallIme) {
  101. PBYTE pbKeyState = (PBYTE)ImmLocalAlloc(0, 256);
  102. ImmAssert(fSkipThisKey == FALSE);
  103. if (pbKeyState != NULL) {
  104. if (GetKeyboardState(pbKeyState)) {
  105. UINT uVKeyIme = uVKey;
  106. if (fTruncateWideVK) {
  107. uVKeyIme &= 0xffff;
  108. }
  109. if ( (*pImeDpi->pfn.ImeProcessKey)(hIMC, uVKeyIme, lParam, pbKeyState) ) {
  110. //
  111. // if the return value of ImeProcessKey is TRUE,
  112. // it means the key is the one that the ime is
  113. // waiting for.
  114. //
  115. pInputContext->fChgMsg = TRUE;
  116. pInputContext->uSavedVKey = uVKey;
  117. dwReturn |= IPHK_PROCESSBYIME;
  118. }
  119. }
  120. ImmLocalFree(pbKeyState);
  121. }
  122. }
  123. else if (fSkipThisKey) {
  124. dwReturn |= IPHK_SKIPTHISKEY;
  125. ImmAssert((dwReturn & (IPHK_PROCESSBYIME | IPHK_HOTKEY)) == 0);
  126. }
  127. ImmUnlockIMC(hIMC);
  128. }
  129. ImmUnlockImeDpi(pImeDpi);
  130. }
  131. //
  132. // call hotkey handler
  133. //
  134. #if !defined(CUAS_ENABLE)
  135. if (dwHotKeyID != IME_INVALID_HOTKEY && HotKeyIDDispatcher(hWnd, hIMC, hkl, dwHotKeyID)) {
  136. // Backward compat:
  137. // On Japanese system, some applications may want VK_KANJI.
  138. if ((uVKey != VK_KANJI) ||
  139. (dwHotKeyID != IME_JHOTKEY_CLOSE_OPEN)) {
  140. dwReturn |= IPHK_HOTKEY;
  141. }
  142. }
  143. #else
  144. //
  145. // Check MSCTF's keyboard hook is running in this thread.
  146. // We can use MSCTF's hotkey handler only when MSCTF's keyboard hook
  147. // is installed and running.
  148. //
  149. if (CtfImmIsCiceroStartedInThread()) {
  150. BOOL fHandled = FALSE;
  151. if (Internal_CtfImeProcessCicHotkey(hIMC, uVKey, lParam)) {
  152. // Backward compat:
  153. // On Japanese system, some applications may want VK_KANJI.
  154. if ((uVKey != VK_KANJI) ||
  155. (dwHotKeyID != IME_JHOTKEY_CLOSE_OPEN)) {
  156. dwReturn |= IPHK_HOTKEY;
  157. }
  158. fHandled = TRUE;
  159. }
  160. if (!fHandled && IS_IME_KBDLAYOUT(hkl))
  161. {
  162. goto TryIMEHotkey;
  163. }
  164. } else {
  165. TryIMEHotkey:
  166. if (dwHotKeyID != IME_INVALID_HOTKEY) {
  167. if (HotKeyIDDispatcher(hWnd, hIMC, hkl, dwHotKeyID)) {
  168. // Backward compat:
  169. // On Japanese system, some applications may want VK_KANJI.
  170. if ((uVKey != VK_KANJI) ||
  171. (dwHotKeyID != IME_JHOTKEY_CLOSE_OPEN)) {
  172. dwReturn |= IPHK_HOTKEY;
  173. }
  174. }
  175. }
  176. }
  177. #endif
  178. //
  179. // some 3.x application doesn't like to see
  180. // VK_PROCESSKEY.
  181. //
  182. if (dwReturn & IPHK_PROCESSBYIME) {
  183. DWORD dwImeCompat = ImmGetAppCompatFlags(hIMC);
  184. if (dwImeCompat & IMECOMPAT_NOVKPROCESSKEY) {
  185. // Korea 3.x application doesn't like to see dummy finalize VK_PROCESSKEY
  186. // and IME hot key.
  187. if ( PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) == LANG_KOREAN &&
  188. ( (uVKey == VK_PROCESSKEY) || (dwReturn & IPHK_HOTKEY) ) ) {
  189. ImmReleaseContext(hWnd, hIMC);
  190. return dwReturn;
  191. }
  192. ImmTranslateMessage(hWnd, WM_KEYDOWN, VK_PROCESSKEY, lParam);
  193. dwReturn &= ~IPHK_PROCESSBYIME;
  194. dwReturn |= IPHK_SKIPTHISKEY;
  195. }
  196. }
  197. ImmReleaseContext(hWnd, hIMC);
  198. return dwReturn;
  199. }
  200. #define TRANSMSGCOUNT 256
  201. /***************************************************************************\
  202. * ImmTranslateMessage (Called from user\client\ntstubs.c\TranslateMessage())
  203. *
  204. * Call ImeToAsciiEx()
  205. *
  206. * History:
  207. * 01-Mar-1996 TakaoK Created
  208. \***************************************************************************/
  209. BOOL ImmTranslateMessage(
  210. HWND hwnd,
  211. UINT message,
  212. WPARAM wParam,
  213. LPARAM lParam)
  214. {
  215. HIMC hImc;
  216. PINPUTCONTEXT pInputContext;
  217. BOOL fReturn = FALSE;
  218. HKL hkl;
  219. PIMEDPI pImeDpi = NULL;
  220. PBYTE pbKeyState;
  221. PTRANSMSG pTransMsg;
  222. PTRANSMSGLIST pTransMsgList;
  223. DWORD dwSize;
  224. UINT uVKey;
  225. INT iNum;
  226. UNREFERENCED_PARAMETER(wParam);
  227. //
  228. // we're interested in only those keyboard messages.
  229. //
  230. switch (message) {
  231. case WM_KEYDOWN:
  232. case WM_KEYUP:
  233. case WM_SYSKEYDOWN:
  234. case WM_SYSKEYUP:
  235. break;
  236. default:
  237. return FALSE;
  238. }
  239. //
  240. // input context is necessary for further handling
  241. //
  242. hImc = ImmGetContext(hwnd);
  243. pInputContext = ImmLockIMC(hImc);
  244. if (pInputContext == NULL) {
  245. ImmReleaseContext(hwnd, hImc);
  246. return FALSE;
  247. }
  248. //
  249. // At first, handle VK_PROCESSKEY generated by IME.
  250. //
  251. if (!pInputContext->fChgMsg) {
  252. if ((iNum=pInputContext->dwNumMsgBuf) != 0) {
  253. pTransMsg = (PTRANSMSG)ImmLockIMCC(pInputContext->hMsgBuf);
  254. if (pTransMsg != NULL) {
  255. ImmPostMessages(hwnd, hImc, iNum, pTransMsg);
  256. ImmUnlockIMCC(pInputContext->hMsgBuf);
  257. fReturn = TRUE;
  258. }
  259. pInputContext->dwNumMsgBuf = 0;
  260. }
  261. goto ExitITM;
  262. }
  263. pInputContext->fChgMsg = FALSE;
  264. //
  265. // retrieve the keyboard layout and IME entry points
  266. //
  267. hkl = GetKeyboardLayout( GetWindowThreadProcessId(hwnd, NULL) );
  268. pImeDpi = ImmLockImeDpi(hkl);
  269. if (pImeDpi == NULL) {
  270. RIPMSG1(RIP_WARNING, "ImmTranslateMessage pImeDpi is NULL(hkl=%x)", hkl);
  271. goto ExitITM;
  272. }
  273. pbKeyState = ImmLocalAlloc(0, 256);
  274. if ( pbKeyState == NULL ) {
  275. RIPMSG0(RIP_WARNING, "ImmTranslateMessage out of memory" );
  276. goto ExitITM;
  277. }
  278. if (!GetKeyboardState(pbKeyState)) {
  279. RIPMSG0(RIP_WARNING, "ImmTranslateMessage GetKeyboardState() failed" );
  280. ImmLocalFree( pbKeyState );
  281. goto ExitITM;
  282. }
  283. //
  284. // Translate the saved vkey into character code if needed
  285. //
  286. uVKey = pInputContext->uSavedVKey;
  287. if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST) {
  288. if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) {
  289. WCHAR wcTemp;
  290. iNum = ToUnicode(pInputContext->uSavedVKey, // virtual-key code
  291. HIWORD(lParam), // scan code
  292. pbKeyState, // key-state array
  293. &wcTemp, // buffer for translated key
  294. 1, // size of buffer
  295. 0);
  296. if (iNum == 1) {
  297. //
  298. // hi word : unicode character code
  299. // hi byte of lo word : zero
  300. // lo byte of lo word : virtual key
  301. //
  302. uVKey = (uVKey & 0x00ff) | ((UINT)wcTemp << 16);
  303. }
  304. } else {
  305. WORD wTemp = 0;
  306. iNum = ToAsciiEx(pInputContext->uSavedVKey, // virtual-key code
  307. HIWORD(lParam), // scan code
  308. pbKeyState, // key-state array
  309. &wTemp, // buffer for translated key
  310. 0, // active-menu flag
  311. hkl);
  312. ImmAssert(iNum <= 2);
  313. if (iNum > 0) {
  314. //
  315. // hi word : should be zero
  316. // hi byte of lo word : character code
  317. // lo byte of lo word : virtual key
  318. //
  319. uVKey = (uVKey & 0x00FF) | ((UINT)wTemp << 8);
  320. if ((BYTE)uVKey == VK_PACKET) {
  321. //
  322. // If ANSI IME is wide vkey aware, its ImeToAsciiEx will receive the uVKey
  323. // as follows:
  324. //
  325. // 31 24 23 16 15 8 7 0
  326. // +----------------+-----------------------------+-------------------+---------------+
  327. // | 24~31:reserved | 16~23:trailing byte(if any) | 8~15:leading byte | 0~7:VK_PACKET |
  328. // +----------------+-----------------------------+-------------------+---------------+
  329. //
  330. ImmAssert(pImeDpi->ImeInfo.fdwProperty & IME_PROP_ACCEPT_WIDE_VKEY);
  331. }
  332. else {
  333. uVKey &= 0xffff;
  334. }
  335. }
  336. }
  337. }
  338. dwSize = FIELD_OFFSET(TRANSMSGLIST, TransMsg)
  339. + TRANSMSGCOUNT * sizeof(TRANSMSG);
  340. pTransMsgList = (PTRANSMSGLIST)ImmLocalAlloc(0, dwSize);
  341. if (pTransMsgList == NULL) {
  342. RIPMSG0(RIP_WARNING, "ImmTranslateMessage out of memory" );
  343. ImmLocalFree(pbKeyState);
  344. goto ExitITM;
  345. }
  346. pTransMsgList->uMsgCount = TRANSMSGCOUNT;
  347. iNum = (*pImeDpi->pfn.ImeToAsciiEx)(uVKey,
  348. HIWORD(lParam),
  349. pbKeyState,
  350. pTransMsgList,
  351. 0,
  352. hImc);
  353. if (iNum > TRANSMSGCOUNT) {
  354. //
  355. // The message buffer is not big enough. IME put messages
  356. // into hMsgBuf in the input context.
  357. //
  358. pTransMsg = (PTRANSMSG)ImmLockIMCC(pInputContext->hMsgBuf);
  359. if (pTransMsg != NULL) {
  360. ImmPostMessages(hwnd, hImc, iNum, pTransMsg);
  361. ImmUnlockIMCC(pInputContext->hMsgBuf);
  362. }
  363. #ifdef LATER
  364. // Shouldn't we need this ?
  365. fReturn = TRUE;
  366. #endif
  367. } else if (iNum > 0) {
  368. ImmPostMessages(hwnd, hImc, iNum, &pTransMsgList->TransMsg[0]);
  369. fReturn = TRUE;
  370. }
  371. ImmLocalFree(pbKeyState);
  372. ImmLocalFree(pTransMsgList);
  373. ExitITM:
  374. ImmUnlockImeDpi(pImeDpi);
  375. ImmUnlockIMC(hImc);
  376. ImmReleaseContext(hwnd, hImc);
  377. return fReturn;
  378. }
  379. /***************************************************************************\
  380. * ImmPostMessages(Called from ImmTranslateMessage() )
  381. *
  382. * Post IME messages to application. If application is 3.x, messages
  383. * are translated to old IME messages.
  384. *
  385. * History:
  386. * 01-Mar-1996 TakaoK Created
  387. \***************************************************************************/
  388. VOID
  389. ImmPostMessages(
  390. HWND hWnd,
  391. HIMC hImc,
  392. INT iNum,
  393. PTRANSMSG pTransMsg)
  394. {
  395. INT i;
  396. BOOL fAnsiIME;
  397. PCLIENTIMC pClientImc;
  398. PTRANSMSG pTransMsgTemp, pTransMsgBuf = NULL;
  399. //
  400. // Check if the IME is unicode or not.
  401. // The message buffer contains unicode messages
  402. // if the IME is unicode.
  403. //
  404. pClientImc = ImmLockClientImc(hImc);
  405. if (pClientImc == NULL) {
  406. RIPMSG1(RIP_WARNING,
  407. "ImmPostMessages: Invalid hImc %lx.", hImc);
  408. return;
  409. }
  410. fAnsiIME = ! TestICF(pClientImc, IMCF_UNICODE);
  411. ImmUnlockClientImc(pClientImc);
  412. //
  413. // translate messages to 3.x format if the App's version is 3.x.
  414. //
  415. pTransMsgTemp = pTransMsg;
  416. if (GetClientInfo()->dwExpWinVer < VER40) {
  417. DWORD dwLangId = PRIMARYLANGID(
  418. LANGIDFROMLCID(
  419. GetSystemDefaultLCID()));
  420. if ( (dwLangId == LANG_KOREAN && TransGetLevel(hWnd) == 3) ||
  421. dwLangId == LANG_JAPANESE ) {
  422. pTransMsgBuf = ImmLocalAlloc(0, iNum * sizeof(TRANSMSG));
  423. if (pTransMsgBuf != NULL) {
  424. RtlCopyMemory(pTransMsgBuf, pTransMsg, iNum * sizeof(TRANSMSG));
  425. iNum = WINNLSTranslateMessage(iNum,
  426. pTransMsgBuf,
  427. hImc,
  428. fAnsiIME,
  429. dwLangId );
  430. pTransMsgTemp = pTransMsgBuf;
  431. }
  432. }
  433. }
  434. for (i = 0; i < iNum; i++) {
  435. if (fAnsiIME) {
  436. PostMessageA(hWnd,
  437. pTransMsgTemp->message,
  438. pTransMsgTemp->wParam,
  439. pTransMsgTemp->lParam);
  440. } else {
  441. PostMessageW(hWnd,
  442. pTransMsgTemp->message,
  443. pTransMsgTemp->wParam,
  444. pTransMsgTemp->lParam);
  445. }
  446. pTransMsgTemp++;
  447. }
  448. if (pTransMsgBuf != NULL) {
  449. ImmLocalFree(pTransMsgBuf);
  450. }
  451. }
  452. UINT WINNLSTranslateMessage(
  453. INT iNum, // number of messages in the source buffer
  454. PTRANSMSG pTransMsg, // source buffer that contains 4.0 style messages
  455. HIMC hImc, // input context handle
  456. BOOL fAnsi, // TRUE if pdwt contains ANSI messages
  457. DWORD dwLangId ) // language ID ( KOREAN or JAPANESE )
  458. {
  459. LPINPUTCONTEXT pInputContext;
  460. LPCOMPOSITIONSTRING pCompStr;
  461. UINT uiRet = 0;
  462. pInputContext = ImmLockIMC(hImc);
  463. if (pInputContext == NULL) {
  464. return uiRet;
  465. }
  466. pCompStr = (LPCOMPOSITIONSTRING)ImmLockIMCC( pInputContext->hCompStr );
  467. if (pCompStr != NULL) {
  468. if (dwLangId == LANG_KOREAN) {
  469. uiRet = WINNLSTranslateMessageK((UINT)iNum,
  470. pTransMsg,
  471. pInputContext,
  472. pCompStr,
  473. fAnsi );
  474. } else if ( dwLangId == LANG_JAPANESE ) {
  475. uiRet = WINNLSTranslateMessageJ((UINT)iNum,
  476. pTransMsg,
  477. pInputContext,
  478. pCompStr,
  479. fAnsi );
  480. }
  481. ImmUnlockIMCC(pInputContext->hCompStr);
  482. }
  483. ImmUnlockIMC(hImc);
  484. return uiRet;
  485. }