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 hControlPanel = NULL, hInputMethod = NULL, hHotKeys = NULL, hKey = NULL; 215 BOOL ret = FALSE, bRevertOnFailure = FALSE; 216 217 if (bDelete) 218 { 219 StringCchPrintfW(szName, _countof(szName), 220 L"Control Panel\\Input Method\\Hot Keys\\%08lX", dwID); 221 error = RegDeleteKeyW(HKEY_CURRENT_USER, szName); 222 return (error == ERROR_SUCCESS); 223 } 224 225 // Open "Control Panel" 226 error = RegCreateKeyExW(HKEY_CURRENT_USER, L"Control Panel", 0, NULL, 0, KEY_ALL_ACCESS, 227 NULL, &hControlPanel, NULL); 228 if (error == ERROR_SUCCESS) 229 { 230 // Open "Input Method" 231 error = RegCreateKeyExW(hControlPanel, L"Input Method", 0, NULL, 0, KEY_ALL_ACCESS, 232 NULL, &hInputMethod, NULL); 233 if (error == ERROR_SUCCESS) 234 { 235 // Open "Hot Keys" 236 error = RegCreateKeyExW(hInputMethod, L"Hot Keys", 0, NULL, 0, KEY_ALL_ACCESS, 237 NULL, &hHotKeys, NULL); 238 if (error == ERROR_SUCCESS) 239 { 240 // Open "Key" 241 StringCchPrintfW(szName, _countof(szName), L"%08lX", dwID); 242 error = RegCreateKeyExW(hHotKeys, szName, 0, NULL, 0, KEY_ALL_ACCESS, 243 NULL, &hKey, NULL); 244 if (error == ERROR_SUCCESS) 245 { 246 bRevertOnFailure = TRUE; 247 248 // Set "Virtual Key" 249 error = RegSetValueExW(hKey, L"Virtual Key", 0, REG_BINARY, 250 (LPBYTE)&uVirtualKey, sizeof(uVirtualKey)); 251 if (error == ERROR_SUCCESS) 252 { 253 // Set "Key Modifiers" 254 error = RegSetValueExW(hKey, L"Key Modifiers", 0, REG_BINARY, 255 (LPBYTE)&uModifiers, sizeof(uModifiers)); 256 if (error == ERROR_SUCCESS) 257 { 258 // Set "Target IME" 259 error = RegSetValueExW(hKey, L"Target IME", 0, REG_BINARY, 260 (LPBYTE)&hKL, sizeof(hKL)); 261 if (error == ERROR_SUCCESS) 262 { 263 // Success! 264 ret = TRUE; 265 bRevertOnFailure = FALSE; 266 } 267 } 268 } 269 RegCloseKey(hKey); 270 } 271 RegCloseKey(hHotKeys); 272 } 273 RegCloseKey(hInputMethod); 274 } 275 RegCloseKey(hControlPanel); 276 } 277 278 if (bRevertOnFailure) 279 CliSaveImeHotKey(dwID, uVirtualKey, uModifiers, hKL, TRUE); 280 281 return ret; 282 } 283 284 /* 285 * @implemented 286 * Same as imm32!ImmSetHotKey. 287 */ 288 BOOL WINAPI CliImmSetHotKey(DWORD dwID, UINT uModifiers, UINT uVirtualKey, HKL hKL) 289 { 290 BOOL ret; 291 292 if (uVirtualKey == 0) // Delete? 293 { 294 ret = CliSaveImeHotKey(dwID, uModifiers, uVirtualKey, hKL, TRUE); 295 if (ret) 296 CliImmSetHotKeyWorker(dwID, uModifiers, uVirtualKey, hKL, SETIMEHOTKEY_DELETE); 297 return ret; 298 } 299 300 // Add 301 ret = CliImmSetHotKeyWorker(dwID, uModifiers, uVirtualKey, hKL, SETIMEHOTKEY_ADD); 302 if (ret) 303 { 304 ret = CliSaveImeHotKey(dwID, uModifiers, uVirtualKey, hKL, FALSE); 305 if (!ret) // Failure? 306 CliImmSetHotKeyWorker(dwID, uModifiers, uVirtualKey, hKL, SETIMEHOTKEY_DELETE); 307 } 308 309 return ret; 310 } 311 312 BOOL FASTCALL CliSetSingleHotKey(LPCWSTR pszSubKey, HANDLE hKey) 313 { 314 LONG error; 315 HKEY hSubKey; 316 DWORD dwHotKeyId = 0; 317 UINT uModifiers = 0, uVirtualKey = 0; 318 HKL hKL = NULL; 319 UNICODE_STRING ustrName; 320 321 error = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_READ, &hSubKey); 322 if (error != ERROR_SUCCESS) 323 return FALSE; 324 325 RtlInitUnicodeString(&ustrName, pszSubKey); 326 RtlUnicodeStringToInteger(&ustrName, 16, &dwHotKeyId); 327 328 uModifiers = CliReadRegistryValue(hSubKey, L"Key Modifiers"); 329 hKL = (HKL)(ULONG_PTR)CliReadRegistryValue(hSubKey, L"Target IME"); 330 uVirtualKey = CliReadRegistryValue(hSubKey, L"Virtual Key"); 331 332 RegCloseKey(hSubKey); 333 334 return CliImmSetHotKeyWorker(dwHotKeyId, uModifiers, uVirtualKey, hKL, SETIMEHOTKEY_ADD); 335 } 336 337 BOOL FASTCALL CliGetImeHotKeysFromRegistry(VOID) 338 { 339 HKEY hKey; 340 LONG error; 341 BOOL ret = FALSE; 342 DWORD dwIndex, cchKeyName; 343 WCHAR szKeyName[16]; 344 345 error = RegOpenKeyExW(HKEY_CURRENT_USER, 346 L"Control Panel\\Input Method\\Hot Keys", 347 0, 348 KEY_READ, 349 &hKey); 350 if (error != ERROR_SUCCESS) 351 return ret; 352 353 for (dwIndex = 0; dwIndex < 1000; ++dwIndex) 354 { 355 cchKeyName = _countof(szKeyName); 356 error = RegEnumKeyExW(hKey, dwIndex, szKeyName, &cchKeyName, NULL, NULL, NULL, NULL); 357 if (error != ERROR_SUCCESS) 358 break; 359 360 szKeyName[_countof(szKeyName) - 1] = 0; /* Avoid stack overrun */ 361 362 if (CliSetSingleHotKey(szKeyName, hKey)) 363 ret = TRUE; 364 } 365 366 RegCloseKey(hKey); 367 return ret; 368 } 369 370 VOID APIENTRY CliGetPreloadKeyboardLayouts(PBYTE pbFlags) 371 { 372 WCHAR szValueName[33], szValue[16]; 373 UNICODE_STRING ustrValue; 374 DWORD dwKL, cbValue, dwType; 375 UINT iNumber; 376 HKEY hKey; 377 LONG error; 378 379 error = RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", 0, KEY_READ, &hKey); 380 if (error != ERROR_SUCCESS) 381 return; 382 383 for (iNumber = 1; iNumber < 1000; ++iNumber) 384 { 385 _ultow(iNumber, szValueName, 10); 386 387 cbValue = sizeof(szValue); 388 error = RegQueryValueExW(hKey, szValueName, NULL, &dwType, (LPBYTE)szValue, &cbValue); 389 if (error != ERROR_SUCCESS) 390 break; 391 392 if (dwType != REG_SZ) 393 continue; 394 395 szValue[_countof(szValue) - 1] = 0; /* Avoid stack overrun */ 396 397 RtlInitUnicodeString(&ustrValue, szValue); 398 RtlUnicodeStringToInteger(&ustrValue, 16, &dwKL); 399 400 IntSetFeKeyboardFlags(LOWORD(dwKL), pbFlags); 401 } 402 403 RegCloseKey(hKey); 404 } 405 406 VOID APIENTRY CliSetDefaultImeHotKeys(PIMEHOTKEYENTRY pEntries, UINT nCount, BOOL bCheck) 407 { 408 UINT uVirtualKey, uModifiers; 409 HKL hKL; 410 411 while (nCount-- > 0) 412 { 413 if (!bCheck || !NtUserGetImeHotKey(pEntries->dwHotKeyId, &uModifiers, &uVirtualKey, &hKL)) 414 { 415 CliImmSetHotKeyWorker(pEntries->dwHotKeyId, 416 pEntries->uModifiers, 417 pEntries->uVirtualKey, 418 pEntries->hKL, 419 SETIMEHOTKEY_ADD); 420 } 421 ++pEntries; 422 } 423 } 424 425 VOID APIENTRY CliImmInitializeHotKeys(DWORD dwAction, HKL hKL) 426 { 427 UINT nCount; 428 LPHKL pList; 429 UINT iIndex; 430 LANGID LangID; 431 BYTE bFlags = 0; 432 BOOL bCheck; 433 434 NtUserSetImeHotKey(0, 0, 0, NULL, SETIMEHOTKEY_INITIALIZE); 435 436 bCheck = CliGetImeHotKeysFromRegistry(); 437 438 if (dwAction == SETIMEHOTKEY_INITIALIZE) 439 { 440 LangID = LANGIDFROMLCID(GetUserDefaultLCID()); 441 IntSetFeKeyboardFlags(LangID, &bFlags); 442 443 CliGetPreloadKeyboardLayouts(&bFlags); 444 } 445 else 446 { 447 nCount = NtUserGetKeyboardLayoutList(0, NULL); 448 if (!nCount) 449 return; 450 451 pList = RtlAllocateHeap(RtlGetProcessHeap(), 0, nCount * sizeof(HKL)); 452 if (!pList) 453 return; 454 455 NtUserGetKeyboardLayoutList(nCount, pList); 456 457 for (iIndex = 0; iIndex < nCount; ++iIndex) 458 { 459 LangID = LOWORD(pList[iIndex]); 460 IntSetFeKeyboardFlags(LangID, &bFlags); 461 } 462 463 RtlFreeHeap(RtlGetProcessHeap(), 0, pList); 464 } 465 466 if (bFlags & FE_JAPANESE) 467 CliSetDefaultImeHotKeys(DefaultHotKeyTableJ, _countof(DefaultHotKeyTableJ), bCheck); 468 469 if (bFlags & FE_CHINESE_TRADITIONAL) 470 CliSetDefaultImeHotKeys(DefaultHotKeyTableT, _countof(DefaultHotKeyTableT), bCheck); 471 472 if (bFlags & FE_CHINESE_SIMPLIFIED) 473 CliSetDefaultImeHotKeys(DefaultHotKeyTableC, _countof(DefaultHotKeyTableC), bCheck); 474 } 475 476 /* 477 * @implemented 478 */ 479 BOOL 480 WINAPI 481 DragDetect( 482 HWND hWnd, 483 POINT pt) 484 { 485 return NtUserDragDetect(hWnd, pt); 486 #if 0 487 MSG msg; 488 RECT rect; 489 POINT tmp; 490 ULONG dx = GetSystemMetrics(SM_CXDRAG); 491 ULONG dy = GetSystemMetrics(SM_CYDRAG); 492 493 rect.left = pt.x - dx; 494 rect.right = pt.x + dx; 495 rect.top = pt.y - dy; 496 rect.bottom = pt.y + dy; 497 498 SetCapture(hWnd); 499 500 for (;;) 501 { 502 while ( 503 PeekMessageW(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) || 504 PeekMessageW(&msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE) 505 ) 506 { 507 if (msg.message == WM_LBUTTONUP) 508 { 509 ReleaseCapture(); 510 return FALSE; 511 } 512 if (msg.message == WM_MOUSEMOVE) 513 { 514 tmp.x = LOWORD(msg.lParam); 515 tmp.y = HIWORD(msg.lParam); 516 if (!PtInRect(&rect, tmp)) 517 { 518 ReleaseCapture(); 519 return TRUE; 520 } 521 } 522 if (msg.message == WM_KEYDOWN) 523 { 524 if (msg.wParam == VK_ESCAPE) 525 { 526 ReleaseCapture(); 527 return TRUE; 528 } 529 } 530 } 531 WaitMessage(); 532 } 533 return 0; 534 #endif 535 } 536 537 /* 538 * @implemented 539 */ 540 BOOL WINAPI 541 EnableWindow(HWND hWnd, BOOL bEnable) 542 { 543 return NtUserxEnableWindow(hWnd, bEnable); 544 } 545 546 /* 547 * @implemented 548 */ 549 SHORT 550 WINAPI 551 DECLSPEC_HOTPATCH 552 GetAsyncKeyState(int vKey) 553 { 554 if (vKey < 0 || vKey > 256) 555 return 0; 556 return (SHORT)NtUserGetAsyncKeyState((DWORD)vKey); 557 } 558 559 560 /* 561 * @implemented 562 */ 563 HKL WINAPI 564 GetKeyboardLayout(DWORD idThread) 565 { 566 return NtUserxGetKeyboardLayout(idThread); 567 } 568 569 570 /* 571 * @implemented 572 */ 573 UINT WINAPI 574 GetKBCodePage(VOID) 575 { 576 return GetOEMCP(); 577 } 578 579 580 /* 581 * @implemented 582 */ 583 int WINAPI 584 GetKeyNameTextA(LONG lParam, 585 LPSTR lpString, 586 int nSize) 587 { 588 LPWSTR pwszBuf; 589 UINT cchBuf = 0; 590 int iRet = 0; 591 BOOL defChar = FALSE; 592 593 pwszBuf = HeapAlloc(GetProcessHeap(), 0, nSize * sizeof(WCHAR)); 594 if (!pwszBuf) 595 return 0; 596 597 cchBuf = NtUserGetKeyNameText(lParam, pwszBuf, nSize); 598 599 iRet = WideCharToMultiByte(CP_ACP, 0, 600 pwszBuf, cchBuf, 601 lpString, nSize, ".", &defChar); // FIXME: do we need defChar? 602 lpString[iRet] = 0; 603 HeapFree(GetProcessHeap(), 0, pwszBuf); 604 605 return iRet; 606 } 607 608 /* 609 * @implemented 610 */ 611 int WINAPI 612 GetKeyNameTextW(LONG lParam, 613 LPWSTR lpString, 614 int nSize) 615 { 616 return NtUserGetKeyNameText(lParam, lpString, nSize); 617 } 618 619 /* 620 * @implemented 621 */ 622 SHORT 623 WINAPI 624 DECLSPEC_HOTPATCH 625 GetKeyState(int nVirtKey) 626 { 627 return (SHORT)NtUserGetKeyState((DWORD)nVirtKey); 628 } 629 630 /* 631 * @implemented 632 */ 633 BOOL WINAPI 634 GetKeyboardLayoutNameA(LPSTR pwszKLID) 635 { 636 WCHAR buf[KL_NAMELENGTH]; 637 638 if (!GetKeyboardLayoutNameW(buf)) 639 return FALSE; 640 641 if (!WideCharToMultiByte(CP_ACP, 0, buf, -1, pwszKLID, KL_NAMELENGTH, NULL, NULL)) 642 return FALSE; 643 644 return TRUE; 645 } 646 647 /* 648 * @implemented 649 */ 650 BOOL WINAPI 651 GetKeyboardLayoutNameW(LPWSTR pwszKLID) 652 { 653 UNICODE_STRING Name; 654 655 RtlInitEmptyUnicodeString(&Name, 656 pwszKLID, 657 KL_NAMELENGTH * sizeof(WCHAR)); 658 659 return NtUserGetKeyboardLayoutName(&Name); 660 } 661 662 /* 663 * @implemented 664 */ 665 int WINAPI 666 GetKeyboardType(int nTypeFlag) 667 { 668 return NtUserxGetKeyboardType(nTypeFlag); 669 } 670 671 /* 672 * @implemented 673 */ 674 BOOL WINAPI 675 GetLastInputInfo(PLASTINPUTINFO plii) 676 { 677 TRACE("%p\n", plii); 678 679 if (plii->cbSize != sizeof (*plii)) 680 { 681 SetLastError(ERROR_INVALID_PARAMETER); 682 return FALSE; 683 } 684 685 plii->dwTime = gpsi->dwLastRITEventTickCount; 686 return TRUE; 687 } 688 689 /* 690 * @implemented 691 */ 692 HKL WINAPI 693 LoadKeyboardLayoutA(LPCSTR pszKLID, 694 UINT Flags) 695 { 696 WCHAR wszKLID[16]; 697 698 if (!MultiByteToWideChar(CP_ACP, 0, pszKLID, -1, 699 wszKLID, sizeof(wszKLID)/sizeof(wszKLID[0]))) 700 { 701 return FALSE; 702 } 703 704 return LoadKeyboardLayoutW(wszKLID, Flags); 705 } 706 707 static inline BOOL IsValidKLID(_In_ LPCWSTR pwszKLID) 708 { 709 return (pwszKLID != NULL) && (wcsspn(pwszKLID, L"0123456789ABCDEFabcdef") == (KL_NAMELENGTH - 1)); 710 } 711 712 VOID GetSystemLibraryPath(LPWSTR pszPath, INT cchPath, LPCWSTR pszFileName) 713 { 714 WCHAR szSysDir[MAX_PATH]; 715 GetSystemDirectoryW(szSysDir, _countof(szSysDir)); 716 StringCchPrintfW(pszPath, cchPath, L"%s\\%s", szSysDir, pszFileName); 717 } 718 719 #define ENGLISH_US MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) 720 721 /* 722 * @unimplemented 723 * 724 * NOTE: We adopt a different design from Microsoft's one due to security reason. 725 * See NtUserLoadKeyboardLayoutEx. 726 */ 727 HKL APIENTRY 728 IntLoadKeyboardLayout( 729 _In_ HKL hklUnload, 730 _In_z_ LPCWSTR pwszKLID, 731 _In_ LANGID wLangID, 732 _In_ UINT Flags, 733 _In_ BOOL unknown5) 734 { 735 DWORD dwKLID, dwHKL, dwType, dwSize; 736 UNICODE_STRING ustrKLID; 737 WCHAR wszRegKey[256] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\"; 738 WCHAR wszLayoutId[10], wszNewKLID[KL_NAMELENGTH], szImeFileName[80]; 739 HKL hNewKL; 740 HKEY hKey; 741 BOOL bIsIME; 742 WORD wLow, wHigh; 743 744 if (!IsValidKLID(pwszKLID)) 745 { 746 ERR("pwszKLID: %s\n", debugstr_w(pwszKLID)); 747 return UlongToHandle(MAKELONG(ENGLISH_US, ENGLISH_US)); 748 } 749 750 dwKLID = wcstoul(pwszKLID, NULL, 16); 751 bIsIME = IS_IME_HKL(UlongToHandle(dwKLID)); 752 753 wLow = LOWORD(dwKLID); 754 wHigh = HIWORD(dwKLID); 755 756 if (Flags & KLF_SUBSTITUTE_OK) 757 { 758 /* Check substitutes key */ 759 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Substitutes", 0, 760 KEY_READ, &hKey) == ERROR_SUCCESS) 761 { 762 dwSize = sizeof(wszNewKLID); 763 if (RegQueryValueExW(hKey, pwszKLID, NULL, &dwType, (LPBYTE)wszNewKLID, 764 &dwSize) == ERROR_SUCCESS && 765 dwType == REG_SZ) 766 { 767 /* Use new KLID value */ 768 pwszKLID = wszNewKLID; 769 dwKLID = wcstoul(pwszKLID, NULL, 16); 770 wHigh = LOWORD(dwKLID); 771 } 772 773 /* Close the key now */ 774 RegCloseKey(hKey); 775 } 776 } 777 778 /* Append KLID at the end of registry key */ 779 StringCbCatW(wszRegKey, sizeof(wszRegKey), pwszKLID); 780 781 /* Open layout registry key for read */ 782 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) 783 { 784 dwSize = sizeof(wszLayoutId); 785 if (RegQueryValueExW(hKey, L"Layout Id", NULL, &dwType, (LPBYTE)wszLayoutId, 786 &dwSize) == ERROR_SUCCESS && dwType == REG_SZ) 787 { 788 /* If Layout Id is specified, use this value | f000 as HIWORD */ 789 wHigh = (0xF000 | wcstoul(wszLayoutId, NULL, 16)); 790 } 791 792 if (bIsIME) 793 { 794 /* Check "IME File" value */ 795 dwSize = sizeof(szImeFileName); 796 if (RegQueryValueExW(hKey, L"IME File", NULL, &dwType, (LPBYTE)szImeFileName, 797 &dwSize) != ERROR_SUCCESS) 798 { 799 bIsIME = FALSE; 800 wHigh = 0; 801 ERR("0x%X\n", dwKLID); 802 } 803 else 804 { 805 WCHAR szPath[MAX_PATH]; 806 szImeFileName[_countof(szImeFileName) - 1] = UNICODE_NULL; 807 GetSystemLibraryPath(szPath, _countof(szPath), szImeFileName); 808 809 /* We don't allow the invalid "IME File" values due to security reason */ 810 if (dwType != REG_SZ || szImeFileName[0] == 0 || 811 wcscspn(szImeFileName, L":\\/") != wcslen(szImeFileName) || 812 GetFileAttributesW(szPath) == INVALID_FILE_ATTRIBUTES) /* Does not exist? */ 813 { 814 bIsIME = FALSE; 815 wHigh = 0; 816 ERR("'%s'\n", debugstr_w(szPath)); 817 } 818 } 819 } 820 821 /* Close the key now */ 822 RegCloseKey(hKey); 823 } 824 else 825 { 826 ERR("Could not find keyboard layout %S.\n", pwszKLID); 827 return NULL; 828 } 829 830 if (wHigh == 0) 831 wHigh = wLow; 832 833 dwHKL = MAKELONG(wLow, wHigh); 834 835 RtlInitUnicodeString(&ustrKLID, pwszKLID); 836 hNewKL = NtUserLoadKeyboardLayoutEx(NULL, 0, NULL, hklUnload, &ustrKLID, dwHKL, Flags); 837 CliImmInitializeHotKeys(SETIMEHOTKEY_ADD, hNewKL); 838 return hNewKL; 839 } 840 841 /* 842 * @implemented 843 */ 844 HKL WINAPI 845 LoadKeyboardLayoutW(LPCWSTR pwszKLID, 846 UINT Flags) 847 { 848 TRACE("(%s, 0x%X)\n", debugstr_w(pwszKLID), Flags); 849 return IntLoadKeyboardLayout(NULL, pwszKLID, 0, Flags, FALSE); 850 } 851 852 /* 853 * @unimplemented 854 */ 855 HKL WINAPI 856 LoadKeyboardLayoutEx(HKL hklUnload, 857 LPCWSTR pwszKLID, 858 UINT Flags) 859 { 860 FIXME("(%p, %s, 0x%X)", hklUnload, debugstr_w(pwszKLID), Flags); 861 if (!hklUnload) 862 return NULL; 863 return IntLoadKeyboardLayout(hklUnload, pwszKLID, 0, Flags, FALSE); 864 } 865 866 /* 867 * @implemented 868 */ 869 BOOL WINAPI UnloadKeyboardLayout(HKL hKL) 870 { 871 if (!NtUserUnloadKeyboardLayout(hKL)) 872 return FALSE; 873 874 CliImmInitializeHotKeys(SETIMEHOTKEY_DELETE, hKL); 875 return TRUE; 876 } 877 878 /* 879 * @implemented 880 */ 881 UINT WINAPI 882 MapVirtualKeyA(UINT uCode, 883 UINT uMapType) 884 { 885 return MapVirtualKeyExA(uCode, uMapType, GetKeyboardLayout(0)); 886 } 887 888 /* 889 * @implemented 890 */ 891 UINT WINAPI 892 MapVirtualKeyExA(UINT uCode, 893 UINT uMapType, 894 HKL dwhkl) 895 { 896 return MapVirtualKeyExW(uCode, uMapType, dwhkl); 897 } 898 899 900 /* 901 * @implemented 902 */ 903 UINT WINAPI 904 MapVirtualKeyExW(UINT uCode, 905 UINT uMapType, 906 HKL dwhkl) 907 { 908 return NtUserMapVirtualKeyEx(uCode, uMapType, 0, dwhkl); 909 } 910 911 912 /* 913 * @implemented 914 */ 915 UINT WINAPI 916 MapVirtualKeyW(UINT uCode, 917 UINT uMapType) 918 { 919 return MapVirtualKeyExW(uCode, uMapType, GetKeyboardLayout(0)); 920 } 921 922 923 /* 924 * @implemented 925 */ 926 DWORD WINAPI 927 OemKeyScan(WORD wOemChar) 928 { 929 WCHAR p; 930 SHORT Vk; 931 UINT Scan; 932 933 MultiByteToWideChar(CP_OEMCP, 0, (PCSTR)&wOemChar, 1, &p, 1); 934 Vk = VkKeyScanW(p); 935 Scan = MapVirtualKeyW((Vk & 0x00ff), 0); 936 if (!Scan) return -1; 937 /* 938 Page 450-1, MS W2k SuperBible by SAMS. Return, low word has the 939 scan code and high word has the shift state. 940 */ 941 return ((Vk & 0xff00) << 8) | Scan; 942 } 943 944 945 /* 946 * @implemented 947 */ 948 BOOL WINAPI 949 SetDoubleClickTime(UINT uInterval) 950 { 951 return (BOOL)NtUserSystemParametersInfo(SPI_SETDOUBLECLICKTIME, 952 uInterval, 953 NULL, 954 0); 955 } 956 957 958 /* 959 * @implemented 960 */ 961 BOOL 962 WINAPI 963 SwapMouseButton( 964 BOOL fSwap) 965 { 966 return NtUserxSwapMouseButton(fSwap); 967 } 968 969 970 /* 971 * @implemented 972 */ 973 int WINAPI 974 ToAscii(UINT uVirtKey, 975 UINT uScanCode, 976 CONST BYTE *lpKeyState, 977 LPWORD lpChar, 978 UINT uFlags) 979 { 980 return ToAsciiEx(uVirtKey, uScanCode, lpKeyState, lpChar, uFlags, 0); 981 } 982 983 984 /* 985 * @implemented 986 */ 987 int WINAPI 988 ToAsciiEx(UINT uVirtKey, 989 UINT uScanCode, 990 CONST BYTE *lpKeyState, 991 LPWORD lpChar, 992 UINT uFlags, 993 HKL dwhkl) 994 { 995 WCHAR UniChars[2]; 996 int Ret, CharCount; 997 998 Ret = ToUnicodeEx(uVirtKey, uScanCode, lpKeyState, UniChars, 2, uFlags, dwhkl); 999 CharCount = (Ret < 0 ? 1 : Ret); 1000 WideCharToMultiByte(CP_ACP, 0, UniChars, CharCount, (LPSTR)lpChar, 2, NULL, NULL); 1001 1002 return Ret; 1003 } 1004 1005 1006 /* 1007 * @implemented 1008 */ 1009 int WINAPI 1010 ToUnicode(UINT wVirtKey, 1011 UINT wScanCode, 1012 CONST BYTE *lpKeyState, 1013 LPWSTR pwszBuff, 1014 int cchBuff, 1015 UINT wFlags) 1016 { 1017 return ToUnicodeEx(wVirtKey, wScanCode, lpKeyState, pwszBuff, cchBuff, 1018 wFlags, 0); 1019 } 1020 1021 1022 /* 1023 * @implemented 1024 */ 1025 int WINAPI 1026 ToUnicodeEx(UINT wVirtKey, 1027 UINT wScanCode, 1028 CONST BYTE *lpKeyState, 1029 LPWSTR pwszBuff, 1030 int cchBuff, 1031 UINT wFlags, 1032 HKL dwhkl) 1033 { 1034 return NtUserToUnicodeEx(wVirtKey, wScanCode, (PBYTE)lpKeyState, pwszBuff, cchBuff, 1035 wFlags, dwhkl); 1036 } 1037 1038 1039 1040 /* 1041 * @implemented 1042 */ 1043 SHORT WINAPI 1044 VkKeyScanA(CHAR ch) 1045 { 1046 WCHAR wChar; 1047 1048 if (IsDBCSLeadByte(ch)) 1049 return -1; 1050 1051 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wChar, 1); 1052 return VkKeyScanW(wChar); 1053 } 1054 1055 1056 /* 1057 * @implemented 1058 */ 1059 SHORT WINAPI 1060 VkKeyScanExA(CHAR ch, 1061 HKL dwhkl) 1062 { 1063 WCHAR wChar; 1064 1065 if (IsDBCSLeadByte(ch)) 1066 return -1; 1067 1068 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wChar, 1); 1069 return VkKeyScanExW(wChar, dwhkl); 1070 } 1071 1072 1073 /* 1074 * @implemented 1075 */ 1076 SHORT WINAPI 1077 VkKeyScanExW(WCHAR ch, 1078 HKL dwhkl) 1079 { 1080 return (SHORT)NtUserVkKeyScanEx(ch, dwhkl, TRUE); 1081 } 1082 1083 1084 /* 1085 * @implemented 1086 */ 1087 SHORT WINAPI 1088 VkKeyScanW(WCHAR ch) 1089 { 1090 return (SHORT)NtUserVkKeyScanEx(ch, 0, FALSE); 1091 } 1092 1093 1094 /* 1095 * @implemented 1096 */ 1097 VOID 1098 WINAPI 1099 keybd_event( 1100 BYTE bVk, 1101 BYTE bScan, 1102 DWORD dwFlags, 1103 ULONG_PTR dwExtraInfo) 1104 { 1105 INPUT Input; 1106 1107 Input.type = INPUT_KEYBOARD; 1108 Input.ki.wVk = bVk; 1109 Input.ki.wScan = bScan; 1110 Input.ki.dwFlags = dwFlags; 1111 Input.ki.time = 0; 1112 Input.ki.dwExtraInfo = dwExtraInfo; 1113 1114 NtUserSendInput(1, &Input, sizeof(INPUT)); 1115 } 1116 1117 1118 /* 1119 * @implemented 1120 */ 1121 VOID 1122 WINAPI 1123 mouse_event( 1124 DWORD dwFlags, 1125 DWORD dx, 1126 DWORD dy, 1127 DWORD dwData, 1128 ULONG_PTR dwExtraInfo) 1129 { 1130 INPUT Input; 1131 1132 Input.type = INPUT_MOUSE; 1133 Input.mi.dx = dx; 1134 Input.mi.dy = dy; 1135 Input.mi.mouseData = dwData; 1136 Input.mi.dwFlags = dwFlags; 1137 Input.mi.time = 0; 1138 Input.mi.dwExtraInfo = dwExtraInfo; 1139 1140 NtUserSendInput(1, &Input, sizeof(INPUT)); 1141 } 1142 1143 /* EOF */ 1144