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