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