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 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 for security reason. 725 */ 726 /* Win: LoadKeyboardLayoutWorker */ 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 ustrKbdName; 737 UNICODE_STRING ustrKLID; 738 WCHAR wszRegKey[256] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\"; 739 WCHAR wszLayoutId[10], wszNewKLID[KL_NAMELENGTH], szImeFileName[80]; 740 HKL hNewKL; 741 HKEY hKey; 742 BOOL bIsIME; 743 WORD wLow, wHigh; 744 745 if (!IsValidKLID(pwszKLID)) 746 { 747 ERR("pwszKLID: %s\n", debugstr_w(pwszKLID)); 748 return UlongToHandle(MAKELONG(ENGLISH_US, ENGLISH_US)); 749 } 750 751 dwKLID = wcstoul(pwszKLID, NULL, 16); 752 bIsIME = IS_IME_HKL(UlongToHandle(dwKLID)); 753 754 wLow = LOWORD(dwKLID); 755 wHigh = HIWORD(dwKLID); 756 757 if (Flags & KLF_SUBSTITUTE_OK) 758 { 759 /* Check substitutes key */ 760 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Substitutes", 0, 761 KEY_READ, &hKey) == ERROR_SUCCESS) 762 { 763 dwSize = sizeof(wszNewKLID); 764 if (RegQueryValueExW(hKey, pwszKLID, NULL, &dwType, (LPBYTE)wszNewKLID, 765 &dwSize) == ERROR_SUCCESS && 766 dwType == REG_SZ) 767 { 768 /* Use new KLID value */ 769 pwszKLID = wszNewKLID; 770 dwKLID = wcstoul(pwszKLID, NULL, 16); 771 wHigh = LOWORD(dwKLID); 772 } 773 774 /* Close the key now */ 775 RegCloseKey(hKey); 776 } 777 } 778 779 /* Append KLID at the end of registry key */ 780 StringCbCatW(wszRegKey, sizeof(wszRegKey), pwszKLID); 781 782 /* Open layout registry key for read */ 783 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) 784 { 785 dwSize = sizeof(wszLayoutId); 786 if (RegQueryValueExW(hKey, L"Layout Id", NULL, &dwType, (LPBYTE)wszLayoutId, 787 &dwSize) == ERROR_SUCCESS && dwType == REG_SZ) 788 { 789 /* If Layout Id is specified, use this value | f000 as HIWORD */ 790 wHigh = (0xF000 | wcstoul(wszLayoutId, NULL, 16)); 791 } 792 793 if (bIsIME) 794 { 795 /* Check "IME File" value */ 796 dwSize = sizeof(szImeFileName); 797 if (RegQueryValueExW(hKey, L"IME File", NULL, &dwType, (LPBYTE)szImeFileName, 798 &dwSize) != ERROR_SUCCESS) 799 { 800 bIsIME = FALSE; 801 wHigh = 0; 802 ERR("0x%X\n", dwKLID); 803 } 804 else 805 { 806 WCHAR szPath[MAX_PATH]; 807 szImeFileName[_countof(szImeFileName) - 1] = UNICODE_NULL; 808 GetSystemLibraryPath(szPath, _countof(szPath), szImeFileName); 809 810 /* We don't allow the invalid "IME File" values for security reason */ 811 if (dwType != REG_SZ || szImeFileName[0] == 0 || 812 wcscspn(szImeFileName, L":\\/") != wcslen(szImeFileName) || 813 GetFileAttributesW(szPath) == INVALID_FILE_ATTRIBUTES) /* Does not exist? */ 814 { 815 bIsIME = FALSE; 816 wHigh = 0; 817 ERR("'%s'\n", debugstr_w(szPath)); 818 } 819 } 820 } 821 822 /* Close the key now */ 823 RegCloseKey(hKey); 824 } 825 else 826 { 827 ERR("Could not find keyboard layout %S.\n", pwszKLID); 828 return NULL; 829 } 830 831 if (wHigh == 0) 832 wHigh = wLow; 833 834 dwHKL = MAKELONG(wLow, wHigh); 835 836 ZeroMemory(&ustrKbdName, sizeof(ustrKbdName)); 837 RtlInitUnicodeString(&ustrKLID, pwszKLID); 838 hNewKL = NtUserLoadKeyboardLayoutEx(NULL, 0, &ustrKbdName, NULL, &ustrKLID, dwHKL, Flags); 839 CliImmInitializeHotKeys(SETIMEHOTKEY_ADD, hNewKL); 840 return hNewKL; 841 } 842 843 /* 844 * @implemented 845 */ 846 HKL WINAPI 847 LoadKeyboardLayoutW(LPCWSTR pwszKLID, 848 UINT Flags) 849 { 850 TRACE("(%s, 0x%X)\n", debugstr_w(pwszKLID), Flags); 851 return IntLoadKeyboardLayout(NULL, pwszKLID, 0, Flags, FALSE); 852 } 853 854 /* 855 * @unimplemented 856 */ 857 HKL WINAPI 858 LoadKeyboardLayoutEx(HKL hklUnload, 859 LPCWSTR pwszKLID, 860 UINT Flags) 861 { 862 FIXME("(%p, %s, 0x%X)", hklUnload, debugstr_w(pwszKLID), Flags); 863 if (!hklUnload) 864 return NULL; 865 return IntLoadKeyboardLayout(hklUnload, pwszKLID, 0, Flags, FALSE); 866 } 867 868 /* 869 * @implemented 870 */ 871 BOOL WINAPI UnloadKeyboardLayout(HKL hKL) 872 { 873 if (!NtUserUnloadKeyboardLayout(hKL)) 874 return FALSE; 875 876 CliImmInitializeHotKeys(SETIMEHOTKEY_DELETE, hKL); 877 return TRUE; 878 } 879 880 /* 881 * @implemented 882 */ 883 UINT WINAPI 884 MapVirtualKeyA(UINT uCode, 885 UINT uMapType) 886 { 887 return MapVirtualKeyExA(uCode, uMapType, GetKeyboardLayout(0)); 888 } 889 890 /* 891 * @implemented 892 */ 893 UINT WINAPI 894 MapVirtualKeyExA(UINT uCode, 895 UINT uMapType, 896 HKL dwhkl) 897 { 898 return MapVirtualKeyExW(uCode, uMapType, dwhkl); 899 } 900 901 902 /* 903 * @implemented 904 */ 905 UINT WINAPI 906 MapVirtualKeyExW(UINT uCode, 907 UINT uMapType, 908 HKL dwhkl) 909 { 910 return NtUserMapVirtualKeyEx(uCode, uMapType, 0, dwhkl); 911 } 912 913 914 /* 915 * @implemented 916 */ 917 UINT WINAPI 918 MapVirtualKeyW(UINT uCode, 919 UINT uMapType) 920 { 921 return MapVirtualKeyExW(uCode, uMapType, GetKeyboardLayout(0)); 922 } 923 924 925 /* 926 * @implemented 927 */ 928 DWORD WINAPI 929 OemKeyScan(WORD wOemChar) 930 { 931 WCHAR p; 932 SHORT Vk; 933 UINT Scan; 934 935 MultiByteToWideChar(CP_OEMCP, 0, (PCSTR)&wOemChar, 1, &p, 1); 936 Vk = VkKeyScanW(p); 937 Scan = MapVirtualKeyW((Vk & 0x00ff), 0); 938 if (!Scan) return -1; 939 /* 940 Page 450-1, MS W2k SuperBible by SAMS. Return, low word has the 941 scan code and high word has the shift state. 942 */ 943 return ((Vk & 0xff00) << 8) | Scan; 944 } 945 946 947 /* 948 * @implemented 949 */ 950 BOOL WINAPI 951 SetDoubleClickTime(UINT uInterval) 952 { 953 return (BOOL)NtUserSystemParametersInfo(SPI_SETDOUBLECLICKTIME, 954 uInterval, 955 NULL, 956 0); 957 } 958 959 960 /* 961 * @implemented 962 */ 963 BOOL 964 WINAPI 965 SwapMouseButton( 966 BOOL fSwap) 967 { 968 return NtUserxSwapMouseButton(fSwap); 969 } 970 971 972 /* 973 * @implemented 974 */ 975 int WINAPI 976 ToAscii(UINT uVirtKey, 977 UINT uScanCode, 978 CONST BYTE *lpKeyState, 979 LPWORD lpChar, 980 UINT uFlags) 981 { 982 return ToAsciiEx(uVirtKey, uScanCode, lpKeyState, lpChar, uFlags, 0); 983 } 984 985 986 /* 987 * @implemented 988 */ 989 int WINAPI 990 ToAsciiEx(UINT uVirtKey, 991 UINT uScanCode, 992 CONST BYTE *lpKeyState, 993 LPWORD lpChar, 994 UINT uFlags, 995 HKL dwhkl) 996 { 997 WCHAR UniChars[2]; 998 int Ret, CharCount; 999 1000 Ret = ToUnicodeEx(uVirtKey, uScanCode, lpKeyState, UniChars, 2, uFlags, dwhkl); 1001 CharCount = (Ret < 0 ? 1 : Ret); 1002 WideCharToMultiByte(CP_ACP, 0, UniChars, CharCount, (LPSTR)lpChar, 2, NULL, NULL); 1003 1004 return Ret; 1005 } 1006 1007 1008 /* 1009 * @implemented 1010 */ 1011 int WINAPI 1012 ToUnicode(UINT wVirtKey, 1013 UINT wScanCode, 1014 CONST BYTE *lpKeyState, 1015 LPWSTR pwszBuff, 1016 int cchBuff, 1017 UINT wFlags) 1018 { 1019 return ToUnicodeEx(wVirtKey, wScanCode, lpKeyState, pwszBuff, cchBuff, 1020 wFlags, 0); 1021 } 1022 1023 1024 /* 1025 * @implemented 1026 */ 1027 int WINAPI 1028 ToUnicodeEx(UINT wVirtKey, 1029 UINT wScanCode, 1030 CONST BYTE *lpKeyState, 1031 LPWSTR pwszBuff, 1032 int cchBuff, 1033 UINT wFlags, 1034 HKL dwhkl) 1035 { 1036 return NtUserToUnicodeEx(wVirtKey, wScanCode, (PBYTE)lpKeyState, pwszBuff, cchBuff, 1037 wFlags, dwhkl); 1038 } 1039 1040 1041 1042 /* 1043 * @implemented 1044 */ 1045 SHORT WINAPI 1046 VkKeyScanA(CHAR ch) 1047 { 1048 WCHAR wChar; 1049 1050 if (IsDBCSLeadByte(ch)) 1051 return -1; 1052 1053 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wChar, 1); 1054 return VkKeyScanW(wChar); 1055 } 1056 1057 1058 /* 1059 * @implemented 1060 */ 1061 SHORT WINAPI 1062 VkKeyScanExA(CHAR ch, 1063 HKL dwhkl) 1064 { 1065 WCHAR wChar; 1066 1067 if (IsDBCSLeadByte(ch)) 1068 return -1; 1069 1070 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wChar, 1); 1071 return VkKeyScanExW(wChar, dwhkl); 1072 } 1073 1074 1075 /* 1076 * @implemented 1077 */ 1078 SHORT WINAPI 1079 VkKeyScanExW(WCHAR ch, 1080 HKL dwhkl) 1081 { 1082 return (SHORT)NtUserVkKeyScanEx(ch, dwhkl, TRUE); 1083 } 1084 1085 1086 /* 1087 * @implemented 1088 */ 1089 SHORT WINAPI 1090 VkKeyScanW(WCHAR ch) 1091 { 1092 return (SHORT)NtUserVkKeyScanEx(ch, 0, FALSE); 1093 } 1094 1095 1096 /* 1097 * @implemented 1098 */ 1099 VOID 1100 WINAPI 1101 keybd_event( 1102 BYTE bVk, 1103 BYTE bScan, 1104 DWORD dwFlags, 1105 ULONG_PTR dwExtraInfo) 1106 { 1107 INPUT Input; 1108 1109 Input.type = INPUT_KEYBOARD; 1110 Input.ki.wVk = bVk; 1111 Input.ki.wScan = bScan; 1112 Input.ki.dwFlags = dwFlags; 1113 Input.ki.time = 0; 1114 Input.ki.dwExtraInfo = dwExtraInfo; 1115 1116 NtUserSendInput(1, &Input, sizeof(INPUT)); 1117 } 1118 1119 1120 /* 1121 * @implemented 1122 */ 1123 VOID 1124 WINAPI 1125 mouse_event( 1126 DWORD dwFlags, 1127 DWORD dx, 1128 DWORD dy, 1129 DWORD dwData, 1130 ULONG_PTR dwExtraInfo) 1131 { 1132 INPUT Input; 1133 1134 Input.type = INPUT_MOUSE; 1135 Input.mi.dx = dx; 1136 Input.mi.dy = dy; 1137 Input.mi.mouseData = dwData; 1138 Input.mi.dwFlags = dwFlags; 1139 Input.mi.time = 0; 1140 Input.mi.dwExtraInfo = dwExtraInfo; 1141 1142 NtUserSendInput(1, &Input, sizeof(INPUT)); 1143 } 1144 1145 /* EOF */ 1146