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.

646 lines
20 KiB

  1. /**************************************************************************\
  2. * Module Name: immhotky.c (user32 side IME hotkey handling)
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * IME hot key management routines for imm32 dll
  7. *
  8. * History:
  9. * 03-Jan-1996 hiroyama Created
  10. \**************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. typedef struct tagFE_KEYBOARDS {
  14. BOOLEAN fJPN : 1;
  15. BOOLEAN fCHT : 1;
  16. BOOLEAN fCHS : 1;
  17. BOOLEAN fKOR : 1;
  18. } FE_KEYBOARDS;
  19. //
  20. // internal functions
  21. //
  22. BOOL CliSaveImeHotKey(DWORD dwID, UINT uModifiers, UINT uVKey, HKL hkl, BOOL fDelete);
  23. BOOL CliImmSetHotKeyWorker(DWORD dwID, UINT uModifiers, UINT uVKey, HKL hkl, DWORD dwAction);
  24. VOID NumToHexAscii(DWORD, PTSTR);
  25. BOOL CliGetImeHotKeysFromRegistry(void);
  26. BOOL CliSetSingleHotKey(PKEY_BASIC_INFORMATION pKeyInfo, HANDLE hKey);
  27. VOID CliSetDefaultImeHotKeys(PCIMEHOTKEY ph, INT num, BOOL fCheckExistingHotKey);
  28. VOID CliGetPreloadKeyboardLayouts(FE_KEYBOARDS* pFeKbds);
  29. //
  30. // IMM hotkey related registry keys under HKEY_CURRENT_USER
  31. //
  32. CONST TCHAR *szaRegImmHotKeys[] = {
  33. TEXT("Control Panel"),
  34. TEXT("Input Method"),
  35. TEXT("Hot Keys"),
  36. NULL
  37. };
  38. CONST TCHAR szRegImeHotKey[] = TEXT("Control Panel\\Input Method\\Hot Keys");
  39. CONST TCHAR szRegKeyboardPreload[] = TEXT("Keyboard Layout\\Preload");
  40. CONST TCHAR szRegVK[] = TEXT("Virtual Key");
  41. CONST TCHAR szRegMOD[] = TEXT("Key Modifiers");
  42. CONST TCHAR szRegHKL[] = TEXT("Target IME");
  43. //
  44. // Default IME HotKey Tables
  45. //
  46. // CR:takaok - move this to the resource if you have time
  47. //
  48. CONST IMEHOTKEY DefaultHotKeyTableJ[]= {
  49. {IME_JHOTKEY_CLOSE_OPEN, VK_KANJI, MOD_IGNORE_ALL_MODIFIER, NULL}
  50. };
  51. CONST INT DefaultHotKeyNumJ = sizeof(DefaultHotKeyTableJ) / sizeof(IMEHOTKEY);
  52. CONST IMEHOTKEY DefaultHotKeyTableT[] = {
  53. { IME_THOTKEY_IME_NONIME_TOGGLE, VK_SPACE, MOD_BOTH_SIDES|MOD_CONTROL, NULL },
  54. { IME_THOTKEY_SHAPE_TOGGLE, VK_SPACE, MOD_BOTH_SIDES|MOD_SHIFT, NULL }
  55. };
  56. CONST INT DefaultHotKeyNumT = sizeof(DefaultHotKeyTableT) / sizeof(IMEHOTKEY);
  57. CONST IMEHOTKEY DefaultHotKeyTableC[] = {
  58. { IME_CHOTKEY_IME_NONIME_TOGGLE, VK_SPACE, MOD_BOTH_SIDES|MOD_CONTROL, NULL },
  59. { IME_CHOTKEY_SHAPE_TOGGLE, VK_SPACE, MOD_BOTH_SIDES|MOD_SHIFT, NULL }
  60. };
  61. CONST INT DefaultHotKeyNumC = sizeof(DefaultHotKeyTableC) / sizeof(IMEHOTKEY);
  62. #if 0 // just FYI.
  63. CONST IMEHOTKEY DefaultHotKeyTableK[] = {
  64. { IME_KHOTKEY_ENGLISH, VK_HANGEUL, MOD_IGNORE_ALL_MODIFIER, NULL },
  65. { IME_KHOTKEY_SHAPE_TOGGLE, VK_JUNJA, MOD_IGNORE_ALL_MODIFIER, NULL },
  66. { IME_KHOTKEY_HANJACONVERT, VK_HANJA, MOD_IGNORE_ALL_MODIFIER, NULL }
  67. };
  68. CONST INT DefaultHotKeyNumK = sizeof(DefaultHotKeyTableK) / sizeof(IMEHOTKEY);
  69. #endif
  70. //
  71. // Set language flags.
  72. //
  73. VOID SetFeKeyboardFlags(LANGID langid, FE_KEYBOARDS* pFeKbds)
  74. {
  75. switch (langid) {
  76. case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL):
  77. case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG):
  78. pFeKbds->fCHT = TRUE;
  79. break;
  80. case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED):
  81. case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE):
  82. pFeKbds->fCHS = TRUE;
  83. break;
  84. case MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT):
  85. pFeKbds->fJPN = TRUE;
  86. break;
  87. case MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT):
  88. pFeKbds->fKOR = TRUE;
  89. break;
  90. }
  91. }
  92. /***************************************************************************\
  93. * ImmInitializeHotkeys()
  94. *
  95. * Called from user\client\UpdatePerUserSystemParameters()
  96. *
  97. * Read the User registry and set the IME hotkey.
  98. *
  99. * History:
  100. * 25-Mar-1996 TakaoK Created
  101. \***************************************************************************/
  102. VOID CliImmInitializeHotKeys(DWORD dwAction, HKL hkl)
  103. {
  104. FE_KEYBOARDS feKbds = { 0, 0, 0, 0, };
  105. BOOL fFoundAny;
  106. UNREFERENCED_PARAMETER(hkl);
  107. // First, initialize the hotkey list
  108. CliImmSetHotKeyWorker(0, 0, 0, NULL, ISHK_INITIALIZE);
  109. // Check if the user has customized IME hotkeys
  110. // (they're stored in the registry)
  111. fFoundAny = CliGetImeHotKeysFromRegistry();
  112. if (dwAction == ISHK_INITIALIZE) {
  113. TAGMSG0(DBGTAG_IMM, "Setting IME HotKeys for Init.\n");
  114. // Get the user's default locale and set its flag
  115. SetFeKeyboardFlags(LANGIDFROMLCID(GetUserDefaultLCID()), &feKbds);
  116. // Get preloaded keyboards' locales and set their flags
  117. CliGetPreloadKeyboardLayouts(&feKbds);
  118. }
  119. else {
  120. UINT i;
  121. UINT nLayouts;
  122. LPHKL lphkl;
  123. TAGMSG0(DBGTAG_IMM, "Setting IME HotKeys for Add.\n");
  124. nLayouts = NtUserGetKeyboardLayoutList(0, NULL);
  125. if (nLayouts == 0) {
  126. return;
  127. }
  128. lphkl = UserLocalAlloc(0, nLayouts * sizeof(HKL));
  129. if (lphkl == NULL) {
  130. return;
  131. }
  132. NtUserGetKeyboardLayoutList(nLayouts, lphkl);
  133. for (i = 0; i < nLayouts; ++i) {
  134. //
  135. // Set language flags. By its definition, LOWORD(hkl) is LANGID
  136. //
  137. SetFeKeyboardFlags(LOWORD(HandleToUlong(lphkl[i])), &feKbds);
  138. }
  139. UserLocalFree(lphkl);
  140. }
  141. if (feKbds.fJPN) {
  142. TAGMSG0(DBGTAG_IMM, "JPN KL Preloaded.\n");
  143. CliSetDefaultImeHotKeys(DefaultHotKeyTableJ, DefaultHotKeyNumJ, fFoundAny);
  144. }
  145. if (feKbds.fKOR) {
  146. TAGMSG0(DBGTAG_IMM, "KOR KL Preloaded, but KOR hotkeys will not be registered.\n");
  147. }
  148. if (feKbds.fCHT) {
  149. TAGMSG0(DBGTAG_IMM, "CHT KL Preloaded.\n");
  150. CliSetDefaultImeHotKeys(DefaultHotKeyTableT, DefaultHotKeyNumT, fFoundAny);
  151. }
  152. if (feKbds.fCHS) {
  153. TAGMSG0(DBGTAG_IMM, "CHS KL Preloaded.\n");
  154. CliSetDefaultImeHotKeys(DefaultHotKeyTableC, DefaultHotKeyNumC, fFoundAny);
  155. }
  156. }
  157. VOID CliSetDefaultImeHotKeys(PCIMEHOTKEY ph, INT num, BOOL fNeedToCheckExistingHotKey)
  158. {
  159. IMEHOTKEY hkt;
  160. while( num-- > 0 ) {
  161. //
  162. // Set IME hotkey only if there is no such
  163. // hotkey in the registry
  164. //
  165. if (!fNeedToCheckExistingHotKey ||
  166. !NtUserGetImeHotKey(ph->dwHotKeyID, &hkt.uModifiers, &hkt.uVKey, &hkt.hKL)) {
  167. CliImmSetHotKeyWorker(ph->dwHotKeyID,
  168. ph->uModifiers,
  169. ph->uVKey,
  170. ph->hKL,
  171. ISHK_ADD);
  172. }
  173. ph++;
  174. }
  175. }
  176. /***************************************************************************\
  177. * CliGetPreloadKeyboardLayouts()
  178. *
  179. * Read the User registry and enumerate values in Keyboard Layouts\Preload
  180. * to see which FE languages are to be preloaded.
  181. *
  182. * History:
  183. * 03-Dec-1997 Hiroyama Created
  184. \***************************************************************************/
  185. VOID CliGetPreloadKeyboardLayouts(FE_KEYBOARDS* pFeKbds)
  186. {
  187. UINT i;
  188. WCHAR szPreLoadee[4]; // up to 999 preloads
  189. WCHAR lpszName[KL_NAMELENGTH];
  190. UNICODE_STRING UnicodeString;
  191. HKL hkl;
  192. for (i = 1; i < 1000; i++) {
  193. wsprintf(szPreLoadee, L"%d", i);
  194. if ((GetPrivateProfileStringW(
  195. L"Preload",
  196. szPreLoadee,
  197. L"", // default = NULL
  198. lpszName, // output buffer
  199. KL_NAMELENGTH,
  200. L"keyboardlayout.ini") == -1 ) || (*lpszName == L'\0')) {
  201. break;
  202. }
  203. RtlInitUnicodeString(&UnicodeString, lpszName);
  204. RtlUnicodeStringToInteger(&UnicodeString, 16L, (PULONG)&hkl);
  205. RIPMSG2(RIP_VERBOSE, "PreLoaded HKL(%d): %08X\n", i, hkl);
  206. //
  207. // Set language flags. By its definition, LOWORD(hkl) is LANGID
  208. //
  209. SetFeKeyboardFlags(LOWORD(HandleToUlong(hkl)), pFeKbds);
  210. }
  211. }
  212. BOOL CliGetImeHotKeysFromRegistry()
  213. {
  214. BOOL fFoundAny = FALSE;
  215. HANDLE hCurrentUserKey;
  216. HANDLE hKeyHotKeys;
  217. OBJECT_ATTRIBUTES Obja;
  218. UNICODE_STRING SubKeyName;
  219. NTSTATUS Status;
  220. ULONG uIndex;
  221. //
  222. // Open the current user registry key
  223. //
  224. Status = RtlOpenCurrentUser(MAXIMUM_ALLOWED, &hCurrentUserKey);
  225. if (!NT_SUCCESS(Status)) {
  226. return fFoundAny;
  227. }
  228. RtlInitUnicodeString( &SubKeyName, szRegImeHotKey );
  229. InitializeObjectAttributes( &Obja,
  230. &SubKeyName,
  231. OBJ_CASE_INSENSITIVE,
  232. hCurrentUserKey,
  233. NULL);
  234. Status = NtOpenKey( &hKeyHotKeys, KEY_READ, &Obja );
  235. if (!NT_SUCCESS(Status)) {
  236. NtClose( hCurrentUserKey );
  237. return fFoundAny;
  238. }
  239. for (uIndex = 0; TRUE; uIndex++) {
  240. BYTE KeyBuffer[sizeof(KEY_BASIC_INFORMATION) + 16 * sizeof(WCHAR)];
  241. PKEY_BASIC_INFORMATION pKeyInfo;
  242. ULONG ResultLength;
  243. pKeyInfo = (PKEY_BASIC_INFORMATION)KeyBuffer;
  244. Status = NtEnumerateKey(hKeyHotKeys,
  245. uIndex,
  246. KeyBasicInformation,
  247. pKeyInfo,
  248. sizeof( KeyBuffer ),
  249. &ResultLength );
  250. if (NT_SUCCESS(Status)) {
  251. if (CliSetSingleHotKey(pKeyInfo, hKeyHotKeys)) {
  252. fFoundAny = TRUE;
  253. }
  254. } else if (Status == STATUS_NO_MORE_ENTRIES) {
  255. break;
  256. }
  257. }
  258. NtClose(hKeyHotKeys);
  259. NtClose(hCurrentUserKey);
  260. return fFoundAny;
  261. }
  262. DWORD CliReadRegistryValue(HANDLE hKey, PCWSTR pName)
  263. {
  264. BYTE ValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(UCHAR)];
  265. PKEY_VALUE_PARTIAL_INFORMATION pKeyValue;
  266. UNICODE_STRING ValueName;
  267. ULONG ResultLength;
  268. NTSTATUS Status;
  269. pKeyValue = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  270. RtlInitUnicodeString(&ValueName, pName);
  271. Status = NtQueryValueKey(hKey,
  272. &ValueName,
  273. KeyValuePartialInformation,
  274. pKeyValue,
  275. sizeof(ValueBuffer),
  276. &ResultLength );
  277. if (NT_SUCCESS(Status) && pKeyValue->DataLength > 3) {
  278. //
  279. // In Win95 registry, these items are written as BYTE data...
  280. //
  281. return (DWORD)(MAKEWORD( pKeyValue->Data[0], pKeyValue->Data[1])) |
  282. (((DWORD)(MAKEWORD( pKeyValue->Data[2], pKeyValue->Data[3]))) << 16);
  283. }
  284. return 0;
  285. }
  286. BOOL CliSetSingleHotKey(PKEY_BASIC_INFORMATION pKeyInfo, HANDLE hKey)
  287. {
  288. UNICODE_STRING SubKeyName;
  289. HANDLE hKeySingleHotKey;
  290. OBJECT_ATTRIBUTES Obja;
  291. DWORD dwID = 0;
  292. UINT uVKey = 0;
  293. UINT uModifiers = 0;
  294. HKL hKL = NULL;
  295. NTSTATUS Status;
  296. SubKeyName.Buffer = (PWSTR)&(pKeyInfo->Name[0]);
  297. SubKeyName.Length = (USHORT)pKeyInfo->NameLength;
  298. SubKeyName.MaximumLength = (USHORT)pKeyInfo->NameLength;
  299. InitializeObjectAttributes(&Obja,
  300. &SubKeyName,
  301. OBJ_CASE_INSENSITIVE,
  302. hKey,
  303. NULL);
  304. Status = NtOpenKey(&hKeySingleHotKey, KEY_READ, &Obja);
  305. if (!NT_SUCCESS(Status)) {
  306. return FALSE;
  307. }
  308. RtlUnicodeStringToInteger(&SubKeyName, 16L, &dwID);
  309. uVKey = CliReadRegistryValue(hKeySingleHotKey, szRegVK);
  310. uModifiers = CliReadRegistryValue(hKeySingleHotKey, szRegMOD);
  311. hKL = (HKL)LongToHandle( CliReadRegistryValue(hKeySingleHotKey, szRegHKL) );
  312. NtClose(hKeySingleHotKey);
  313. return CliImmSetHotKeyWorker(dwID, uModifiers, uVKey, hKL, ISHK_ADD);
  314. }
  315. /***************************************************************************\
  316. * ImmSetHotKey()
  317. *
  318. * Private API for IMEs and the control panel.
  319. *
  320. * History:
  321. * 25-Mar-1996 TakaoK Created
  322. \***************************************************************************/
  323. FUNCLOG4(LOG_GENERAL, BOOL, WINAPI, CliImmSetHotKey, DWORD, dwID, UINT, uModifiers, UINT, uVKey, HKL, hkl)
  324. BOOL WINAPI CliImmSetHotKey(
  325. DWORD dwID,
  326. UINT uModifiers,
  327. UINT uVKey,
  328. HKL hkl)
  329. {
  330. BOOL fResult;
  331. BOOL fTmp;
  332. BOOL fDelete = (uVKey == 0 );
  333. if (fDelete) {
  334. //
  335. // Removing an IME hotkey from the list in the kernel side
  336. // should not be failed, if we succeed to remove the IME
  337. // hotkey entry from the registry. Therefore CliSaveImeHotKey
  338. // is called first.
  339. //
  340. fResult = CliSaveImeHotKey( dwID, uModifiers, uVKey, hkl, fDelete );
  341. if (fResult) {
  342. fTmp = CliImmSetHotKeyWorker( dwID, uModifiers, uVKey, hkl, ISHK_REMOVE );
  343. UserAssert(fTmp);
  344. }
  345. } else {
  346. //
  347. // CliImmSetHotKeyWorker should be called first since
  348. // adding an IME hotkey into the list in the kernel side
  349. // will be failed in various reasons.
  350. //
  351. fResult = CliImmSetHotKeyWorker(dwID, uModifiers, uVKey, hkl, ISHK_ADD);
  352. if (fResult) {
  353. fResult = CliSaveImeHotKey(dwID, uModifiers, uVKey, hkl, fDelete);
  354. if (!fResult) {
  355. //
  356. // We failed to save the hotkey to the registry.
  357. // We need to remove the entry from the IME hotkey
  358. // list in the kernel side.
  359. //
  360. fTmp = CliImmSetHotKeyWorker(dwID, uModifiers, uVKey, hkl, ISHK_REMOVE);
  361. UserAssert(fTmp);
  362. }
  363. }
  364. }
  365. return fResult;
  366. }
  367. /***************************************************************************\
  368. * CliSaveImeHotKey()
  369. *
  370. * Put/Remove the specified IME hotkey entry from the registry
  371. *
  372. * History:
  373. * 25-Mar-1996 TakaoK Created
  374. \***************************************************************************/
  375. BOOL CliSaveImeHotKey(DWORD id, UINT mod, UINT vk, HKL hkl, BOOL fDelete)
  376. {
  377. HKEY hKey, hKeyParent;
  378. INT i;
  379. LONG lResult;
  380. TCHAR szHex[16];
  381. if (fDelete) {
  382. TCHAR szRegTmp[(sizeof(szRegImeHotKey) / sizeof(TCHAR) + 1 + 8 + 1)];
  383. lstrcpy(szRegTmp, szRegImeHotKey);
  384. lstrcat(szRegTmp, TEXT("\\"));
  385. NumToHexAscii(id, szHex);
  386. lstrcat(szRegTmp, szHex);
  387. lResult = RegDeleteKeyW(HKEY_CURRENT_USER, szRegTmp);
  388. if (lResult != ERROR_SUCCESS) {
  389. RIPERR1(lResult, RIP_WARNING,
  390. "CliSaveImeHotKey: deleting %s failed", szRegTmp);
  391. return FALSE;
  392. }
  393. return TRUE;
  394. }
  395. hKeyParent = HKEY_CURRENT_USER;
  396. for (i = 0; szaRegImmHotKeys[i] != NULL; i++) {
  397. lResult = RegCreateKeyExW(hKeyParent,
  398. szaRegImmHotKeys[i],
  399. 0,
  400. NULL,
  401. REG_OPTION_NON_VOLATILE,
  402. KEY_WRITE|KEY_READ,
  403. NULL,
  404. &hKey,
  405. NULL );
  406. RegCloseKey(hKeyParent);
  407. if (lResult == ERROR_SUCCESS) {
  408. hKeyParent = hKey;
  409. } else {
  410. RIPERR1(lResult, RIP_WARNING,
  411. "CliSaveImeHotKey: creating %s failed", szaRegImmHotKeys[i]);
  412. return FALSE;
  413. }
  414. }
  415. NumToHexAscii(id, szHex);
  416. lResult = RegCreateKeyExW(hKeyParent,
  417. szHex,
  418. 0,
  419. NULL,
  420. REG_OPTION_NON_VOLATILE,
  421. KEY_WRITE|KEY_READ,
  422. NULL,
  423. &hKey,
  424. NULL );
  425. RegCloseKey(hKeyParent);
  426. if (lResult != ERROR_SUCCESS) {
  427. RIPERR1(lResult, RIP_WARNING,
  428. "CliSaveImeHotKey: creating %s failed", szHex );
  429. return FALSE;
  430. }
  431. lResult = RegSetValueExW(hKey,
  432. szRegVK,
  433. 0,
  434. REG_BINARY,
  435. (LPBYTE)&vk,
  436. sizeof(DWORD));
  437. if (lResult != ERROR_SUCCESS) {
  438. RegCloseKey(hKey);
  439. CliSaveImeHotKey(id, vk, mod, hkl, TRUE);
  440. RIPERR1( lResult, RIP_WARNING,
  441. "SaveImeHotKey:setting value on %s failed", szRegVK );
  442. return ( FALSE );
  443. }
  444. lResult = RegSetValueExW(hKey,
  445. szRegMOD,
  446. 0,
  447. REG_BINARY,
  448. (LPBYTE)&mod,
  449. sizeof(DWORD));
  450. if (lResult != ERROR_SUCCESS) {
  451. RegCloseKey(hKey);
  452. CliSaveImeHotKey(id, vk, mod, hkl, TRUE);
  453. RIPERR1(lResult, RIP_WARNING,
  454. "CliSaveImeHotKey: setting value on %s failed", szRegMOD);
  455. return FALSE;
  456. }
  457. lResult = RegSetValueExW(hKey,
  458. szRegHKL,
  459. 0,
  460. REG_BINARY,
  461. (LPBYTE)&hkl,
  462. sizeof(DWORD));
  463. if (lResult != ERROR_SUCCESS) {
  464. RegCloseKey(hKey);
  465. CliSaveImeHotKey(id, vk, mod, hkl, TRUE);
  466. RIPERR1(lResult, RIP_WARNING,
  467. "CliSaveImeHotKey: setting value on %s failed", szRegHKL);
  468. return FALSE;
  469. }
  470. RegCloseKey(hKey);
  471. return TRUE;
  472. }
  473. BOOL CliImmSetHotKeyWorker(
  474. DWORD dwID,
  475. UINT uModifiers,
  476. UINT uVKey,
  477. HKL hkl,
  478. DWORD dwAction)
  479. {
  480. //
  481. // if we're adding an IME hotkey entry, let's check
  482. // the parameters before calling the kernel side code
  483. //
  484. if (dwAction == ISHK_ADD) {
  485. if (dwID >= IME_HOTKEY_DSWITCH_FIRST &&
  486. dwID <= IME_HOTKEY_DSWITCH_LAST) {
  487. //
  488. // IME direct switching hot key - switch to
  489. // the keyboard layout specified.
  490. // We need to specify keyboard layout.
  491. //
  492. if (hkl == NULL) {
  493. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "hkl should be specified");
  494. return FALSE;
  495. }
  496. } else {
  497. //
  498. // normal hot keys - change the mode of current iME
  499. //
  500. // Because it should be effective in all IME no matter
  501. // which IME is active we should not specify a target IME
  502. //
  503. if (hkl != NULL) {
  504. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "hkl shouldn't be specified");
  505. return FALSE;
  506. }
  507. if (dwID >= IME_KHOTKEY_FIRST && dwID <= IME_KHOTKEY_LAST) {
  508. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Hotkey for Korean IMEs are invalid.");
  509. return FALSE;
  510. }
  511. }
  512. if (uModifiers & MOD_MODIFY_KEYS) {
  513. //
  514. // Because normal keyboard has left and right key for
  515. // these keys, you should specify left or right ( or both )
  516. //
  517. if ((uModifiers & MOD_BOTH_SIDES) == 0) {
  518. RIPERR3(ERROR_INVALID_PARAMETER, RIP_WARNING, "invalid modifiers %x for id %x vKey %x", uModifiers, dwID, uVKey);
  519. return FALSE;
  520. }
  521. }
  522. #if 0 // Skip this check for now
  523. //
  524. // It doesn't make sense if vkey is same as modifiers
  525. //
  526. if ( ((uModifiers & MOD_ALT) && (uVKey == VK_MENU)) ||
  527. ((uModifiers & MOD_CONTROL) && (uVKey == VK_CONTROL)) ||
  528. ((uModifiers & MOD_SHIFT) && (uVKey == VK_SHIFT)) ||
  529. ((uModifiers & MOD_WIN) && ((uVKey == VK_LWIN)||(uVKey == VK_RWIN)))
  530. ) {
  531. RIPERR0( ERROR_INVALID_PARAMETER, RIP_WARNING, "vkey and modifiers are same");
  532. return FALSE;
  533. }
  534. #endif
  535. }
  536. return NtUserSetImeHotKey(dwID, uModifiers, uVKey, hkl, dwAction);
  537. }
  538. //
  539. // NumToHexAscii
  540. //
  541. // convert a DWORD into the hex string
  542. // (e.g. 0x31 -> "00000031")
  543. //
  544. // 29-Jan-1996 takaok ported from Win95.
  545. //
  546. static CONST TCHAR szHexString[] = TEXT("0123456789ABCDEF");
  547. VOID
  548. NumToHexAscii(
  549. DWORD dwNum,
  550. PWSTR szAscii)
  551. {
  552. int i;
  553. for (i = 7; i >= 0; i--) {
  554. szAscii[i] = szHexString[dwNum & 0x0000000f];
  555. dwNum >>= 4;
  556. }
  557. szAscii[8] = TEXT('\0');
  558. return;
  559. }