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