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