1 /* 2 * ReactOS kernel 3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 /* 20 * PROJECT: ReactOS user32.dll 21 * FILE: win32ss/user/user32/windows/input.c 22 * PURPOSE: Input 23 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) 24 * UPDATE HISTORY: 25 * 09-05-2001 CSH Created 26 */ 27 28 #include <user32.h> 29 30 #include <strsafe.h> 31 32 WINE_DEFAULT_DEBUG_CHANNEL(user32); 33 34 typedef struct tagIMEHOTKEYENTRY 35 { 36 DWORD dwHotKeyId; 37 UINT uVirtualKey; 38 UINT uModifiers; 39 HKL hKL; 40 } IMEHOTKEYENTRY, *PIMEHOTKEYENTRY; 41 42 // Japanese 43 IMEHOTKEYENTRY DefaultHotKeyTableJ[] = 44 { 45 { IME_JHOTKEY_CLOSE_OPEN, VK_KANJI, MOD_IGNORE_ALL_MODIFIER, NULL }, 46 }; 47 48 // Chinese Traditional 49 IMEHOTKEYENTRY DefaultHotKeyTableT[] = 50 { 51 { IME_THOTKEY_IME_NONIME_TOGGLE, VK_SPACE, MOD_LEFT | MOD_RIGHT | MOD_CONTROL, NULL }, 52 { IME_THOTKEY_SHAPE_TOGGLE, VK_SPACE, MOD_LEFT | MOD_RIGHT | MOD_SHIFT, NULL }, 53 }; 54 55 // Chinese Simplified 56 IMEHOTKEYENTRY DefaultHotKeyTableC[] = 57 { 58 { IME_CHOTKEY_IME_NONIME_TOGGLE, VK_SPACE, MOD_LEFT | MOD_RIGHT | MOD_CONTROL, NULL }, 59 { IME_CHOTKEY_SHAPE_TOGGLE, VK_SPACE, MOD_LEFT | MOD_RIGHT | MOD_SHIFT, NULL }, 60 }; 61 62 // The far-east flags 63 #define FE_JAPANESE (1 << 0) 64 #define FE_CHINESE_TRADITIONAL (1 << 1) 65 #define FE_CHINESE_SIMPLIFIED (1 << 2) 66 #define FE_KOREAN (1 << 3) 67 68 // Sets the far-east flags 69 // Win: SetFeKeyboardFlags 70 VOID FASTCALL IntSetFeKeyboardFlags(LANGID LangID, PBYTE pbFlags) 71 { 72 switch (LangID) 73 { 74 case MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT): 75 *pbFlags |= FE_JAPANESE; 76 break; 77 78 case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL): 79 case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG): 80 *pbFlags |= FE_CHINESE_TRADITIONAL; 81 break; 82 83 case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED): 84 case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE): 85 *pbFlags |= FE_CHINESE_SIMPLIFIED; 86 break; 87 88 case MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN): 89 *pbFlags |= FE_KOREAN; 90 break; 91 92 default: 93 break; 94 } 95 } 96 97 DWORD FASTCALL CliReadRegistryValue(HANDLE hKey, LPCWSTR pszName) 98 { 99 DWORD dwValue, cbValue; 100 LONG error; 101 102 cbValue = sizeof(dwValue); 103 error = RegQueryValueExW(hKey, pszName, NULL, NULL, (LPBYTE)&dwValue, &cbValue); 104 if (error != ERROR_SUCCESS || cbValue < sizeof(DWORD)) 105 return 0; 106 107 return dwValue; 108 } 109 110 BOOL APIENTRY 111 CliImmSetHotKeyWorker(DWORD dwHotKeyId, UINT uModifiers, UINT uVirtualKey, HKL hKL, DWORD dwAction) 112 { 113 if (dwAction == SETIMEHOTKEY_ADD) 114 { 115 if (IME_HOTKEY_DSWITCH_FIRST <= dwHotKeyId && dwHotKeyId <= IME_HOTKEY_DSWITCH_LAST) 116 { 117 if (!hKL) 118 goto Failure; 119 } 120 else 121 { 122 if (hKL) 123 goto Failure; 124 125 if (IME_KHOTKEY_SHAPE_TOGGLE <= dwHotKeyId && 126 dwHotKeyId < IME_THOTKEY_IME_NONIME_TOGGLE) 127 { 128 // The Korean cannot set the IME hotkeys 129 goto Failure; 130 } 131 } 132 133 #define MOD_ALL_MODS (MOD_ALT | MOD_CONTROL | MOD_SHIFT | MOD_WIN) 134 if ((uModifiers & MOD_ALL_MODS) && !(uModifiers & (MOD_LEFT | MOD_RIGHT))) 135 goto Failure; 136 #undef MOD_ALL_MODS 137 } 138 139 return NtUserSetImeHotKey(dwHotKeyId, uModifiers, uVirtualKey, hKL, dwAction); 140 141 Failure: 142 SetLastError(ERROR_INVALID_PARAMETER); 143 return FALSE; 144 } 145 146 147 /* Win: LoadPreloadKeyboardLayouts */ 148 VOID IntLoadPreloadKeyboardLayouts(VOID) 149 { 150 UINT nNumber, uFlags; 151 DWORD cbValue, dwType; 152 WCHAR szNumber[32], szValue[KL_NAMELENGTH]; 153 HKEY hPreloadKey; 154 BOOL bOK = FALSE; 155 HKL hKL, hDefaultKL = NULL; 156 157 if (RegOpenKeyW(HKEY_CURRENT_USER, 158 L"Keyboard Layout\\Preload", 159 &hPreloadKey) != ERROR_SUCCESS) 160 { 161 return; 162 } 163 164 for (nNumber = 1; nNumber <= 1000; ++nNumber) 165 { 166 _ultow(nNumber, szNumber, 10); 167 168 cbValue = sizeof(szValue); 169 if (RegQueryValueExW(hPreloadKey, 170 szNumber, 171 NULL, 172 &dwType, 173 (LPBYTE)szValue, 174 &cbValue) != ERROR_SUCCESS) 175 { 176 break; 177 } 178 179 if (dwType != REG_SZ) 180 continue; 181 182 if (nNumber == 1) /* The first entry is for default keyboard layout */ 183 uFlags = KLF_SUBSTITUTE_OK | KLF_ACTIVATE | KLF_RESET; 184 else 185 uFlags = KLF_SUBSTITUTE_OK | KLF_NOTELLSHELL | KLF_REPLACELANG; 186 187 hKL = LoadKeyboardLayoutW(szValue, uFlags); 188 if (hKL) 189 { 190 bOK = TRUE; 191 if (nNumber == 1) /* The first entry */ 192 hDefaultKL = hKL; 193 } 194 } 195 196 RegCloseKey(hPreloadKey); 197 198 if (hDefaultKL) 199 SystemParametersInfoW(SPI_SETDEFAULTINPUTLANG, 0, &hDefaultKL, 0); 200 201 if (!bOK) 202 { 203 /* Fallback to English (US) */ 204 LoadKeyboardLayoutW(L"00000409", KLF_SUBSTITUTE_OK | KLF_ACTIVATE | KLF_RESET); 205 } 206 } 207 208 209 BOOL APIENTRY 210 CliSaveImeHotKey(DWORD dwID, UINT uModifiers, UINT uVirtualKey, HKL hKL, BOOL bDelete) 211 { 212 WCHAR szName[MAX_PATH]; 213 LONG error; 214 HKEY hKey; 215 BOOL ret = FALSE, bRevertOnFailure = FALSE; 216 217 StringCchPrintfW(szName, _countof(szName), 218 L"Control Panel\\Input Method\\Hot Keys\\%08lX", dwID); 219 220 if (bDelete) 221 { 222 error = RegDeleteKeyW(HKEY_CURRENT_USER, szName); 223 return (error == ERROR_SUCCESS); 224 } 225 226 error = RegCreateKeyExW(HKEY_CURRENT_USER, szName, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL); 227 if (error == ERROR_SUCCESS) 228 { 229 bRevertOnFailure = TRUE; 230 231 // Set "Virtual Key" 232 error = RegSetValueExW(hKey, L"Virtual Key", 0, REG_BINARY, 233 (LPBYTE)&uVirtualKey, sizeof(uVirtualKey)); 234 if (error == ERROR_SUCCESS) 235 { 236 // Set "Key Modifiers" 237 error = RegSetValueExW(hKey, L"Key Modifiers", 0, REG_BINARY, 238 (LPBYTE)&uModifiers, sizeof(uModifiers)); 239 if (error == ERROR_SUCCESS) 240 { 241 // Set "Target IME" 242 error = RegSetValueExW(hKey, L"Target IME", 0, REG_BINARY, 243 (LPBYTE)&hKL, sizeof(hKL)); 244 if (error == ERROR_SUCCESS) 245 { 246 // Success! 247 ret = TRUE; 248 bRevertOnFailure = FALSE; 249 } 250 } 251 } 252 RegCloseKey(hKey); 253 } 254 255 if (bRevertOnFailure) 256 CliSaveImeHotKey(dwID, uVirtualKey, uModifiers, hKL, TRUE); 257 258 return ret; 259 } 260 261 /* 262 * @implemented 263 * Same as imm32!ImmSetHotKey. 264 */ 265 BOOL WINAPI CliImmSetHotKey(DWORD dwID, UINT uModifiers, UINT uVirtualKey, HKL hKL) 266 { 267 BOOL ret; 268 269 if (uVirtualKey == 0) // Delete? 270 { 271 ret = CliSaveImeHotKey(dwID, uModifiers, uVirtualKey, hKL, TRUE); 272 if (ret) 273 CliImmSetHotKeyWorker(dwID, uModifiers, uVirtualKey, hKL, SETIMEHOTKEY_DELETE); 274 return ret; 275 } 276 277 // Add 278 ret = CliImmSetHotKeyWorker(dwID, uModifiers, uVirtualKey, hKL, SETIMEHOTKEY_ADD); 279 if (ret) 280 { 281 ret = CliSaveImeHotKey(dwID, uModifiers, uVirtualKey, hKL, FALSE); 282 if (!ret) // Failure? 283 CliImmSetHotKeyWorker(dwID, uModifiers, uVirtualKey, hKL, SETIMEHOTKEY_DELETE); 284 } 285 286 return ret; 287 } 288 289 BOOL FASTCALL CliSetSingleHotKey(LPCWSTR pszSubKey, HANDLE hKey) 290 { 291 LONG error; 292 HKEY hSubKey; 293 DWORD dwHotKeyId = 0; 294 UINT uModifiers = 0, uVirtualKey = 0; 295 HKL hKL = NULL; 296 UNICODE_STRING ustrName; 297 298 error = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_READ, &hSubKey); 299 if (error != ERROR_SUCCESS) 300 return FALSE; 301 302 RtlInitUnicodeString(&ustrName, pszSubKey); 303 RtlUnicodeStringToInteger(&ustrName, 16, &dwHotKeyId); 304 305 uModifiers = CliReadRegistryValue(hSubKey, L"Key Modifiers"); 306 hKL = (HKL)(ULONG_PTR)CliReadRegistryValue(hSubKey, L"Target IME"); 307 uVirtualKey = CliReadRegistryValue(hSubKey, L"Virtual Key"); 308 309 RegCloseKey(hSubKey); 310 311 return CliImmSetHotKeyWorker(dwHotKeyId, uModifiers, uVirtualKey, hKL, SETIMEHOTKEY_ADD); 312 } 313 314 BOOL FASTCALL CliGetImeHotKeysFromRegistry(VOID) 315 { 316 HKEY hKey; 317 LONG error; 318 BOOL ret = FALSE; 319 DWORD dwIndex, cchKeyName; 320 WCHAR szKeyName[16]; 321 322 error = RegOpenKeyExW(HKEY_CURRENT_USER, 323 L"Control Panel\\Input Method\\Hot Keys", 324 0, 325 KEY_READ, 326 &hKey); 327 if (error != ERROR_SUCCESS) 328 return ret; 329 330 for (dwIndex = 0; dwIndex < 1000; ++dwIndex) 331 { 332 cchKeyName = _countof(szKeyName); 333 error = RegEnumKeyExW(hKey, dwIndex, szKeyName, &cchKeyName, NULL, NULL, NULL, NULL); 334 if (error != ERROR_SUCCESS) 335 break; 336 337 szKeyName[_countof(szKeyName) - 1] = 0; /* Avoid stack overrun */ 338 339 if (CliSetSingleHotKey(szKeyName, hKey)) 340 ret = TRUE; 341 } 342 343 RegCloseKey(hKey); 344 return ret; 345 } 346 347 VOID APIENTRY CliGetPreloadKeyboardLayouts(PBYTE pbFlags) 348 { 349 WCHAR szValueName[33], szValue[16]; 350 UNICODE_STRING ustrValue; 351 DWORD dwKL, cbValue, dwType; 352 UINT iNumber; 353 HKEY hKey; 354 LONG error; 355 356 error = RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", 0, KEY_READ, &hKey); 357 if (error != ERROR_SUCCESS) 358 return; 359 360 for (iNumber = 1; iNumber < 1000; ++iNumber) 361 { 362 _ultow(iNumber, szValueName, 10); 363 364 cbValue = sizeof(szValue); 365 error = RegQueryValueExW(hKey, szValueName, NULL, &dwType, (LPBYTE)szValue, &cbValue); 366 if (error != ERROR_SUCCESS) 367 break; 368 369 if (dwType != REG_SZ) 370 continue; 371 372 szValue[_countof(szValue) - 1] = 0; /* Avoid stack overrun */ 373 374 RtlInitUnicodeString(&ustrValue, szValue); 375 RtlUnicodeStringToInteger(&ustrValue, 16, &dwKL); 376 377 IntSetFeKeyboardFlags(LOWORD(dwKL), pbFlags); 378 } 379 380 RegCloseKey(hKey); 381 } 382 383 VOID APIENTRY CliSetDefaultImeHotKeys(PIMEHOTKEYENTRY pEntries, UINT nCount, BOOL bCheck) 384 { 385 UINT uVirtualKey, uModifiers; 386 HKL hKL; 387 388 while (nCount-- > 0) 389 { 390 if (!bCheck || !NtUserGetImeHotKey(pEntries->dwHotKeyId, &uModifiers, &uVirtualKey, &hKL)) 391 { 392 CliImmSetHotKeyWorker(pEntries->dwHotKeyId, 393 pEntries->uModifiers, 394 pEntries->uVirtualKey, 395 pEntries->hKL, 396 SETIMEHOTKEY_ADD); 397 } 398 ++pEntries; 399 } 400 } 401 402 VOID APIENTRY CliImmInitializeHotKeys(DWORD dwAction, HKL hKL) 403 { 404 UINT nCount; 405 LPHKL pList; 406 UINT iIndex; 407 LANGID LangID; 408 BYTE bFlags = 0; 409 BOOL bCheck; 410 411 NtUserSetImeHotKey(0, 0, 0, NULL, SETIMEHOTKEY_INITIALIZE); 412 413 bCheck = CliGetImeHotKeysFromRegistry(); 414 415 if (dwAction == SETIMEHOTKEY_INITIALIZE) 416 { 417 LangID = LANGIDFROMLCID(GetUserDefaultLCID()); 418 IntSetFeKeyboardFlags(LangID, &bFlags); 419 420 CliGetPreloadKeyboardLayouts(&bFlags); 421 } 422 else 423 { 424 nCount = NtUserGetKeyboardLayoutList(0, NULL); 425 if (!nCount) 426 return; 427 428 pList = RtlAllocateHeap(RtlGetProcessHeap(), 0, nCount * sizeof(HKL)); 429 if (!pList) 430 return; 431 432 NtUserGetKeyboardLayoutList(nCount, pList); 433 434 for (iIndex = 0; iIndex < nCount; ++iIndex) 435 { 436 LangID = LOWORD(pList[iIndex]); 437 IntSetFeKeyboardFlags(LangID, &bFlags); 438 } 439 440 RtlFreeHeap(RtlGetProcessHeap(), 0, pList); 441 } 442 443 if (bFlags & FE_JAPANESE) 444 CliSetDefaultImeHotKeys(DefaultHotKeyTableJ, _countof(DefaultHotKeyTableJ), bCheck); 445 446 if (bFlags & FE_CHINESE_TRADITIONAL) 447 CliSetDefaultImeHotKeys(DefaultHotKeyTableT, _countof(DefaultHotKeyTableT), bCheck); 448 449 if (bFlags & FE_CHINESE_SIMPLIFIED) 450 CliSetDefaultImeHotKeys(DefaultHotKeyTableC, _countof(DefaultHotKeyTableC), bCheck); 451 } 452 453 /* 454 * @implemented 455 */ 456 BOOL 457 WINAPI 458 DragDetect( 459 HWND hWnd, 460 POINT pt) 461 { 462 return NtUserDragDetect(hWnd, pt); 463 #if 0 464 MSG msg; 465 RECT rect; 466 POINT tmp; 467 ULONG dx = GetSystemMetrics(SM_CXDRAG); 468 ULONG dy = GetSystemMetrics(SM_CYDRAG); 469 470 rect.left = pt.x - dx; 471 rect.right = pt.x + dx; 472 rect.top = pt.y - dy; 473 rect.bottom = pt.y + dy; 474 475 SetCapture(hWnd); 476 477 for (;;) 478 { 479 while ( 480 PeekMessageW(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) || 481 PeekMessageW(&msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE) 482 ) 483 { 484 if (msg.message == WM_LBUTTONUP) 485 { 486 ReleaseCapture(); 487 return FALSE; 488 } 489 if (msg.message == WM_MOUSEMOVE) 490 { 491 tmp.x = LOWORD(msg.lParam); 492 tmp.y = HIWORD(msg.lParam); 493 if (!PtInRect(&rect, tmp)) 494 { 495 ReleaseCapture(); 496 return TRUE; 497 } 498 } 499 if (msg.message == WM_KEYDOWN) 500 { 501 if (msg.wParam == VK_ESCAPE) 502 { 503 ReleaseCapture(); 504 return TRUE; 505 } 506 } 507 } 508 WaitMessage(); 509 } 510 return 0; 511 #endif 512 } 513 514 /* 515 * @implemented 516 */ 517 BOOL WINAPI 518 EnableWindow(HWND hWnd, BOOL bEnable) 519 { 520 return NtUserxEnableWindow(hWnd, bEnable); 521 } 522 523 /* 524 * @implemented 525 */ 526 SHORT 527 WINAPI 528 DECLSPEC_HOTPATCH 529 GetAsyncKeyState(int vKey) 530 { 531 if (vKey < 0 || vKey > 256) 532 return 0; 533 return (SHORT)NtUserGetAsyncKeyState((DWORD)vKey); 534 } 535 536 537 /* 538 * @implemented 539 */ 540 HKL WINAPI 541 GetKeyboardLayout(DWORD idThread) 542 { 543 return NtUserxGetKeyboardLayout(idThread); 544 } 545 546 547 /* 548 * @implemented 549 */ 550 UINT WINAPI 551 GetKBCodePage(VOID) 552 { 553 return GetOEMCP(); 554 } 555 556 557 /* 558 * @implemented 559 */ 560 int WINAPI 561 GetKeyNameTextA(LONG lParam, 562 LPSTR lpString, 563 int nSize) 564 { 565 LPWSTR pwszBuf; 566 UINT cchBuf = 0; 567 int iRet = 0; 568 BOOL defChar = FALSE; 569 570 pwszBuf = HeapAlloc(GetProcessHeap(), 0, nSize * sizeof(WCHAR)); 571 if (!pwszBuf) 572 return 0; 573 574 cchBuf = NtUserGetKeyNameText(lParam, pwszBuf, nSize); 575 576 iRet = WideCharToMultiByte(CP_ACP, 0, 577 pwszBuf, cchBuf, 578 lpString, nSize, ".", &defChar); // FIXME: do we need defChar? 579 lpString[iRet] = 0; 580 HeapFree(GetProcessHeap(), 0, pwszBuf); 581 582 return iRet; 583 } 584 585 /* 586 * @implemented 587 */ 588 int WINAPI 589 GetKeyNameTextW(LONG lParam, 590 LPWSTR lpString, 591 int nSize) 592 { 593 return NtUserGetKeyNameText(lParam, lpString, nSize); 594 } 595 596 /* 597 * @implemented 598 */ 599 SHORT 600 WINAPI 601 DECLSPEC_HOTPATCH 602 GetKeyState(int nVirtKey) 603 { 604 return (SHORT)NtUserGetKeyState((DWORD)nVirtKey); 605 } 606 607 /* 608 * @implemented 609 */ 610 BOOL WINAPI 611 GetKeyboardLayoutNameA(LPSTR pwszKLID) 612 { 613 WCHAR buf[KL_NAMELENGTH]; 614 615 if (!GetKeyboardLayoutNameW(buf)) 616 return FALSE; 617 618 if (!WideCharToMultiByte(CP_ACP, 0, buf, -1, pwszKLID, KL_NAMELENGTH, NULL, NULL)) 619 return FALSE; 620 621 return TRUE; 622 } 623 624 /* 625 * @implemented 626 */ 627 BOOL WINAPI 628 GetKeyboardLayoutNameW(LPWSTR pwszKLID) 629 { 630 UNICODE_STRING Name; 631 632 RtlInitEmptyUnicodeString(&Name, 633 pwszKLID, 634 KL_NAMELENGTH * sizeof(WCHAR)); 635 636 return NtUserGetKeyboardLayoutName(&Name); 637 } 638 639 /* 640 * @implemented 641 */ 642 int WINAPI 643 GetKeyboardType(int nTypeFlag) 644 { 645 return NtUserxGetKeyboardType(nTypeFlag); 646 } 647 648 /* 649 * @implemented 650 */ 651 BOOL WINAPI 652 GetLastInputInfo(PLASTINPUTINFO plii) 653 { 654 TRACE("%p\n", plii); 655 656 if (plii->cbSize != sizeof (*plii)) 657 { 658 SetLastError(ERROR_INVALID_PARAMETER); 659 return FALSE; 660 } 661 662 plii->dwTime = gpsi->dwLastRITEventTickCount; 663 return TRUE; 664 } 665 666 /* 667 * @implemented 668 */ 669 HKL WINAPI 670 LoadKeyboardLayoutA(LPCSTR pszKLID, 671 UINT Flags) 672 { 673 WCHAR wszKLID[16]; 674 675 if (!MultiByteToWideChar(CP_ACP, 0, pszKLID, -1, 676 wszKLID, sizeof(wszKLID)/sizeof(wszKLID[0]))) 677 { 678 return FALSE; 679 } 680 681 return LoadKeyboardLayoutW(wszKLID, Flags); 682 } 683 684 static inline BOOL IsValidKLID(_In_ LPCWSTR pwszKLID) 685 { 686 return (pwszKLID != NULL) && (wcsspn(pwszKLID, L"0123456789ABCDEFabcdef") == (KL_NAMELENGTH - 1)); 687 } 688 689 VOID GetSystemLibraryPath(LPWSTR pszPath, INT cchPath, LPCWSTR pszFileName) 690 { 691 WCHAR szSysDir[MAX_PATH]; 692 GetSystemDirectoryW(szSysDir, _countof(szSysDir)); 693 StringCchPrintfW(pszPath, cchPath, L"%s\\%s", szSysDir, pszFileName); 694 } 695 696 #define ENGLISH_US MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) 697 698 /* 699 * @unimplemented 700 * 701 * NOTE: We adopt a different design from Microsoft's one due to security reason. 702 * See NtUserLoadKeyboardLayoutEx. 703 */ 704 HKL APIENTRY 705 IntLoadKeyboardLayout( 706 _In_ HKL hklUnload, 707 _In_z_ LPCWSTR pwszKLID, 708 _In_ LANGID wLangID, 709 _In_ UINT Flags, 710 _In_ BOOL unknown5) 711 { 712 DWORD dwKLID, dwHKL, dwType, dwSize; 713 UNICODE_STRING ustrKLID; 714 WCHAR wszRegKey[256] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\"; 715 WCHAR wszLayoutId[10], wszNewKLID[KL_NAMELENGTH], szImeFileName[80]; 716 HKL hNewKL; 717 HKEY hKey; 718 BOOL bIsIME; 719 WORD wLow, wHigh; 720 721 if (!IsValidKLID(pwszKLID)) 722 { 723 ERR("pwszKLID: %s\n", debugstr_w(pwszKLID)); 724 return UlongToHandle(MAKELONG(ENGLISH_US, ENGLISH_US)); 725 } 726 727 dwKLID = wcstoul(pwszKLID, NULL, 16); 728 bIsIME = IS_IME_HKL(UlongToHandle(dwKLID)); 729 730 wLow = LOWORD(dwKLID); 731 wHigh = HIWORD(dwKLID); 732 733 if (Flags & KLF_SUBSTITUTE_OK) 734 { 735 /* Check substitutes key */ 736 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Substitutes", 0, 737 KEY_READ, &hKey) == ERROR_SUCCESS) 738 { 739 dwSize = sizeof(wszNewKLID); 740 if (RegQueryValueExW(hKey, pwszKLID, NULL, &dwType, (LPBYTE)wszNewKLID, 741 &dwSize) == ERROR_SUCCESS && 742 dwType == REG_SZ) 743 { 744 /* Use new KLID value */ 745 pwszKLID = wszNewKLID; 746 dwKLID = wcstoul(pwszKLID, NULL, 16); 747 wHigh = LOWORD(dwKLID); 748 } 749 750 /* Close the key now */ 751 RegCloseKey(hKey); 752 } 753 } 754 755 /* Append KLID at the end of registry key */ 756 StringCbCatW(wszRegKey, sizeof(wszRegKey), pwszKLID); 757 758 /* Open layout registry key for read */ 759 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) 760 { 761 dwSize = sizeof(wszLayoutId); 762 if (RegQueryValueExW(hKey, L"Layout Id", NULL, &dwType, (LPBYTE)wszLayoutId, 763 &dwSize) == ERROR_SUCCESS && dwType == REG_SZ) 764 { 765 /* If Layout Id is specified, use this value | f000 as HIWORD */ 766 wHigh = (0xF000 | wcstoul(wszLayoutId, NULL, 16)); 767 } 768 769 if (bIsIME) 770 { 771 /* Check "IME File" value */ 772 dwSize = sizeof(szImeFileName); 773 if (RegQueryValueExW(hKey, L"IME File", NULL, &dwType, (LPBYTE)szImeFileName, 774 &dwSize) != ERROR_SUCCESS) 775 { 776 bIsIME = FALSE; 777 wHigh = 0; 778 ERR("0x%X\n", dwKLID); 779 } 780 else 781 { 782 WCHAR szPath[MAX_PATH]; 783 szImeFileName[_countof(szImeFileName) - 1] = UNICODE_NULL; 784 GetSystemLibraryPath(szPath, _countof(szPath), szImeFileName); 785 786 /* We don't allow the invalid "IME File" values due to security reason */ 787 if (dwType != REG_SZ || szImeFileName[0] == 0 || 788 wcscspn(szImeFileName, L":\\/") != wcslen(szImeFileName) || 789 GetFileAttributesW(szPath) == INVALID_FILE_ATTRIBUTES) /* Does not exist? */ 790 { 791 bIsIME = FALSE; 792 wHigh = 0; 793 ERR("'%s'\n", debugstr_w(szPath)); 794 } 795 } 796 } 797 798 /* Close the key now */ 799 RegCloseKey(hKey); 800 } 801 else 802 { 803 ERR("Could not find keyboard layout %S.\n", pwszKLID); 804 return NULL; 805 } 806 807 if (wHigh == 0) 808 wHigh = wLow; 809 810 dwHKL = MAKELONG(wLow, wHigh); 811 812 RtlInitUnicodeString(&ustrKLID, pwszKLID); 813 hNewKL = NtUserLoadKeyboardLayoutEx(NULL, 0, NULL, hklUnload, &ustrKLID, dwHKL, Flags); 814 CliImmInitializeHotKeys(SETIMEHOTKEY_ADD, hNewKL); 815 return hNewKL; 816 } 817 818 /* 819 * @implemented 820 */ 821 HKL WINAPI 822 LoadKeyboardLayoutW(LPCWSTR pwszKLID, 823 UINT Flags) 824 { 825 TRACE("(%s, 0x%X)\n", debugstr_w(pwszKLID), Flags); 826 return IntLoadKeyboardLayout(NULL, pwszKLID, 0, Flags, FALSE); 827 } 828 829 /* 830 * @unimplemented 831 */ 832 HKL WINAPI 833 LoadKeyboardLayoutEx(HKL hklUnload, 834 LPCWSTR pwszKLID, 835 UINT Flags) 836 { 837 FIXME("(%p, %s, 0x%X)", hklUnload, debugstr_w(pwszKLID), Flags); 838 if (!hklUnload) 839 return NULL; 840 return IntLoadKeyboardLayout(hklUnload, pwszKLID, 0, Flags, FALSE); 841 } 842 843 /* 844 * @implemented 845 */ 846 BOOL WINAPI UnloadKeyboardLayout(HKL hKL) 847 { 848 if (!NtUserUnloadKeyboardLayout(hKL)) 849 return FALSE; 850 851 CliImmInitializeHotKeys(SETIMEHOTKEY_DELETE, hKL); 852 return TRUE; 853 } 854 855 /* 856 * @implemented 857 */ 858 UINT WINAPI 859 MapVirtualKeyA(UINT uCode, 860 UINT uMapType) 861 { 862 return MapVirtualKeyExA(uCode, uMapType, GetKeyboardLayout(0)); 863 } 864 865 /* 866 * @implemented 867 */ 868 UINT WINAPI 869 MapVirtualKeyExA(UINT uCode, 870 UINT uMapType, 871 HKL dwhkl) 872 { 873 return MapVirtualKeyExW(uCode, uMapType, dwhkl); 874 } 875 876 877 /* 878 * @implemented 879 */ 880 UINT WINAPI 881 MapVirtualKeyExW(UINT uCode, 882 UINT uMapType, 883 HKL dwhkl) 884 { 885 return NtUserMapVirtualKeyEx(uCode, uMapType, 0, dwhkl); 886 } 887 888 889 /* 890 * @implemented 891 */ 892 UINT WINAPI 893 MapVirtualKeyW(UINT uCode, 894 UINT uMapType) 895 { 896 return MapVirtualKeyExW(uCode, uMapType, GetKeyboardLayout(0)); 897 } 898 899 900 /* 901 * @implemented 902 */ 903 DWORD WINAPI 904 OemKeyScan(WORD wOemChar) 905 { 906 WCHAR p; 907 SHORT Vk; 908 UINT Scan; 909 910 MultiByteToWideChar(CP_OEMCP, 0, (PCSTR)&wOemChar, 1, &p, 1); 911 Vk = VkKeyScanW(p); 912 Scan = MapVirtualKeyW((Vk & 0x00ff), 0); 913 if (!Scan) return -1; 914 /* 915 Page 450-1, MS W2k SuperBible by SAMS. Return, low word has the 916 scan code and high word has the shift state. 917 */ 918 return ((Vk & 0xff00) << 8) | Scan; 919 } 920 921 922 /* 923 * @implemented 924 */ 925 BOOL WINAPI 926 SetDoubleClickTime(UINT uInterval) 927 { 928 return (BOOL)NtUserSystemParametersInfo(SPI_SETDOUBLECLICKTIME, 929 uInterval, 930 NULL, 931 0); 932 } 933 934 935 /* 936 * @implemented 937 */ 938 BOOL 939 WINAPI 940 SwapMouseButton( 941 BOOL fSwap) 942 { 943 return NtUserxSwapMouseButton(fSwap); 944 } 945 946 947 /* 948 * @implemented 949 */ 950 int WINAPI 951 ToAscii(UINT uVirtKey, 952 UINT uScanCode, 953 CONST BYTE *lpKeyState, 954 LPWORD lpChar, 955 UINT uFlags) 956 { 957 return ToAsciiEx(uVirtKey, uScanCode, lpKeyState, lpChar, uFlags, 0); 958 } 959 960 961 /* 962 * @implemented 963 */ 964 int WINAPI 965 ToAsciiEx(UINT uVirtKey, 966 UINT uScanCode, 967 CONST BYTE *lpKeyState, 968 LPWORD lpChar, 969 UINT uFlags, 970 HKL dwhkl) 971 { 972 WCHAR UniChars[2]; 973 int Ret, CharCount; 974 975 Ret = ToUnicodeEx(uVirtKey, uScanCode, lpKeyState, UniChars, 2, uFlags, dwhkl); 976 CharCount = (Ret < 0 ? 1 : Ret); 977 WideCharToMultiByte(CP_ACP, 0, UniChars, CharCount, (LPSTR)lpChar, 2, NULL, NULL); 978 979 return Ret; 980 } 981 982 983 /* 984 * @implemented 985 */ 986 int WINAPI 987 ToUnicode(UINT wVirtKey, 988 UINT wScanCode, 989 CONST BYTE *lpKeyState, 990 LPWSTR pwszBuff, 991 int cchBuff, 992 UINT wFlags) 993 { 994 return ToUnicodeEx(wVirtKey, wScanCode, lpKeyState, pwszBuff, cchBuff, 995 wFlags, 0); 996 } 997 998 999 /* 1000 * @implemented 1001 */ 1002 int WINAPI 1003 ToUnicodeEx(UINT wVirtKey, 1004 UINT wScanCode, 1005 CONST BYTE *lpKeyState, 1006 LPWSTR pwszBuff, 1007 int cchBuff, 1008 UINT wFlags, 1009 HKL dwhkl) 1010 { 1011 return NtUserToUnicodeEx(wVirtKey, wScanCode, (PBYTE)lpKeyState, pwszBuff, cchBuff, 1012 wFlags, dwhkl); 1013 } 1014 1015 1016 1017 /* 1018 * @implemented 1019 */ 1020 SHORT WINAPI 1021 VkKeyScanA(CHAR ch) 1022 { 1023 WCHAR wChar; 1024 1025 if (IsDBCSLeadByte(ch)) 1026 return -1; 1027 1028 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wChar, 1); 1029 return VkKeyScanW(wChar); 1030 } 1031 1032 1033 /* 1034 * @implemented 1035 */ 1036 SHORT WINAPI 1037 VkKeyScanExA(CHAR ch, 1038 HKL dwhkl) 1039 { 1040 WCHAR wChar; 1041 1042 if (IsDBCSLeadByte(ch)) 1043 return -1; 1044 1045 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wChar, 1); 1046 return VkKeyScanExW(wChar, dwhkl); 1047 } 1048 1049 1050 /* 1051 * @implemented 1052 */ 1053 SHORT WINAPI 1054 VkKeyScanExW(WCHAR ch, 1055 HKL dwhkl) 1056 { 1057 return (SHORT)NtUserVkKeyScanEx(ch, dwhkl, TRUE); 1058 } 1059 1060 1061 /* 1062 * @implemented 1063 */ 1064 SHORT WINAPI 1065 VkKeyScanW(WCHAR ch) 1066 { 1067 return (SHORT)NtUserVkKeyScanEx(ch, 0, FALSE); 1068 } 1069 1070 1071 /* 1072 * @implemented 1073 */ 1074 VOID 1075 WINAPI 1076 keybd_event( 1077 BYTE bVk, 1078 BYTE bScan, 1079 DWORD dwFlags, 1080 ULONG_PTR dwExtraInfo) 1081 { 1082 INPUT Input; 1083 1084 Input.type = INPUT_KEYBOARD; 1085 Input.ki.wVk = bVk; 1086 Input.ki.wScan = bScan; 1087 Input.ki.dwFlags = dwFlags; 1088 Input.ki.time = 0; 1089 Input.ki.dwExtraInfo = dwExtraInfo; 1090 1091 NtUserSendInput(1, &Input, sizeof(INPUT)); 1092 } 1093 1094 1095 /* 1096 * @implemented 1097 */ 1098 VOID 1099 WINAPI 1100 mouse_event( 1101 DWORD dwFlags, 1102 DWORD dx, 1103 DWORD dy, 1104 DWORD dwData, 1105 ULONG_PTR dwExtraInfo) 1106 { 1107 INPUT Input; 1108 1109 Input.type = INPUT_MOUSE; 1110 Input.mi.dx = dx; 1111 Input.mi.dy = dy; 1112 Input.mi.mouseData = dwData; 1113 Input.mi.dwFlags = dwFlags; 1114 Input.mi.time = 0; 1115 Input.mi.dwExtraInfo = dwExtraInfo; 1116 1117 NtUserSendInput(1, &Input, sizeof(INPUT)); 1118 } 1119 1120 /* EOF */ 1121