xref: /reactos/win32ss/user/user32/windows/input.c (revision 76086220)
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     HKL hNewKL;
660 
661     /* LOWORD of dwhkl is Locale Identifier */
662     dwhkl = LOWORD(wcstoul(pwszKLID, NULL, 16));
663 
664     if (Flags & KLF_SUBSTITUTE_OK)
665     {
666         /* Check substitutes key */
667         if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Substitutes", 0,
668                           KEY_READ, &hKey) == ERROR_SUCCESS)
669         {
670             dwSize = sizeof(wszNewKLID);
671             if (RegQueryValueExW(hKey, pwszKLID, NULL, &dwType, (LPBYTE)wszNewKLID, &dwSize) == ERROR_SUCCESS)
672             {
673                 /* Use new KLID value */
674                 pwszKLID = wszNewKLID;
675             }
676 
677             /* Close the key now */
678             RegCloseKey(hKey);
679         }
680     }
681 
682     /* Append KLID at the end of registry key */
683     StringCbCatW(wszRegKey, sizeof(wszRegKey), pwszKLID);
684 
685     /* Open layout registry key for read */
686     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0,
687                       KEY_READ, &hKey) == ERROR_SUCCESS)
688     {
689         dwSize = sizeof(wszLayoutId);
690         if (RegQueryValueExW(hKey, L"Layout Id", NULL, &dwType, (LPBYTE)wszLayoutId, &dwSize) == ERROR_SUCCESS)
691         {
692             /* If Layout Id is specified, use this value | f000 as HIWORD */
693             /* FIXME: Microsoft Office expects this value to be something specific
694              * for Japanese and Korean Windows with an IME the value is 0xe001
695              * We should probably check to see if an IME exists and if so then
696              * set this word properly.
697              */
698             dwhkl |= (0xf000 | wcstol(wszLayoutId, NULL, 16)) << 16;
699         }
700 
701         /* Close the key now */
702         RegCloseKey(hKey);
703     }
704     else
705     {
706         ERR("Could not find keyboard layout %S.\n", pwszKLID);
707         return NULL;
708     }
709 
710     /* If Layout Id is not given HIWORD == LOWORD (for dwhkl) */
711     if (!HIWORD(dwhkl))
712         dwhkl |= dwhkl << 16;
713 
714     ZeroMemory(&ustrKbdName, sizeof(ustrKbdName));
715     RtlInitUnicodeString(&ustrKLID, pwszKLID);
716     hNewKL = NtUserLoadKeyboardLayoutEx(NULL, 0, &ustrKbdName,
717                                         NULL, &ustrKLID,
718                                         dwhkl, Flags);
719     CliImmInitializeHotKeys(SETIMEHOTKEY_ADD, hNewKL);
720     return hNewKL;
721 }
722 
723 /*
724  * @implemented
725  */
726 HKL WINAPI
727 LoadKeyboardLayoutW(LPCWSTR pwszKLID,
728                     UINT Flags)
729 {
730     TRACE("(%s, 0x%X)", debugstr_w(pwszKLID), Flags);
731     return IntLoadKeyboardLayout(NULL, pwszKLID, 0, Flags, FALSE);
732 }
733 
734 /*
735  * @unimplemented
736  */
737 HKL WINAPI
738 LoadKeyboardLayoutEx(HKL hklUnload,
739                      LPCWSTR pwszKLID,
740                      UINT Flags)
741 {
742     FIXME("(%p, %s, 0x%X)", hklUnload, debugstr_w(pwszKLID), Flags);
743     if (!hklUnload)
744         return NULL;
745     return IntLoadKeyboardLayout(hklUnload, pwszKLID, 0, Flags, FALSE);
746 }
747 
748 /*
749  * @implemented
750  */
751 BOOL WINAPI UnloadKeyboardLayout(HKL hKL)
752 {
753     if (!NtUserUnloadKeyboardLayout(hKL))
754         return FALSE;
755 
756     CliImmInitializeHotKeys(SETIMEHOTKEY_DELETE, hKL);
757     return TRUE;
758 }
759 
760 /*
761  * @implemented
762  */
763 UINT WINAPI
764 MapVirtualKeyA(UINT uCode,
765                UINT uMapType)
766 {
767     return MapVirtualKeyExA(uCode, uMapType, GetKeyboardLayout(0));
768 }
769 
770 /*
771  * @implemented
772  */
773 UINT WINAPI
774 MapVirtualKeyExA(UINT uCode,
775                  UINT uMapType,
776                  HKL dwhkl)
777 {
778     return MapVirtualKeyExW(uCode, uMapType, dwhkl);
779 }
780 
781 
782 /*
783  * @implemented
784  */
785 UINT WINAPI
786 MapVirtualKeyExW(UINT uCode,
787                  UINT uMapType,
788                  HKL dwhkl)
789 {
790     return NtUserMapVirtualKeyEx(uCode, uMapType, 0, dwhkl);
791 }
792 
793 
794 /*
795  * @implemented
796  */
797 UINT WINAPI
798 MapVirtualKeyW(UINT uCode,
799                UINT uMapType)
800 {
801     return MapVirtualKeyExW(uCode, uMapType, GetKeyboardLayout(0));
802 }
803 
804 
805 /*
806  * @implemented
807  */
808 DWORD WINAPI
809 OemKeyScan(WORD wOemChar)
810 {
811     WCHAR p;
812     SHORT Vk;
813     UINT Scan;
814 
815     MultiByteToWideChar(CP_OEMCP, 0, (PCSTR)&wOemChar, 1, &p, 1);
816     Vk = VkKeyScanW(p);
817     Scan = MapVirtualKeyW((Vk & 0x00ff), 0);
818     if (!Scan) return -1;
819     /*
820        Page 450-1, MS W2k SuperBible by SAMS. Return, low word has the
821        scan code and high word has the shift state.
822      */
823     return ((Vk & 0xff00) << 8) | Scan;
824 }
825 
826 
827 /*
828  * @implemented
829  */
830 BOOL WINAPI
831 SetDoubleClickTime(UINT uInterval)
832 {
833     return (BOOL)NtUserSystemParametersInfo(SPI_SETDOUBLECLICKTIME,
834                                             uInterval,
835                                             NULL,
836                                             0);
837 }
838 
839 
840 /*
841  * @implemented
842  */
843 BOOL
844 WINAPI
845 SwapMouseButton(
846     BOOL fSwap)
847 {
848     return NtUserxSwapMouseButton(fSwap);
849 }
850 
851 
852 /*
853  * @implemented
854  */
855 int WINAPI
856 ToAscii(UINT uVirtKey,
857         UINT uScanCode,
858         CONST BYTE *lpKeyState,
859         LPWORD lpChar,
860         UINT uFlags)
861 {
862     return ToAsciiEx(uVirtKey, uScanCode, lpKeyState, lpChar, uFlags, 0);
863 }
864 
865 
866 /*
867  * @implemented
868  */
869 int WINAPI
870 ToAsciiEx(UINT uVirtKey,
871           UINT uScanCode,
872           CONST BYTE *lpKeyState,
873           LPWORD lpChar,
874           UINT uFlags,
875           HKL dwhkl)
876 {
877     WCHAR UniChars[2];
878     int Ret, CharCount;
879 
880     Ret = ToUnicodeEx(uVirtKey, uScanCode, lpKeyState, UniChars, 2, uFlags, dwhkl);
881     CharCount = (Ret < 0 ? 1 : Ret);
882     WideCharToMultiByte(CP_ACP, 0, UniChars, CharCount, (LPSTR)lpChar, 2, NULL, NULL);
883 
884     return Ret;
885 }
886 
887 
888 /*
889  * @implemented
890  */
891 int WINAPI
892 ToUnicode(UINT wVirtKey,
893           UINT wScanCode,
894           CONST BYTE *lpKeyState,
895           LPWSTR pwszBuff,
896           int cchBuff,
897           UINT wFlags)
898 {
899     return ToUnicodeEx(wVirtKey, wScanCode, lpKeyState, pwszBuff, cchBuff,
900                        wFlags, 0);
901 }
902 
903 
904 /*
905  * @implemented
906  */
907 int WINAPI
908 ToUnicodeEx(UINT wVirtKey,
909             UINT wScanCode,
910             CONST BYTE *lpKeyState,
911             LPWSTR pwszBuff,
912             int cchBuff,
913             UINT wFlags,
914             HKL dwhkl)
915 {
916     return NtUserToUnicodeEx(wVirtKey, wScanCode, (PBYTE)lpKeyState, pwszBuff, cchBuff,
917                              wFlags, dwhkl);
918 }
919 
920 
921 
922 /*
923  * @implemented
924  */
925 SHORT WINAPI
926 VkKeyScanA(CHAR ch)
927 {
928     WCHAR wChar;
929 
930     if (IsDBCSLeadByte(ch))
931         return -1;
932 
933     MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wChar, 1);
934     return VkKeyScanW(wChar);
935 }
936 
937 
938 /*
939  * @implemented
940  */
941 SHORT WINAPI
942 VkKeyScanExA(CHAR ch,
943              HKL dwhkl)
944 {
945     WCHAR wChar;
946 
947     if (IsDBCSLeadByte(ch))
948         return -1;
949 
950     MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wChar, 1);
951     return VkKeyScanExW(wChar, dwhkl);
952 }
953 
954 
955 /*
956  * @implemented
957  */
958 SHORT WINAPI
959 VkKeyScanExW(WCHAR ch,
960              HKL dwhkl)
961 {
962     return (SHORT)NtUserVkKeyScanEx(ch, dwhkl, TRUE);
963 }
964 
965 
966 /*
967  * @implemented
968  */
969 SHORT WINAPI
970 VkKeyScanW(WCHAR ch)
971 {
972     return (SHORT)NtUserVkKeyScanEx(ch, 0, FALSE);
973 }
974 
975 
976 /*
977  * @implemented
978  */
979 VOID
980 WINAPI
981 keybd_event(
982     BYTE bVk,
983     BYTE bScan,
984     DWORD dwFlags,
985     ULONG_PTR dwExtraInfo)
986 {
987     INPUT Input;
988 
989     Input.type = INPUT_KEYBOARD;
990     Input.ki.wVk = bVk;
991     Input.ki.wScan = bScan;
992     Input.ki.dwFlags = dwFlags;
993     Input.ki.time = 0;
994     Input.ki.dwExtraInfo = dwExtraInfo;
995 
996     NtUserSendInput(1, &Input, sizeof(INPUT));
997 }
998 
999 
1000 /*
1001  * @implemented
1002  */
1003 VOID
1004 WINAPI
1005 mouse_event(
1006     DWORD dwFlags,
1007     DWORD dx,
1008     DWORD dy,
1009     DWORD dwData,
1010     ULONG_PTR dwExtraInfo)
1011 {
1012     INPUT Input;
1013 
1014     Input.type = INPUT_MOUSE;
1015     Input.mi.dx = dx;
1016     Input.mi.dy = dy;
1017     Input.mi.mouseData = dwData;
1018     Input.mi.dwFlags = dwFlags;
1019     Input.mi.time = 0;
1020     Input.mi.dwExtraInfo = dwExtraInfo;
1021 
1022     NtUserSendInput(1, &Input, sizeof(INPUT));
1023 }
1024 
1025 /* EOF */
1026