ReactOS 0.4.16-dev-2332-g4cba65d
keyboard.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Keyboard functions
5 * FILE: win32ss/user/ntuser/keyboard.c
6 * PROGRAMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Rafal Harabien (rafalh@reactos.org)
8 */
9
10#include <win32k.h>
12
13BYTE gafAsyncKeyState[256 * 2 / 8]; // 2 bits per key
14static BYTE gafAsyncKeyStateRecentDown[256 / 8]; // 1 bit per key
22
23/* State for Alt+Numpad character entry */
24static enum _ALTNUM_STATE
25{
30
32
33/* FUNCTIONS *****************************************************************/
34
35/*
36 * InitKeyboardImpl
37 *
38 * Initialization -- Right now, just zero the key state
39 */
40CODE_SEG("INIT")
44{
47 // Clear and set default information.
49 gKeyboardInfo.KeyboardIdentifier.Type = 4; /* AT-101 */
50 gKeyboardInfo.NumberOfFunctionKeys = 12; /* We're doing an 101 for now, so return 12 F-keys */
51 return STATUS_SUCCESS;
52}
53
54/*
55 * IntKeyboardGetIndicatorTrans
56 *
57 * Asks the keyboard driver to send a small table that shows which
58 * lights should connect with which scancodes
59 */
60//static
63 PKEYBOARD_INDICATOR_TRANSLATION *ppIndicatorTrans)
64{
66 DWORD dwSize = 0;
67 IO_STATUS_BLOCK Block;
69
71
73 dwSize,
75
76 while (pRet)
77 {
78 Status = ZwDeviceIoControlFile(hKeyboardDevice,
79 NULL,
80 NULL,
81 NULL,
82 &Block,
84 NULL, 0,
85 pRet, dwSize);
86
88 break;
89
91
93
95 dwSize,
97 }
98
99 if (!pRet)
101
102 if (!NT_SUCCESS(Status))
103 {
105 return Status;
106 }
107
108 *ppIndicatorTrans = pRet;
109 return Status;
110}
111
112/*
113 * IntKeyboardUpdateLeds
114 *
115 * Sends the keyboard commands to turn on/off the lights
116 */
117static
120 WORD wVk,
121 WORD wScanCode)
122{
124 UINT i;
125 USHORT LedFlag = 0;
126 IO_STATUS_BLOCK Block;
127
130
131 switch (wVk)
132 {
133 case VK_CAPITAL: LedFlag = KEYBOARD_CAPS_LOCK_ON; break;
134 case VK_NUMLOCK: LedFlag = KEYBOARD_NUM_LOCK_ON; break;
135 case VK_SCROLL: LedFlag = KEYBOARD_SCROLL_LOCK_ON; break;
136 default:
138 {
140 {
142 break;
143 }
144 }
145 }
146
147 if (LedFlag)
148 {
149 gIndicators.LedFlags ^= LedFlag;
150
151 /* Update the lights on the hardware */
152 Status = ZwDeviceIoControlFile(hKeyboardDevice,
153 NULL,
154 NULL,
155 NULL,
156 &Block,
158 &gIndicators, sizeof(gIndicators),
159 NULL, 0);
160
161 return Status;
162 }
163
164 return STATUS_SUCCESS;
165}
166
167/*
168 * UserInitKeyboard
169 *
170 * Initializes keyboard indicators translation and their state
171 */
173UserInitKeyboard(HANDLE hKeyboardDevice)
174{
176 IO_STATUS_BLOCK Block;
177
179
180 Status = ZwDeviceIoControlFile(hKeyboardDevice,
181 NULL,
182 NULL,
183 NULL,
184 &Block,
186 NULL, 0,
188 sizeof(gIndicators));
189
190 if (!NT_SUCCESS(Status))
191 {
192 WARN("NtDeviceIoControlFile() failed, ignored\n");
195 }
196
203
204 // FIXME: Need device driver to work! HID support more than one!!!!
205 Status = ZwDeviceIoControlFile(hKeyboardDevice,
206 NULL,
207 NULL,
208 NULL,
209 &Block,
211 NULL, 0,
212 &gKeyboardInfo, sizeof(gKeyboardInfo));
213
214 if (!NT_SUCCESS(Status))
215 {
216 ERR("NtDeviceIoControlFile() failed, ignored\n");
217 }
218 TRACE("Keyboard type %u, subtype %u and number of func keys %u\n",
222}
223
224/*
225 * IntSimplifyVk
226 *
227 * Changes virtual keys which distinguish between left and right hand, to keys which don't distinguish
228 */
229static
230WORD
232{
233 switch (wVk)
234 {
235 case VK_LSHIFT:
236 case VK_RSHIFT:
237 return VK_SHIFT;
238
239 case VK_LCONTROL:
240 case VK_RCONTROL:
241 return VK_CONTROL;
242
243 case VK_LMENU:
244 case VK_RMENU:
245 return VK_MENU;
246
247 default:
248 return wVk;
249 }
250}
251
252/*
253 * IntFixVk
254 *
255 * Changes virtual keys which don't not distinguish between left and right hand to proper keys
256 */
257static
258WORD
260{
261 switch (wVk)
262 {
263 case VK_SHIFT:
264 return bExt ? VK_RSHIFT : VK_LSHIFT;
265
266 case VK_CONTROL:
267 return bExt ? VK_RCONTROL : VK_LCONTROL;
268
269 case VK_MENU:
270 return bExt ? VK_RMENU : VK_LMENU;
271
272 default:
273 return wVk;
274 }
275}
276
277/*
278 * IntTranslateNumpadKey
279 *
280 * Translates numpad keys when numlock is enabled
281 */
282static
283WORD
285{
286 switch (wVk)
287 {
288 case VK_INSERT: return VK_NUMPAD0;
289 case VK_END: return VK_NUMPAD1;
290 case VK_DOWN: return VK_NUMPAD2;
291 case VK_NEXT: return VK_NUMPAD3;
292 case VK_LEFT: return VK_NUMPAD4;
293 case VK_CLEAR: return VK_NUMPAD5;
294 case VK_RIGHT: return VK_NUMPAD6;
295 case VK_HOME: return VK_NUMPAD7;
296 case VK_UP: return VK_NUMPAD8;
297 case VK_PRIOR: return VK_NUMPAD9;
298 case VK_DELETE: return VK_DECIMAL;
299 default: return wVk;
300 }
301}
302
303/*
304 * IntGetModBits
305 *
306 * Gets layout specific modification bits, for example KBDSHIFT, KBDCTRL, KBDALT
307 */
308static
309DWORD
310IntGetModBits(PKBDTABLES pKbdTbl, PBYTE pKeyState)
311{
312 DWORD i, dwModBits = 0;
313
314 /* DumpKeyState( KeyState ); */
315
316 for (i = 0; pKbdTbl->pCharModifiers->pVkToBit[i].Vk; i++)
317 if (IS_KEY_DOWN(pKeyState, pKbdTbl->pCharModifiers->pVkToBit[i].Vk))
318 dwModBits |= pKbdTbl->pCharModifiers->pVkToBit[i].ModBits;
319
320 TRACE("Current Mod Bits: %lx\n", dwModBits);
321
322 return dwModBits;
323}
324
325/*
326 * IntTranslateChar
327 *
328 * Translates virtual key to character
329 */
330static
331BOOL
333 PBYTE pKeyState,
334 PBOOL pbDead,
335 PBOOL pbLigature,
336 PWCHAR pwcTranslatedChar,
337 PKBDTABLES pKbdTbl)
338{
339 PVK_TO_WCHAR_TABLE pVkToVchTbl;
340 PVK_TO_WCHARS10 pVkToVch;
341 DWORD i, dwModBits, dwVkModBits, dwModNumber = 0;
342 WCHAR wch;
343 BOOL bAltGr;
344 WORD wCaplokAttr;
345
346 dwModBits = pKeyState ? IntGetModBits(pKbdTbl, pKeyState) : 0;
347 bAltGr = pKeyState && (pKbdTbl->fLocaleFlags & KLLF_ALTGR) && IS_KEY_DOWN(pKeyState, VK_RMENU);
348 wCaplokAttr = bAltGr ? CAPLOKALTGR : CAPLOK;
349
350 TRACE("TryToTranslate: %04x %x\n", wVirtKey, dwModBits);
351
352 /* If ALT without CTRL has ben used, remove ALT flag */
353 if ((dwModBits & (KBDALT|KBDCTRL)) == KBDALT)
354 dwModBits &= ~KBDALT;
355
356 if (dwModBits > pKbdTbl->pCharModifiers->wMaxModBits)
357 {
358 TRACE("dwModBits %x > wMaxModBits %x\n", dwModBits, pKbdTbl->pCharModifiers->wMaxModBits);
359 return FALSE;
360 }
361
362 for (i = 0; pKbdTbl->pVkToWcharTable[i].pVkToWchars; i++)
363 {
364 pVkToVchTbl = &pKbdTbl->pVkToWcharTable[i];
365 pVkToVch = (PVK_TO_WCHARS10)(pVkToVchTbl->pVkToWchars);
366 while (pVkToVch->VirtualKey)
367 {
368 if (wVirtKey == (pVkToVch->VirtualKey & 0xFF))
369 {
370 dwVkModBits = dwModBits;
371
372 /* If CapsLock is enabled for this key and locked, add SHIFT bit */
373 if ((pVkToVch->Attributes & wCaplokAttr) &&
374 pKeyState &&
375 IS_KEY_LOCKED(pKeyState, VK_CAPITAL))
376 {
377 /* Note: we use special value here instead of getting VK_SHIFT mod bit - it's verified */
378 dwVkModBits ^= KBDSHIFT;
379 }
380
381 if (dwVkModBits > pKbdTbl->pCharModifiers->wMaxModBits)
382 break;
383
384 /* Get modification number */
385 dwModNumber = pKbdTbl->pCharModifiers->ModNumber[dwVkModBits];
386 if (dwModNumber >= pVkToVchTbl->nModifications)
387 {
388 TRACE("dwModNumber %u >= nModifications %u\n", dwModNumber, pVkToVchTbl->nModifications);
389 break;
390 }
391
392 /* Read character */
393 wch = pVkToVch->wch[dwModNumber];
394 if (wch == WCH_NONE)
395 break;
396
397 *pbDead = (wch == WCH_DEAD);
398 *pbLigature = (wch == WCH_LGTR);
399 *pwcTranslatedChar = wch;
400
401 TRACE("%lu %04x: dwModNumber %08x Char %04x\n",
402 i, wVirtKey, dwModNumber, wch);
403
404 if (*pbDead)
405 {
406 /* After WCH_DEAD, real character is located */
407 pVkToVch = (PVK_TO_WCHARS10)(((BYTE *)pVkToVch) + pVkToVchTbl->cbSize);
408 if (pVkToVch->VirtualKey != 0xFF)
409 {
410 WARN("Found dead key with no trailer in the table.\n");
411 WARN("VK: %04x, ADDR: %p\n", wVirtKey, pVkToVch);
412 break;
413 }
414 *pwcTranslatedChar = pVkToVch->wch[dwModNumber];
415 }
416 return TRUE;
417 }
418 pVkToVch = (PVK_TO_WCHARS10)(((BYTE *)pVkToVch) + pVkToVchTbl->cbSize);
419 }
420 }
421
422 /* If nothing has been found in layout, check if this is ASCII control character.
423 Note: we could add it to layout table, but windows does not have it there */
424 if (wVirtKey >= 'A' && wVirtKey <= 'Z' &&
425 pKeyState && IS_KEY_DOWN(pKeyState, VK_CONTROL) &&
426 !IS_KEY_DOWN(pKeyState, VK_MENU))
427 {
428 *pwcTranslatedChar = (wVirtKey - 'A') + 1; /* ASCII control character */
429 *pbDead = FALSE;
430 *pbLigature = FALSE;
431 return TRUE;
432 }
433
434 return FALSE;
435}
436
437/*
438 * IntToUnicodeEx
439 *
440 * Translates virtual key to characters
441 */
442static
443int APIENTRY
445 UINT wScanCode,
446 PBYTE pKeyState,
447 LPWSTR pwszBuff,
448 int cchBuff,
449 UINT wFlags,
450 PKBDTABLES pKbdTbl)
451{
452 WCHAR wchTranslatedChar;
453 BOOL bDead, bLigature;
454 static WCHAR wchDead = 0;
455 int iRet = 0;
456
457 ASSERT(pKbdTbl);
458
459 if (!IntTranslateChar(wVirtKey,
460 pKeyState,
461 &bDead,
462 &bLigature,
463 &wchTranslatedChar,
464 pKbdTbl))
465 {
466 return 0;
467 }
468
469 if (bLigature)
470 {
471 WARN("Not handling ligature (yet)\n" );
472 return 0;
473 }
474
475 /* If we got dead char in previous call check dead keys in keyboard layout */
476 if (wchDead)
477 {
478 UINT i;
479 WCHAR wchFirst, wchSecond;
480 TRACE("Previous dead char: %lc (%x)\n", wchDead, wchDead);
481
482 if (pKbdTbl->pDeadKey)
483 {
484 for (i = 0; pKbdTbl->pDeadKey[i].dwBoth; i++)
485 {
486 wchFirst = pKbdTbl->pDeadKey[i].dwBoth >> 16;
487 wchSecond = pKbdTbl->pDeadKey[i].dwBoth & 0xFFFF;
488 if (wchFirst == wchDead && wchSecond == wchTranslatedChar)
489 {
490 wchTranslatedChar = pKbdTbl->pDeadKey[i].wchComposed;
491 wchDead = 0;
492 bDead = FALSE;
493 break;
494 }
495 }
496 }
497 else
498 {
499#if defined(__GNUC__)
500 if (wchDead == 0x8000)
501 {
502 ERR("GCC is inventing bits, ignoring fake dead key\n");
503 wchDead = 0;
504 }
505#endif
506 }
507
508 TRACE("Final char: %lc (%x)\n", wchTranslatedChar, wchTranslatedChar);
509 }
510
511 /* Dead char has not been not found */
512 if (wchDead)
513 {
514 /* Treat both characters normally */
515 if (cchBuff > iRet)
516 pwszBuff[iRet++] = wchDead;
517 bDead = FALSE;
518 }
519
520 /* Add character to the buffer */
521 if (cchBuff > iRet)
522 pwszBuff[iRet++] = wchTranslatedChar;
523
524 /* Save dead character */
525 wchDead = bDead ? wchTranslatedChar : 0;
526
527 return bDead ? -iRet : iRet;
528}
529
530/*
531 * IntVkToVsc
532 *
533 * Translates virtual key to scan code
534 */
535static
538{
539 unsigned i;
540
541 ASSERT(pKbdTbl);
542
543 /* Check standard keys first */
544 for (i = 0; i < pKbdTbl->bMaxVSCtoVK; i++)
545 {
546 if ((pKbdTbl->pusVSCtoVK[i] & 0xFF) == wVk)
547 return i;
548 }
549
550 /* Check extended keys now */
551 for (i = 0; pKbdTbl->pVSCtoVK_E0[i].Vsc; i++)
552 {
553 if ((pKbdTbl->pVSCtoVK_E0[i].Vk & 0xFF) == wVk)
554 return 0xE000 | pKbdTbl->pVSCtoVK_E0[i].Vsc;
555 }
556
557 for (i = 0; pKbdTbl->pVSCtoVK_E1[i].Vsc; i++)
558 {
559 if ((pKbdTbl->pVSCtoVK_E1[i].Vk & 0xFF) == wVk)
560 return 0xE100 | pKbdTbl->pVSCtoVK_E1[i].Vsc;
561 }
562
563 /* Virtual key has not been found */
564 return 0;
565}
566
567/*
568 * IntVscToVk
569 *
570 * Translates prefixed scancode to virtual key
571 */
572static
574IntVscToVk(WORD wScanCode, PKBDTABLES pKbdTbl)
575{
576 unsigned i;
577 WORD wVk = 0;
578
579 ASSERT(pKbdTbl);
580
581 if ((wScanCode & 0xFF00) == 0xE000)
582 {
583 for (i = 0; pKbdTbl->pVSCtoVK_E0[i].Vsc; i++)
584 {
585 if (pKbdTbl->pVSCtoVK_E0[i].Vsc == (wScanCode & 0xFF))
586 {
587 wVk = pKbdTbl->pVSCtoVK_E0[i].Vk;
588 }
589 }
590 }
591 else if ((wScanCode & 0xFF00) == 0xE100)
592 {
593 for (i = 0; pKbdTbl->pVSCtoVK_E1[i].Vsc; i++)
594 {
595 if (pKbdTbl->pVSCtoVK_E1[i].Vsc == (wScanCode & 0xFF))
596 {
597 wVk = pKbdTbl->pVSCtoVK_E1[i].Vk;
598 }
599 }
600 }
601 else if (wScanCode < pKbdTbl->bMaxVSCtoVK)
602 {
603 wVk = pKbdTbl->pusVSCtoVK[wScanCode];
604 }
605
606 /* 0xFF nad 0x00 are invalid VKs */
607 return wVk != 0xFF ? wVk : 0;
608}
609
610/*
611 * IntVkToChar
612 *
613 * Translates virtual key to character, ignoring shift state
614 */
615static
618{
619 WCHAR wch;
620 BOOL bDead, bLigature;
621
622 ASSERT(pKbdTbl);
623
624 if (IntTranslateChar(wVk,
625 NULL,
626 &bDead,
627 &bLigature,
628 &wch,
629 pKbdTbl))
630 {
631 return wch;
632 }
633
634 return 0;
635}
636
637/*
638 * NtUserGetAsyncKeyState
639 *
640 * Gets key state from global bitmap
641 */
642SHORT
645{
646 WORD wRet = 0;
647
648 TRACE("Enter NtUserGetAsyncKeyState\n");
649
650 if (Key >= 0x100 || Key < 0)
651 {
653 ERR("Invalid parameter Key\n");
654 return 0;
655 }
656
658
660 wRet |= 0x8000; // If down, windows returns 0x8000.
661 if (gafAsyncKeyStateRecentDown[Key / 8] & (1 << (Key % 8)))
662 wRet |= 0x1;
663 gafAsyncKeyStateRecentDown[Key / 8] &= ~(1 << (Key % 8));
664
665 UserLeave();
666
667 TRACE("Leave NtUserGetAsyncKeyState, ret=%u\n", wRet);
668 return wRet;
669}
670
671/*
672 * UpdateAsyncKeyState
673 *
674 * Updates gafAsyncKeyState array
675 */
676static
679{
680 if (bIsDown)
681 {
682 /* If it's first key down event, xor lock bit */
683 if (!IS_KEY_DOWN(gafAsyncKeyState, wVk))
685
687 gafAsyncKeyStateRecentDown[wVk / 8] |= (1 << (wVk % 8));
688 }
689 else
691}
692
693/*
694 * co_CallLowLevelKeyboardHook
695 *
696 * Calls WH_KEYBOARD_LL hook
697 */
698static LRESULT
699co_CallLowLevelKeyboardHook(WORD wVk, WORD wScanCode, DWORD dwFlags, BOOL bInjected, DWORD dwTime, DWORD dwExtraInfo)
700{
701 KBDLLHOOKSTRUCT KbdHookData;
702 UINT uMsg;
703
704 KbdHookData.vkCode = wVk;
705 KbdHookData.scanCode = wScanCode;
706 KbdHookData.flags = 0;
708 KbdHookData.flags |= LLKHF_EXTENDED;
710 KbdHookData.flags |= LLKHF_ALTDOWN;
712 KbdHookData.flags |= LLKHF_UP;
713 if (bInjected)
714 KbdHookData.flags |= LLKHF_INJECTED;
715 KbdHookData.time = dwTime;
716 KbdHookData.dwExtraInfo = dwExtraInfo;
717
718 /* Note: it doesnt support WM_SYSKEYUP */
720 uMsg = WM_KEYUP;
722 uMsg = WM_SYSKEYDOWN;
723 else
724 uMsg = WM_KEYDOWN;
725
726 return co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, uMsg, (LPARAM)&KbdHookData);
727}
728
729/*
730 * SnapWindow
731 *
732 * Saves snapshot of specified window or whole screen in the clipboard
733 */
734static VOID
736{
737 HBITMAP hbm = NULL, hbmOld;
738 HDC hdc = NULL, hdcMem;
739 SETCLIPBDATA scd;
740 INT cx, cy;
741 PWND pWnd = NULL;
742
743 TRACE("SnapWindow(%p)\n", hWnd);
744
745 /* If no windows is given, make snapshot of desktop window */
746 if (!hWnd)
748
750 if (!pWnd)
751 {
752 ERR("Invalid window\n");
753 goto cleanup;
754 }
755
757 if (!hdc)
758 {
759 ERR("UserGetDCEx failed!\n");
760 goto cleanup;
761 }
762
763 cx = pWnd->rcWindow.right - pWnd->rcWindow.left;
764 cy = pWnd->rcWindow.bottom - pWnd->rcWindow.top;
765
767 if (!hbm)
768 {
769 ERR("NtGdiCreateCompatibleBitmap failed!\n");
770 goto cleanup;
771 }
772
774 if (!hdcMem)
775 {
776 ERR("NtGdiCreateCompatibleDC failed!\n");
777 goto cleanup;
778 }
779
780 hbmOld = NtGdiSelectBitmap(hdcMem, hbm);
781 NtGdiBitBlt(hdcMem, 0, 0, cx, cy, hdc, 0, 0, SRCCOPY, CLR_INVALID, 0);
782 NtGdiSelectBitmap(hdcMem, hbmOld);
784
785 /* Save snapshot in clipboard */
787 {
790 scd.fGlobalHandle = FALSE;
792 {
793 /* Bitmap is managed by system now */
794 hbm = NULL;
795 }
797 }
798
799cleanup:
800 if (hbm)
802 if (hdc)
803 UserReleaseDC(pWnd, hdc, FALSE);
804}
805
806/* Find the next/previous keyboard layout of the same/different language */
807static PKL FASTCALL
809 _In_ PKL pKL,
810 _In_ BOOL bNext,
811 _In_ BOOL bSameLang)
812{
813 PKL pFirstKL = pKL;
814 LANGID LangID = LOWORD(pKL->hkl);
815
816 do
817 {
818 pKL = (bNext ? pKL->pklNext : pKL->pklPrev);
819
820 if (!(pKL->dwKL_Flags & KL_UNLOAD) && bSameLang == (LangID == LOWORD(pKL->hkl)))
821 return pKL;
822 } while (pKL != pFirstKL);
823
824 return pFirstKL;
825}
826
827/* Perform layout toggle by [Left Alt]+Shift or Ctrl+Shift */
828static VOID
830 _In_ PUSER_MESSAGE_QUEUE pFocusQueue,
831 _In_ BOOL bSameLang,
832 _In_ INT nKeyState)
833{
834 PWND pWnd;
835 PTHREADINFO pti;
836 PKL pkl;
837 WPARAM wParam = 0;
838
839 if (!pFocusQueue)
840 {
841 ERR("IntLanguageToggle(): NULL pFocusQueue\n");
842 return;
843 }
844 pWnd = pFocusQueue->spwndFocus;
845 if (!pWnd)
846 pWnd = pFocusQueue->spwndActive;
847 if (!pWnd)
848 return;
849
850 pti = pWnd->head.pti;
851 pkl = pti->KeyboardLayout;
852
853 if (nKeyState == INPUTLANGCHANGE_FORWARD)
854 pkl = IntGetNextKL(pkl, TRUE, bSameLang);
855 else if (nKeyState == INPUTLANGCHANGE_BACKWARD)
856 pkl = IntGetNextKL(pkl, FALSE, bSameLang);
857
858 if (gSystemFS & pkl->dwFontSigs)
859 wParam |= INPUTLANGCHANGE_SYSCHARSET;
860
861 UserPostMessage(UserHMGetHandle(pWnd), WM_INPUTLANGCHANGEREQUEST, wParam, (LPARAM)pkl->hkl);
862}
863
864/* Check Language Toggle by [Left Alt]+Shift or Ctrl+Shift */
865static BOOL
867 _In_ PUSER_MESSAGE_QUEUE pFocusQueue,
868 _In_ BOOL bIsDown,
869 _In_ WORD wVk,
870 _Inout_ PINT pKeyState)
871{
872 if (bIsDown) /* Toggle key combination is pressed? */
873 {
874 if (wVk == VK_LSHIFT)
875 *pKeyState = INPUTLANGCHANGE_FORWARD;
876 else if (wVk == VK_RSHIFT)
877 *pKeyState = INPUTLANGCHANGE_BACKWARD;
878 else if (!wVk && IS_KEY_DOWN(gafAsyncKeyState, VK_LSHIFT))
879 *pKeyState = INPUTLANGCHANGE_FORWARD;
880 else if (!wVk && IS_KEY_DOWN(gafAsyncKeyState, VK_RSHIFT))
881 *pKeyState = INPUTLANGCHANGE_BACKWARD;
882 else
883 return FALSE;
884 }
885 else
886 {
887 if (*pKeyState == 0)
888 return FALSE;
889
890 IntLanguageToggle(pFocusQueue, (pKeyState == &gLayoutToggleKeyState), *pKeyState);
891 *pKeyState = 0;
892 }
893 return TRUE;
894}
895
910static BOOL
912 _In_ WORD wVk,
913 _In_ BOOL bIsDown,
914 _In_ DWORD dwTime /*,
915 _In_ PUSER_MESSAGE_QUEUE pFocusQueue */)
916{
917 // TODO: Handle Unicode characters.
918 if (bIsDown &&
921 {
922 TRACE("VK_MENU && !VK_CONTROL - wVk: 0x%04x\n", wVk);
923
924 /* Check if the incoming key is a numpad digit */
925 if (wVk >= VK_NUMPAD0 && wVk <= VK_NUMPAD9)
926 {
927 UINT uDigit = wVk - VK_NUMPAD0;
928
929 /* Initialize the Alt+Numpad state if necessary */
931 gAltNumPadState = (uDigit == 0) ? ALTNUM_ACP : ALTNUM_OEM;
932
933 /* Build the decimal value; the value can overflow
934 * and be truncated (same behaviour as on Windows) */
935 gAltNumPadValue = (gAltNumPadValue * 10) + uDigit;
936
937 return TRUE; /* No key processing needs to be done */
938 }
939 /* Check if the incoming key is not the menu key itself/alone */
940 else if (wVk != VK_MENU)
941 {
942 /* Reset the Alt+Numpad state */
944 gAltNumPadValue = 0;
945 }
946 }
947 TRACE("gAltNumPadState: %lu, gAltNumPadValue: %lu\n",
949
950 /* Check for the end of an Alt+Numpad sequence, triggered by the release of the ALT key */
951 if ((gAltNumPadState != ALTNUM_INACTIVE) && !bIsDown && (wVk == VK_MENU))
952 {
954
955 TRACE("End of Alt+Numpad\n");
956 if (gAltNumPadValue != 0 && pFocusQueue && pFocusQueue->ptiKeyboard)
957 {
959 WCHAR wchUnicodeChar;
960 /*
961 * NOTE: the input value is considered modulo 256, because it
962 * is stored to a 1-byte CHAR. Other applications that hook and
963 * reimplement the Alt+Numpad system (e.g. WordPad, ...) store
964 * the value instead in a 2-byte WORD, hence they consider the
965 * value modulo 65536.
966 * See: https://devblogs.microsoft.com/oldnewthing/20240702-00/?p=109951
967 */
968 CHAR cAnsiChar = (CHAR)(gAltNumPadValue & 0xFF);
969
970 /* Convert the input character value to Unicode */
972 {
973 /* Use the OEM->Unicode function */
974 Status = RtlOemToUnicodeN(&wchUnicodeChar,
975 sizeof(wchUnicodeChar),
976 NULL,
977 &cAnsiChar,
978 sizeof(cAnsiChar));
979 }
980 else if (gAltNumPadState == ALTNUM_ACP)
981 {
982 /* The sequence started with '0', use the ANSI codepage
983 * (ACP)-aware MultiByte->Unicode function */
984 Status = RtlMultiByteToUnicodeN(&wchUnicodeChar,
985 sizeof(wchUnicodeChar),
986 NULL,
987 &cAnsiChar,
988 sizeof(cAnsiChar));
989 }
990
991 /* Post the Unicode character to the focused message queue if conversion succeeded */
992 if (NT_SUCCESS(Status))
993 {
994 MSG msgChar;
995 msgChar.hwnd = pFocusQueue->spwndFocus ? UserHMGetHandle(pFocusQueue->spwndFocus) : NULL;
996 msgChar.message = WM_CHAR;
997 msgChar.wParam = wchUnicodeChar;
998 msgChar.lParam = 1;
999 msgChar.time = dwTime;
1000 msgChar.pt = gpsi->ptCursor;
1001
1002 MsqPostMessage(pFocusQueue->ptiKeyboard, &msgChar, FALSE, QS_KEY, 0, 0);
1003 }
1004 }
1005
1006 /* Reset the Alt+Numpad state */
1008 gAltNumPadValue = 0;
1009 }
1010
1011 return FALSE; /* More key processing has to be done */
1012}
1013
1014/*
1015 * UserSendKeyboardInput
1016 *
1017 * Process keyboard input from input devices and SendInput API
1018 */
1019BOOL NTAPI
1020ProcessKeyEvent(WORD wVk, WORD wScanCode, DWORD dwFlags, BOOL bInjected, DWORD dwTime, DWORD dwExtraInfo)
1021{
1022 WORD wSimpleVk, wFixedVk, wVk2;
1023 PUSER_MESSAGE_QUEUE pFocusQueue;
1024 PTHREADINFO pti;
1026 BOOL bIsDown = (dwFlags & KEYEVENTF_KEYUP) ? FALSE : TRUE;
1027 BOOL bPacket = (dwFlags & KEYEVENTF_UNICODE) ? TRUE : FALSE;
1028 BOOL bWasSimpleDown = FALSE, bPostMsg = TRUE, bIsSimpleDown;
1029 MSG Msg;
1030 static BOOL bMenuDownRecently = FALSE;
1031 BOOL bLangToggled = FALSE;
1032
1033 /* Get virtual key without shifts (VK_(L|R)* -> VK_*) */
1034 wSimpleVk = IntSimplifyVk(wVk);
1035
1037 {
1038 /* Japanese special! */
1040 {
1041 if (wSimpleVk == VK_OEM_ATTN)
1042 wSimpleVk = VK_CAPITAL;
1043 else if (wSimpleVk == VK_OEM_COPY)
1044 wSimpleVk = VK_OEM_FINISH;
1045 }
1046 }
1047
1048 /* Handle Alt+Numpad character composition */
1049 if (IntHandleAltNumpad(wSimpleVk, bIsDown, dwTime))
1050 return TRUE;
1051
1052 bWasSimpleDown = IS_KEY_DOWN(gafAsyncKeyState, wSimpleVk);
1053
1054 /* Update key without shifts */
1055 wVk2 = IntFixVk(wSimpleVk, !bExt);
1056 bIsSimpleDown = bIsDown || IS_KEY_DOWN(gafAsyncKeyState, wVk2);
1057 UpdateAsyncKeyState(wSimpleVk, bIsSimpleDown);
1058
1059 if (bIsDown)
1060 {
1061 /* Update keyboard LEDs */
1063 wSimpleVk,
1064 wScanCode);
1065 }
1066
1067 /* Call WH_KEYBOARD_LL hook */
1068 if (co_CallLowLevelKeyboardHook(wVk, wScanCode, dwFlags, bInjected, dwTime, dwExtraInfo))
1069 {
1070 ERR("Kbd msg dropped by WH_KEYBOARD_LL hook\n");
1071 bPostMsg = FALSE;
1072 }
1073
1074 /* Check if this is a hotkey */
1075 if (co_UserProcessHotKeys(wSimpleVk, bIsDown))
1076 {
1077 TRACE("HotKey Processed\n");
1078 bPostMsg = FALSE;
1079 }
1080
1081 wFixedVk = IntFixVk(wSimpleVk, bExt); /* LSHIFT + EXT = RSHIFT */
1082 if (wSimpleVk == VK_SHIFT) /* shift can't be extended */
1083 bExt = FALSE;
1084
1085 /* If we have a focus queue, post a keyboard message */
1086 pFocusQueue = IntGetFocusMessageQueue();
1087 TRACE("ProcessKeyEvent Q 0x%p Active pWnd 0x%p Focus pWnd 0x%p\n",
1088 pFocusQueue,
1089 (pFocusQueue ? pFocusQueue->spwndActive : NULL),
1090 (pFocusQueue ? pFocusQueue->spwndFocus : NULL));
1091
1092 /* If it is F10 or ALT is down and CTRL is up, it's a system key */
1093 if ( wVk == VK_F10 ||
1094 (wSimpleVk == VK_MENU && bMenuDownRecently) ||
1097 // See MSDN WM_SYSKEYDOWN/UP fixes last wine Win test_keyboard_input.
1098 (pFocusQueue && !pFocusQueue->spwndFocus) )
1099 {
1100 bMenuDownRecently = FALSE; // reset
1101 if (bIsDown)
1102 {
1103 Msg.message = WM_SYSKEYDOWN;
1104 if (wSimpleVk == VK_MENU)
1105 {
1106 // Note: If only LALT is pressed WM_SYSKEYUP is generated instead of WM_KEYUP
1107 bMenuDownRecently = TRUE;
1108 }
1109 }
1110 else
1111 Msg.message = WM_SYSKEYUP;
1112 }
1113 else
1114 {
1115 if (bIsDown)
1116 Msg.message = WM_KEYDOWN;
1117 else
1118 Msg.message = WM_KEYUP;
1119 }
1120
1121 /* Update async state of not simplified vk here.
1122 See user32_apitest:GetKeyState */
1123 UpdateAsyncKeyState(wFixedVk, bIsDown);
1124
1125 /* Alt-Tab/Esc Check. Use FocusQueue or RIT Queue */
1126 if (bIsSimpleDown && !bWasSimpleDown &&
1129 (wVk == VK_ESCAPE || wVk == VK_TAB))
1130 {
1131 TRACE("Alt-Tab/Esc Pressed wParam %x\n",wVk);
1132 }
1133
1134 /*
1135 * Check Language/Layout Toggle by [Left Alt]+Shift or Ctrl+Shift.
1136 * @see https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc976564%28v=technet.10%29
1137 */
1139 {
1140 if (wSimpleVk == VK_SHIFT) /* Shift key is pressed or released */
1141 {
1142 UINT targetKey = ((gdwLanguageToggleKey == 1) ? VK_LMENU : VK_CONTROL);
1143 if (IS_KEY_DOWN(gafAsyncKeyState, targetKey))
1144 bLangToggled = IntCheckLanguageToggle(pFocusQueue, bIsDown, wVk, &gLanguageToggleKeyState);
1145 }
1146 else if ((wSimpleVk == VK_MENU && gdwLanguageToggleKey == 1) ||
1147 (wSimpleVk == VK_CONTROL && gdwLanguageToggleKey == 2))
1148 {
1150 bLangToggled = IntCheckLanguageToggle(pFocusQueue, bIsDown, 0, &gLanguageToggleKeyState);
1151 }
1152 }
1153 if (!bLangToggled && (gdwLayoutToggleKey == 1 || gdwLayoutToggleKey == 2))
1154 {
1155 if (wSimpleVk == VK_SHIFT) /* Shift key is pressed or released */
1156 {
1157 UINT targetKey = ((gdwLayoutToggleKey == 1) ? VK_LMENU : VK_CONTROL);
1158 if (IS_KEY_DOWN(gafAsyncKeyState, targetKey))
1159 IntCheckLanguageToggle(pFocusQueue, bIsDown, wVk, &gLayoutToggleKeyState);
1160 }
1161 else if ((wSimpleVk == VK_MENU && gdwLayoutToggleKey == 1) ||
1162 (wSimpleVk == VK_CONTROL && gdwLayoutToggleKey == 2))
1163 {
1165 IntCheckLanguageToggle(pFocusQueue, bIsDown, 0, &gLayoutToggleKeyState);
1166 }
1167 }
1168
1169 if (bIsDown && wVk == VK_SNAPSHOT)
1170 {
1171 if (pFocusQueue &&
1174 {
1175 // Snap from Active Window, Focus can be null.
1176 SnapWindow(pFocusQueue->spwndActive ? UserHMGetHandle(pFocusQueue->spwndActive) : NULL);
1177 }
1178 else
1179 SnapWindow(NULL); // Snap Desktop.
1180 }
1181 else if (pFocusQueue && bPostMsg)
1182 {
1183 PWND Wnd = pFocusQueue->spwndFocus; // SysInit.....
1184
1185 pti = pFocusQueue->ptiKeyboard;
1186
1187 if (!Wnd && pFocusQueue->spwndActive) // SysInit.....
1188 {
1189 // Going with Active. WM_SYSKEYXXX last wine Win test_keyboard_input.
1190 Wnd = pFocusQueue->spwndActive;
1191 }
1192 if (Wnd) pti = Wnd->head.pti;
1193
1194 /* Init message */
1195 Msg.hwnd = Wnd ? UserHMGetHandle(Wnd) : NULL;
1196 Msg.wParam = wFixedVk & 0xFF; /* Note: It's simplified by msg queue */
1197 Msg.lParam = MAKELPARAM(1, wScanCode);
1198 Msg.time = dwTime;
1199 Msg.pt = gpsi->ptCursor;
1200
1201 if ( Msg.message == WM_KEYDOWN || Msg.message == WM_SYSKEYDOWN )
1202 {
1203 if ( (Msg.wParam == VK_SHIFT ||
1204 Msg.wParam == VK_CONTROL ||
1205 Msg.wParam == VK_MENU ) &&
1207 {
1208 ERR("Set last input\n");
1209 //ptiLastInput = pti;
1210 }
1211 }
1212
1213 /* If it is VK_PACKET, high word of wParam is used for wchar */
1214 if (!bPacket)
1215 {
1216 if (bExt)
1217 Msg.lParam |= KF_EXTENDED << 16;
1219 Msg.lParam |= KF_ALTDOWN << 16;
1220 if (bWasSimpleDown)
1221 Msg.lParam |= KF_REPEAT << 16;
1222 if (!bIsDown)
1223 Msg.lParam |= KF_UP << 16;
1224 /* FIXME: Set KF_DLGMODE and KF_MENUMODE when needed */
1225 if (pFocusQueue->QF_flags & QF_DIALOGACTIVE)
1226 Msg.lParam |= KF_DLGMODE << 16;
1227 if (pFocusQueue->MenuOwner) // pti->pMenuState->fMenuStarted
1228 Msg.lParam |= KF_MENUMODE << 16;
1229 }
1230
1231 // Post mouse move before posting key buttons, to keep it syned.
1232 if (pFocusQueue->QF_flags & QF_MOUSEMOVED)
1233 {
1235 }
1236
1237 /* Post a keyboard message */
1238 TRACE("Posting keyboard msg %u wParam 0x%x lParam 0x%x\n", Msg.message, Msg.wParam, Msg.lParam);
1239 if (!Wnd) {ERR("Window is NULL\n");}
1240 MsqPostMessage(pti, &Msg, TRUE, QS_KEY, 0, dwExtraInfo);
1241 }
1242 return TRUE;
1243}
1244
1245BOOL NTAPI
1247{
1248 WORD wScanCode, wVk;
1249 PKL pKl = NULL;
1250 PKBDTABLES pKbdTbl;
1251 PUSER_MESSAGE_QUEUE pFocusQueue;
1252 DWORD dwTime;
1253 BOOL bExt = (pKbdInput->dwFlags & KEYEVENTF_EXTENDEDKEY) ? TRUE : FALSE;
1254
1256
1257 /* Find the target thread whose locale is in effect */
1258 pFocusQueue = IntGetFocusMessageQueue();
1259
1260 if (pFocusQueue && pFocusQueue->ptiKeyboard)
1261 {
1262 pKl = pFocusQueue->ptiKeyboard->KeyboardLayout;
1263 }
1264
1265 if (!pKl)
1267 if (!pKl)
1268 {
1269 ERR("No keyboard layout!\n");
1270 return FALSE;
1271 }
1272
1273 pKbdTbl = pKl->spkf->pKbdTbl;
1274
1275 /* Note: wScan field is always used */
1276 wScanCode = pKbdInput->wScan;
1277
1278 if (pKbdInput->dwFlags & KEYEVENTF_UNICODE)
1279 {
1280 /* Generate WM_KEYDOWN msg with wParam == VK_PACKET and
1281 high order word of lParam == pKbdInput->wScan */
1282 wVk = VK_PACKET;
1283 }
1284 else
1285 {
1286 wScanCode &= 0x7F;
1287 if (pKbdInput->dwFlags & KEYEVENTF_SCANCODE)
1288 {
1289 /* Don't ignore invalid scan codes */
1290 wVk = IntVscToVk(wScanCode | (bExt ? 0xE000 : 0), pKbdTbl);
1291 if (!wVk) /* use 0xFF if vsc is invalid */
1292 wVk = 0xFF;
1293 }
1294 else
1295 {
1296 wVk = pKbdInput->wVk;
1297 }
1298
1299 /* Remove all virtual key flags (KBDEXT, KBDMULTIVK, KBDSPECIAL, KBDNUMPAD) */
1300 wVk &= 0xFF;
1301 }
1302
1303 /* If time is given, use it */
1304 if (pKbdInput->time)
1305 dwTime = pKbdInput->time;
1306 else
1307 {
1309 }
1310
1311 if (wVk == VK_RMENU && (pKbdTbl->fLocaleFlags & KLLF_ALTGR))
1312 {
1313 /* For AltGr keyboards RALT generates CTRL events */
1314 ProcessKeyEvent(VK_LCONTROL, 0, pKbdInput->dwFlags & KEYEVENTF_KEYUP, bInjected, dwTime, 0);
1315 }
1316
1317 /* Finally process this key */
1318 return ProcessKeyEvent(wVk, wScanCode, pKbdInput->dwFlags, bInjected, dwTime, pKbdInput->dwExtraInfo);
1319}
1320
1321/*
1322 * UserProcessKeyboardInput
1323 *
1324 * Process raw keyboard input data
1325 */
1326VOID NTAPI
1328 PKEYBOARD_INPUT_DATA pKbdInputData)
1329{
1330 WORD wScanCode, wVk;
1331 PKL pKl = NULL;
1332 PKBDTABLES pKbdTbl;
1333 PUSER_MESSAGE_QUEUE pFocusQueue;
1334
1335 /* Calculate scan code with prefix */
1336 wScanCode = pKbdInputData->MakeCode & 0x7F;
1337 if (pKbdInputData->Flags & KEY_E0)
1338 wScanCode |= 0xE000;
1339 if (pKbdInputData->Flags & KEY_E1)
1340 wScanCode |= 0xE100;
1341
1342 /* Find the target thread whose locale is in effect */
1343 pFocusQueue = IntGetFocusMessageQueue();
1344
1345 if (pFocusQueue && pFocusQueue->ptiKeyboard)
1346 {
1347 pKl = pFocusQueue->ptiKeyboard->KeyboardLayout;
1348 }
1349
1350 if (!pKl)
1352 if (!pKl)
1353 return;
1354
1355 pKbdTbl = pKl->spkf->pKbdTbl;
1356
1357 /* Convert scan code to virtual key.
1358 Note: We could call UserSendKeyboardInput using scan code,
1359 but it wouldn't interpret E1 key(s) properly */
1360 wVk = IntVscToVk(wScanCode, pKbdTbl);
1361 TRACE("UserProcessKeyboardInput: %x (break: %u) -> %x\n",
1362 wScanCode, (pKbdInputData->Flags & KEY_BREAK) ? 1u : 0, wVk);
1363
1364 if (wVk)
1365 {
1366 KEYBDINPUT KbdInput;
1367
1368 /* Support numlock */
1370 {
1371 wVk = IntTranslateNumpadKey(wVk & 0xFF);
1372 }
1373
1374 /* Send keyboard input */
1375 KbdInput.wVk = wVk & 0xFF;
1376 KbdInput.wScan = wScanCode & 0x7F;
1377 KbdInput.dwFlags = 0;
1378 if (pKbdInputData->Flags & KEY_BREAK)
1379 KbdInput.dwFlags |= KEYEVENTF_KEYUP;
1380
1381 if (wVk & KBDEXT)
1382 KbdInput.dwFlags |= KEYEVENTF_EXTENDEDKEY;
1383 //
1384 // Based on wine input:test_Input_blackbox this is okay. It seems the
1385 // bit did not get set and more research is needed. Now the right
1386 // shift works.
1387 //
1388 if (wVk == VK_RSHIFT)
1389 KbdInput.dwFlags |= KEYEVENTF_EXTENDEDKEY;
1390
1391 KbdInput.time = 0;
1392 KbdInput.dwExtraInfo = pKbdInputData->ExtraInformation;
1393 UserSendKeyboardInput(&KbdInput, FALSE);
1394
1395 /* E1 keys don't have break code */
1396 if (pKbdInputData->Flags & KEY_E1)
1397 {
1398 /* Send key up event */
1399 KbdInput.dwFlags |= KEYEVENTF_KEYUP;
1400 UserSendKeyboardInput(&KbdInput, FALSE);
1401 }
1402 }
1403}
1404
1405/*
1406 * IntTranslateKbdMessage
1407 *
1408 * Addes WM_(SYS)CHAR messages to message queue if message
1409 * describes key which produce character.
1410 */
1413 UINT flags)
1414{
1415 PTHREADINFO pti;
1416 INT cch = 0, i;
1417 WCHAR wch[3] = { 0 };
1418 MSG NewMsg = { 0 };
1419 PKBDTABLES pKbdTbl;
1420 BOOL bResult = FALSE;
1421
1422 switch(lpMsg->message)
1423 {
1424 case WM_KEYDOWN:
1425 case WM_KEYUP:
1426 case WM_SYSKEYDOWN:
1427 case WM_SYSKEYUP:
1428 break;
1429 default:
1430 return FALSE;
1431 }
1432
1434
1435 if (!pti->KeyboardLayout)
1436 {
1437 PKL pDefKL = W32kGetDefaultKeyLayout();
1438 UserAssignmentLock((PVOID*)&(pti->KeyboardLayout), pDefKL);
1439 if (pDefKL)
1440 {
1441 pti->pClientInfo->hKL = pDefKL->hkl;
1442 pKbdTbl = pDefKL->spkf->pKbdTbl;
1443 }
1444 else
1445 {
1446 pti->pClientInfo->hKL = NULL;
1447 pKbdTbl = NULL;
1448 }
1449 }
1450 else
1451 pKbdTbl = pti->KeyboardLayout->spkf->pKbdTbl;
1452 if (!pKbdTbl)
1453 return FALSE;
1454
1455 if (lpMsg->message != WM_KEYDOWN && lpMsg->message != WM_SYSKEYDOWN)
1456 return FALSE;
1457
1458 /* Init pt, hwnd and time msg fields */
1459 NewMsg.pt = gpsi->ptCursor;
1460 NewMsg.hwnd = lpMsg->hwnd;
1461 NewMsg.time = EngGetTickCount32();
1462
1463 TRACE("Enter IntTranslateKbdMessage msg %s, vk %x\n",
1464 lpMsg->message == WM_SYSKEYDOWN ? "WM_SYSKEYDOWN" : "WM_KEYDOWN", lpMsg->wParam);
1465
1466 if (lpMsg->wParam == VK_PACKET)
1467 {
1468 NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
1469 NewMsg.wParam = HIWORD(lpMsg->lParam);
1470 NewMsg.lParam = LOWORD(lpMsg->lParam);
1471 MsqPostMessage(pti, &NewMsg, FALSE, QS_KEY, 0, 0);
1472 return TRUE;
1473 }
1474
1475 cch = IntToUnicodeEx(lpMsg->wParam,
1476 HIWORD(lpMsg->lParam) & 0xFF,
1477 pti->MessageQueue->afKeyState,
1478 wch,
1479 sizeof(wch) / sizeof(wch[0]),
1480 0,
1481 pKbdTbl);
1482
1483 if (cch)
1484 {
1485 if (cch > 0) /* Normal characters */
1486 NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
1487 else /* Dead character */
1488 {
1489 cch = -cch;
1490 NewMsg.message =
1492 }
1493 NewMsg.lParam = lpMsg->lParam;
1494
1495 /* Send all characters */
1496 for (i = 0; i < cch; ++i)
1497 {
1498 TRACE("Msg: %x '%lc' (%04x) %08x\n", NewMsg.message, wch[i], wch[i], NewMsg.lParam);
1499 NewMsg.wParam = wch[i];
1500 MsqPostMessage(pti, &NewMsg, FALSE, QS_KEY, 0, 0);
1501 }
1502 bResult = TRUE;
1503 }
1504
1505 TRACE("Leave IntTranslateKbdMessage ret %d, cch %d, msg %x, wch %x\n",
1506 bResult, cch, NewMsg.message, NewMsg.wParam);
1507 return bResult;
1508}
1509
1510/*
1511 * Map a virtual key code, or virtual scan code, to a scan code, key code,
1512 * or unshifted unicode character.
1513 *
1514 * Code: See Below
1515 * Type:
1516 * 0 -- Code is a virtual key code that is converted into a virtual scan code
1517 * that does not distinguish between left and right shift keys.
1518 * 1 -- Code is a virtual scan code that is converted into a virtual key code
1519 * that does not distinguish between left and right shift keys.
1520 * 2 -- Code is a virtual key code that is converted into an unshifted unicode
1521 * character.
1522 * 3 -- Code is a virtual scan code that is converted into a virtual key code
1523 * that distinguishes left and right shift keys.
1524 * KeyLayout: Keyboard layout handle
1525 *
1526 * @implemented
1527 */
1528static UINT
1530{
1531 UINT uRet = 0;
1532
1533 switch (Type)
1534 {
1535 case MAPVK_VK_TO_VSC:
1536 uCode = IntFixVk(uCode, FALSE);
1537 uRet = IntVkToVsc(uCode, pKbdTbl);
1538 if (uRet > 0xFF) // Fail for scancodes with prefix (e0, e1)
1539 uRet = 0;
1540 break;
1541
1542 case MAPVK_VSC_TO_VK:
1543 uRet = IntVscToVk(uCode, pKbdTbl) & 0xFF;
1544 uRet = IntSimplifyVk(uRet);
1545 break;
1546
1547 case MAPVK_VK_TO_CHAR:
1548 uRet = (UINT)IntVkToChar(uCode, pKbdTbl);
1549 break;
1550
1551 case MAPVK_VSC_TO_VK_EX:
1552 uRet = IntVscToVk(uCode, pKbdTbl) & 0xFF;
1553 break;
1554
1555 case MAPVK_VK_TO_VSC_EX:
1556 uRet = IntVkToVsc(uCode, pKbdTbl);
1557 break;
1558
1559 default:
1561 ERR("Wrong type value: %u\n", Type);
1562 }
1563
1564 return uRet;
1565}
1566
1567/*
1568 * NtUserMapVirtualKeyEx
1569 *
1570 * Map a virtual key code, or virtual scan code, to a scan code, key code,
1571 * or unshifted unicode character. See IntMapVirtualKeyEx.
1572 */
1573UINT
1575NtUserMapVirtualKeyEx(UINT uCode, UINT uType, DWORD keyboardId, HKL dwhkl)
1576{
1577 PKBDTABLES pKbdTbl = NULL;
1578 UINT ret = 0;
1579
1580 TRACE("Enter NtUserMapVirtualKeyEx\n");
1582
1583 if (!dwhkl)
1584 {
1585 PTHREADINFO pti;
1586
1588 if (pti && pti->KeyboardLayout)
1589 pKbdTbl = pti->KeyboardLayout->spkf->pKbdTbl;
1590 }
1591 else
1592 {
1593 PKL pKl;
1594
1595 pKl = UserHklToKbl(dwhkl);
1596 if (pKl)
1597 pKbdTbl = pKl->spkf->pKbdTbl;
1598 }
1599
1600 if (pKbdTbl)
1601 ret = IntMapVirtualKeyEx(uCode, uType, pKbdTbl);
1602
1603 UserLeave();
1604 TRACE("Leave NtUserMapVirtualKeyEx, ret=%u\n", ret);
1605 return ret;
1606}
1607
1608/*
1609 * NtUserToUnicodeEx
1610 *
1611 * Translates virtual key to characters
1612 */
1613int
1616 UINT wVirtKey,
1617 UINT wScanCode,
1618 PBYTE pKeyStateUnsafe,
1619 LPWSTR pwszBuffUnsafe,
1620 INT cchBuff,
1621 UINT wFlags,
1622 HKL dwhkl)
1623{
1624 PTHREADINFO pti;
1625 BYTE afKeyState[256 * 2 / 8] = {0};
1626 PWCHAR pwszBuff = NULL;
1627 INT i, iRet = 0;
1628 PKL pKl = NULL;
1630
1631 TRACE("Enter NtUserSetKeyboardState\n");
1632
1633 /* Return 0 if SC_KEY_UP bit is set */
1634 if (wScanCode & SC_KEY_UP || wVirtKey >= 0x100)
1635 {
1636 ERR("Invalid parameter\n");
1637 return 0;
1638 }
1639
1640 _SEH2_TRY
1641 {
1642 /* Probe and copy key state to smaller bitmap */
1643 ProbeForRead(pKeyStateUnsafe, 256 * sizeof(BYTE), 1);
1644 for (i = 0; i < 256; ++i)
1645 {
1646 if (pKeyStateUnsafe[i] & KS_DOWN_BIT)
1647 SET_KEY_DOWN(afKeyState, i, TRUE);
1648 if (pKeyStateUnsafe[i] & KS_LOCK_BIT)
1649 SET_KEY_LOCKED(afKeyState, i, TRUE);
1650 }
1651 }
1653 {
1654 ERR("Cannot copy key state\n");
1656 _SEH2_YIELD(return 0);
1657 }
1658 _SEH2_END;
1659
1660 pwszBuff = ExAllocatePoolWithTag(NonPagedPool, sizeof(WCHAR) * cchBuff, TAG_STRING);
1661 if (!pwszBuff)
1662 {
1663 ERR("ExAllocatePoolWithTag(%u) failed\n", sizeof(WCHAR) * cchBuff);
1664 return 0;
1665 }
1666 RtlZeroMemory(pwszBuff, sizeof(WCHAR) * cchBuff);
1667
1668 UserEnterExclusive(); // Note: We modify wchDead static variable
1669
1670 if (dwhkl)
1671 pKl = UserHklToKbl(dwhkl);
1672
1673 if (!pKl)
1674 {
1676 pKl = pti->KeyboardLayout;
1677 }
1678
1679 if (pKl)
1680 {
1681 iRet = IntToUnicodeEx(wVirtKey,
1682 wScanCode,
1683 afKeyState,
1684 pwszBuff,
1685 cchBuff,
1686 wFlags,
1687 pKl->spkf->pKbdTbl);
1688
1689 if (iRet)
1690 {
1691 Status = MmCopyToCaller(pwszBuffUnsafe, pwszBuff, cchBuff * sizeof(WCHAR));
1692 }
1693 }
1694 else
1695 {
1696 ERR("No keyboard layout ?!\n");
1698 }
1699
1700 ExFreePoolWithTag(pwszBuff, TAG_STRING);
1701
1702 if (!NT_SUCCESS(Status))
1703 {
1704 iRet = 0;
1706 }
1707
1708 UserLeave();
1709 TRACE("Leave NtUserSetKeyboardState, ret=%i\n", iRet);
1710 return iRet;
1711}
1712
1713/*
1714 * NtUserGetKeyNameText
1715 *
1716 * Gets key name from keyboard layout
1717 */
1718DWORD
1721{
1722 PTHREADINFO pti;
1723 DWORD i, dwRet = 0;
1724 SIZE_T cchKeyName;
1725 WORD wScanCode = (lParam >> 16) & 0xFF;
1726 BOOL bExtKey = (HIWORD(lParam) & KF_EXTENDED) ? TRUE : FALSE;
1727 PKBDTABLES pKbdTbl;
1728 VSC_LPWSTR *pKeyNames = NULL;
1729 CONST WCHAR *pKeyName = NULL;
1730 WCHAR KeyNameBuf[2];
1731
1732 TRACE("Enter NtUserGetKeyNameText\n");
1733
1735
1736 /* Get current keyboard layout */
1738 pKbdTbl = pti ? pti->KeyboardLayout->spkf->pKbdTbl : NULL;
1739
1740 if (!pKbdTbl || cchSize < 1)
1741 {
1742 ERR("Invalid parameter\n");
1743 goto cleanup;
1744 }
1745
1746 /* "Do not care" flag */
1748 {
1749 /* Note: We could do vsc -> vk -> vsc conversion, instead of using
1750 hardcoded scan codes, but it's not what Windows does */
1751 if (wScanCode == SCANCODE_RSHIFT && !bExtKey)
1752 wScanCode = SCANCODE_LSHIFT;
1753 else if (wScanCode == SCANCODE_CTRL || wScanCode == SCANCODE_ALT)
1754 bExtKey = FALSE;
1755 }
1756
1757 if (bExtKey)
1758 pKeyNames = pKbdTbl->pKeyNamesExt;
1759 else
1760 pKeyNames = pKbdTbl->pKeyNames;
1761
1762 for (i = 0; pKeyNames[i].pwsz; i++)
1763 {
1764 if (pKeyNames[i].vsc == wScanCode)
1765 {
1766 pKeyName = pKeyNames[i].pwsz;
1767 break;
1768 }
1769 }
1770
1771 if (!pKeyName)
1772 {
1773 WORD wVk = IntVscToVk(wScanCode, pKbdTbl);
1774
1775 if (wVk)
1776 {
1777 KeyNameBuf[0] = IntVkToChar(wVk, pKbdTbl);
1778 KeyNameBuf[1] = 0;
1779 if (KeyNameBuf[0])
1780 pKeyName = KeyNameBuf;
1781 }
1782 }
1783
1784 if (pKeyName)
1785 {
1786 cchKeyName = wcslen(pKeyName);
1787 if (cchKeyName > (cchSize - 1UL))
1788 cchKeyName = cchSize - 1UL; // Don't count '\0'
1789
1790 _SEH2_TRY
1791 {
1792 ProbeForWrite(lpString, (cchKeyName + 1) * sizeof(WCHAR), 1);
1793 RtlCopyMemory(lpString, pKeyName, cchKeyName * sizeof(WCHAR));
1794 lpString[cchKeyName] = UNICODE_NULL;
1795 dwRet = cchKeyName;
1796 }
1798 {
1800 }
1801 _SEH2_END;
1802 }
1803 else
1804 {
1806 }
1807
1808cleanup:
1809 UserLeave();
1810 TRACE("Leave NtUserGetKeyNameText, ret=%lu\n", dwRet);
1811 return dwRet;
1812}
1813
1814/*
1815 * UserGetKeyboardType
1816 *
1817 * Returns some keyboard specific information
1818 */
1821 DWORD dwTypeFlag)
1822{
1823 switch (dwTypeFlag)
1824 {
1825 case 0: /* Keyboard type */
1827 case 1: /* Keyboard Subtype */
1829 case 2: /* Number of F-keys */
1831 default:
1832 ERR("Unknown type!\n");
1833 return 0; /* Note: we don't have to set last error here */
1834 }
1835}
1836
1837/*
1838 * NtUserVkKeyScanEx
1839 *
1840 * Based on IntTranslateChar, instead of processing VirtualKey match,
1841 * look for wChar match.
1842 */
1843DWORD
1846 WCHAR wch,
1847 HKL dwhkl,
1848 BOOL bUsehKL)
1849{
1850 PKBDTABLES pKbdTbl;
1851 PVK_TO_WCHAR_TABLE pVkToWchTbl;
1852 PVK_TO_WCHARS10 pVkToWch;
1853 PKL pKl = NULL;
1854 DWORD i, dwModBits = 0, dwModNumber = 0, Ret = (DWORD)-1;
1855
1856 TRACE("NtUserVkKeyScanEx() wch %u, KbdLayout 0x%p\n", wch, dwhkl);
1858
1859 if (bUsehKL)
1860 {
1861 // Use given keyboard layout
1862 if (dwhkl)
1863 pKl = UserHklToKbl(dwhkl);
1864 }
1865 else
1866 {
1867 // Use thread keyboard layout
1868 pKl = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->KeyboardLayout;
1869 }
1870
1871 if (!pKl)
1872 goto Exit;
1873
1874 pKbdTbl = pKl->spkf->pKbdTbl;
1875
1876 // Interate through all VkToWchar tables while pVkToWchars is not NULL
1877 for (i = 0; pKbdTbl->pVkToWcharTable[i].pVkToWchars; i++)
1878 {
1879 pVkToWchTbl = &pKbdTbl->pVkToWcharTable[i];
1880 pVkToWch = (PVK_TO_WCHARS10)(pVkToWchTbl->pVkToWchars);
1881
1882 // Interate through all virtual keys
1883 while (pVkToWch->VirtualKey)
1884 {
1885 for (dwModNumber = 0; dwModNumber < pVkToWchTbl->nModifications; dwModNumber++)
1886 {
1887 if (pVkToWch->wch[dwModNumber] == wch)
1888 {
1889 dwModBits = pKbdTbl->pCharModifiers->ModNumber[dwModNumber];
1890 TRACE("i %lu wC %04x: dwModBits %08x dwModNumber %08x MaxModBits %08x\n",
1891 i, wch, dwModBits, dwModNumber, pKbdTbl->pCharModifiers->wMaxModBits);
1892 Ret = (dwModBits << 8) | (pVkToWch->VirtualKey & 0xFF);
1893 goto Exit;
1894 }
1895 }
1896 pVkToWch = (PVK_TO_WCHARS10)(((BYTE *)pVkToWch) + pVkToWchTbl->cbSize);
1897 }
1898 }
1899Exit:
1900 UserLeave();
1901 return Ret;
1902}
1903
1904/* EOF */
#define CODE_SEG(...)
#define DCX_USESTYLE
Definition: GetDCEx.c:10
Type
Definition: Type.h:7
HWND hWnd
Definition: settings.c:17
LONG NTSTATUS
Definition: precomp.h:26
#define CF_BITMAP
Definition: constants.h:397
#define CHAR(Char)
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:106
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
struct @1743 Msg[]
#define STATUS_INVALID_HANDLE
Definition: d3dkmdt.h:40
#define STATUS_NOT_SUPPORTED
Definition: d3dkmdt.h:48
BOOL FASTCALL IntGdiDeleteDC(HDC, BOOL)
Definition: dclife.c:892
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define APIENTRY
Definition: api.h:79
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
static void cleanup(void)
Definition: main.c:1335
_ACRTIMP size_t __cdecl wcslen(const wchar_t *)
Definition: wcs.c:2983
return ret
Definition: mutex.c:146
#define EngGetTickCount32()
Definition: eng.h:43
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define NonPagedPool
Definition: env_spec_w32.h:307
#define PagedPool
Definition: env_spec_w32.h:308
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
Status
Definition: gdiplustypes.h:25
GLbitfield flags
Definition: glext.h:7161
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
PSERVERINFO gpsi
Definition: imm.c:18
#define UserHMGetHandle(obj)
Definition: ntuser.h:230
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
#define WCH_DEAD
Definition: kbd.h:114
#define SCANCODE_LSHIFT
Definition: kbd.h:128
#define SCANCODE_ALT
Definition: kbd.h:131
#define CAPLOK
Definition: kbd.h:118
#define WCH_LGTR
Definition: kbd.h:115
#define KBDALT
Definition: kbd.h:16
#define WCH_NONE
Definition: kbd.h:113
#define CAPLOKALTGR
Definition: kbd.h:120
#define KBDCTRL
Definition: kbd.h:15
#define KBDNUMPAD
Definition: kbd.h:11
#define SCANCODE_RSHIFT
Definition: kbd.h:129
#define KBDEXT
Definition: kbd.h:8
#define KLLF_ALTGR
Definition: kbd.h:91
#define SCANCODE_CTRL
Definition: kbd.h:130
#define KBDSHIFT
Definition: kbd.h:14
USHORT LANGID
Definition: mui.h:9
LONG_PTR LPARAM
Definition: minwindef.h:175
LONG_PTR LRESULT
Definition: minwindef.h:176
UINT_PTR WPARAM
Definition: minwindef.h:174
int * PINT
Definition: minwindef.h:150
BOOL * PBOOL
Definition: minwindef.h:137
#define MmCopyToCaller(x, y, z)
Definition: mmcopy.h:19
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:56
HDC hdc
Definition: main.c:9
static HBITMAP
Definition: button.c:44
static HDC
Definition: imagelist.c:88
UINT_PTR HKL
Definition: msctf.idl:125
VOID FASTCALL IntCoalesceMouseMove(PTHREADINFO pti)
Definition: msgqueue.c:551
VOID FASTCALL MsqPostMessage(PTHREADINFO pti, MSG *Msg, BOOLEAN HardwareMessage, DWORD MessageBits, DWORD dwQEvent, LONG_PTR ExtraInfo)
Definition: msgqueue.c:1337
#define QF_DIALOGACTIVE
Definition: msgqueue.h:106
#define QF_MOUSEMOVED
Definition: msgqueue.h:99
unsigned int UINT
Definition: ndis.h:50
_In_ LPWSTR _In_ DWORD _In_ DWORD _In_ DWORD dwFlags
Definition: netsh.h:141
_Use_decl_annotations_ NTSTATUS NTAPI RtlMultiByteToUnicodeN(_Out_ PWCH UnicodeString, _In_ ULONG UnicodeSize, _Out_opt_ PULONG ResultSize, _In_ PCCH MbString, _In_ ULONG MbSize)
Definition: nlsboot.c:62
_Use_decl_annotations_ NTSTATUS NTAPI RtlOemToUnicodeN(_Out_ PWCHAR UnicodeString, _In_ ULONG UnicodeSize, _Out_opt_ PULONG ResultSize, _In_ PCCH OemString, _In_ ULONG OemSize)
Definition: nlsboot.c:282
#define _Inout_
Definition: no_sal2.h:162
#define _In_
Definition: no_sal2.h:158
#define FASTCALL
Definition: nt_native.h:50
#define DWORD
Definition: nt_native.h:44
#define UNICODE_NULL
#define KEYBOARD_CAPS_LOCK_ON
Definition: ntddkbd.h:81
#define KEY_BREAK
Definition: ntddkbd.h:71
#define IOCTL_KEYBOARD_QUERY_INDICATORS
Definition: ntddkbd.h:35
#define IOCTL_KEYBOARD_SET_INDICATORS
Definition: ntddkbd.h:47
#define IOCTL_KEYBOARD_QUERY_ATTRIBUTES
Definition: ntddkbd.h:32
struct _KEYBOARD_INDICATOR_TRANSLATION KEYBOARD_INDICATOR_TRANSLATION
#define IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
Definition: ntddkbd.h:38
#define KEYBOARD_SCROLL_LOCK_ON
Definition: ntddkbd.h:83
#define KEY_E1
Definition: ntddkbd.h:73
#define KEY_E0
Definition: ntddkbd.h:72
#define KEYBOARD_NUM_LOCK_ON
Definition: ntddkbd.h:82
_In_ HBITMAP hbm
Definition: ntgdi.h:2776
__kernel_entry W32KAPI HBITMAP APIENTRY NtGdiCreateCompatibleBitmap(_In_ HDC hdc, _In_ INT cx, _In_ INT cy)
__kernel_entry W32KAPI HDC APIENTRY NtGdiCreateCompatibleDC(_In_opt_ HDC hdc)
__kernel_entry W32KAPI BOOL APIENTRY NtGdiBitBlt(_In_ HDC hdcDst, _In_ INT x, _In_ INT y, _In_ INT cx, _In_ INT cy, _In_opt_ HDC hdcSrc, _In_ INT xSrc, _In_ INT ySrc, _In_ DWORD rop4, _In_ DWORD crBackColor, _In_ FLONG fl)
__kernel_entry W32KAPI HBITMAP APIENTRY NtGdiSelectBitmap(_In_ HDC hdc, _In_ HBITMAP hbm)
NTSYSAPI NTSTATUS NTAPI ZwDeviceIoControlFile(IN HANDLE DeviceHandle, IN HANDLE Event OPTIONAL, IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, IN PVOID UserApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG IoControlCode, IN PVOID InputBuffer, IN ULONG InputBufferSize, OUT PVOID OutputBuffer, IN ULONG OutputBufferSize)
PVOID NTAPI PsGetCurrentThreadWin32Thread(VOID)
Definition: thread.c:805
LRESULT APIENTRY co_HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam)
Definition: hook.c:1102
PPROCESSINFO gppiInputProvider
Definition: ntuser.c:16
VOID FASTCALL UserLeave(VOID)
Definition: ntuser.c:258
VOID FASTCALL UserEnterShared(VOID)
Definition: ntuser.c:242
VOID FASTCALL UserEnterExclusive(VOID)
Definition: ntuser.c:249
struct _THREADINFO * PTHREADINFO
Definition: ntwin32.h:6
#define TAG_STRING
Definition: oslist.h:22
#define LOWORD(l)
Definition: pedump.c:82
#define CONST
Definition: pedump.c:81
BYTE * PBYTE
Definition: pedump.c:66
short SHORT
Definition: pedump.c:59
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:586
_Out_opt_ int * cx
Definition: commctrl.h:585
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:181
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:82
#define _SEH2_END
Definition: pseh2_64.h:171
#define _SEH2_TRY
Definition: pseh2_64.h:71
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:184
#define LANG_JAPANESE
Definition: nls.h:76
#define PRIMARYLANGID(l)
Definition: nls.h:16
_In_ UINT _In_ UINT cch
Definition: shellapi.h:432
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
static void Exit(void)
Definition: sock.c:1330
#define TRACE(s)
Definition: solgame.cpp:4
DWORD dwTime
Definition: solitaire.cpp:27
WCHAR wchComposed
Definition: kbd.h:58
DWORD dwBoth
Definition: kbd.h:57
USHORT IndicatorFlags
Definition: ntddkbd.h:115
USHORT MakeCode
Definition: ntddkbd.h:114
Definition: kbd.h:95
VSC_LPWSTR * pKeyNamesExt
Definition: kbd.h:100
PMODIFIERS pCharModifiers
Definition: kbd.h:96
BYTE bMaxVSCtoVK
Definition: kbd.h:103
PVK_TO_WCHAR_TABLE pVkToWcharTable
Definition: kbd.h:97
USHORT * pusVSCtoVK
Definition: kbd.h:102
DWORD fLocaleFlags
Definition: kbd.h:106
PVSC_VK pVSCtoVK_E0
Definition: kbd.h:104
PDEADKEY pDeadKey
Definition: kbd.h:98
VSC_LPWSTR * pKeyNames
Definition: kbd.h:99
PVSC_VK pVSCtoVK_E1
Definition: kbd.h:105
KEYBOARD_ID KeyboardIdentifier
Definition: ntddkbd.h:124
USHORT NumberOfFunctionKeys
Definition: ntddkbd.h:126
UCHAR Subtype
Definition: ntddkbd.h:102
UCHAR Type
Definition: ntddkbd.h:101
INDICATOR_LIST IndicatorList[1]
Definition: ntddkbd.h:120
ULONG ExtraInformation
Definition: ntddkbd.h:90
WORD wMaxModBits
Definition: kbd.h:28
BYTE ModNumber[]
Definition: kbd.h:29
PVK_TO_BIT pVkToBit
Definition: kbd.h:27
struct _CLIENTINFO * pClientInfo
Definition: win32.h:94
struct tagKL * KeyboardLayout
Definition: win32.h:90
struct _USER_MESSAGE_QUEUE * MessageQueue
Definition: win32.h:89
PTHREADINFO ptiKeyboard
Definition: msgqueue.h:56
BYTE ModBits
Definition: kbd.h:23
BYTE Vk
Definition: kbd.h:22
BYTE cbSize
Definition: kbd.h:53
PVK_TO_WCHARS1 pVkToWchars
Definition: kbd.h:51
BYTE nModifications
Definition: kbd.h:52
LPWSTR pwsz
Definition: kbd.h:68
USHORT Vk
Definition: kbd.h:73
BYTE Vsc
Definition: kbd.h:72
Definition: ntuser.h:694
THRDESKHEAD head
Definition: ntuser.h:695
RECT rcWindow
Definition: ntuser.h:716
struct _KBDTABLES * pKbdTbl
Definition: input.h:21
ULONG_PTR dwExtraInfo
Definition: winuser.h:3914
DWORD dwFlags
Definition: winable.h:49
WORD wVk
Definition: winable.h:47
WORD wScan
Definition: winable.h:48
ULONG_PTR dwExtraInfo
Definition: winable.h:51
DWORD time
Definition: winable.h:50
Definition: input.h:27
DWORD dwFontSigs
Definition: input.h:34
PKBDFILE spkf
Definition: input.h:33
HKL hkl
Definition: input.h:32
UINT message
Definition: winuser.h:3217
HWND hwnd
Definition: winuser.h:3216
WPARAM wParam
Definition: winuser.h:3218
LPARAM lParam
Definition: winuser.h:3219
LONG right
Definition: windef.h:108
LONG bottom
Definition: windef.h:109
LONG top
Definition: windef.h:107
LONG left
Definition: windef.h:106
BOOL fIncSerialNumber
Definition: ntuser.h:1169
BOOL fGlobalHandle
Definition: ntuser.h:1168
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1829
#define NTAPI
Definition: typedefs.h:36
ULONG_PTR SIZE_T
Definition: typedefs.h:80
int32_t INT
Definition: typedefs.h:58
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint16_t * PWCHAR
Definition: typedefs.h:56
uint32_t ULONG
Definition: typedefs.h:59
#define HIWORD(l)
Definition: typedefs.h:247
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define KL_UNLOAD
Definition: undocuser.h:183
PWND FASTCALL UserGetWindowObject(HWND hWnd)
Definition: window.c:124
INT FASTCALL UserReleaseDC(PWND Window, HDC hDc, BOOL EndPaint)
Definition: windc.c:918
HDC FASTCALL UserGetDCEx(PWND Window OPTIONAL, HANDLE ClipRegion, ULONG Flags)
_Must_inspect_result_ _In_ WDFUSBDEVICE _In_opt_ WDFREQUEST _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_writes_opt_ NumCharacters PUSHORT _Inout_ PUSHORT _In_ UCHAR _In_opt_ USHORT LangID
Definition: wdfusb.h:1083
HDC hdcMem
Definition: welcome.c:104
VOID FASTCALL SetLastNtError(_In_ NTSTATUS Status)
Definition: error.c:31
BOOL NTAPI GreDeleteObject(HGDIOBJ hobj)
Definition: gdiobj.c:1165
USHORT gusLanguageID
Definition: init.c:12
BOOL NTAPI UserEmptyClipboard(VOID)
Definition: clipboard.c:680
BOOL NTAPI UserCloseClipboard(VOID)
Definition: clipboard.c:545
BOOL NTAPI UserOpenClipboard(HWND hWnd)
Definition: clipboard.c:488
HANDLE NTAPI UserSetClipboardData(UINT fmt, HANDLE hData, PSETCLIPBDATA scd)
Definition: clipboard.c:1023
HWND FASTCALL IntGetDesktopWindow(VOID)
Definition: desktop.c:1391
PUSER_MESSAGE_QUEUE FASTCALL IntGetFocusMessageQueue(VOID)
Definition: desktop.c:1324
BOOL NTAPI co_UserProcessHotKeys(WORD wVk, BOOL bIsDown)
Definition: hotkey.c:191
HANDLE ghKeyboardDevice
Definition: input.c:19
#define SET_KEY_DOWN(ks, vk, down)
Definition: input.h:105
#define KS_DOWN_BIT
Definition: input.h:51
DWORD gSystemFS
Definition: kbdlayout.c:24
PKL NTAPI UserHklToKbl(HKL hKl)
Definition: kbdlayout.c:539
#define IS_KEY_DOWN(ks, vk)
Definition: input.h:103
#define SC_KEY_UP
Definition: input.h:54
#define LP_DO_NOT_CARE_BIT
Definition: input.h:56
#define KS_LOCK_BIT
Definition: input.h:52
#define IS_KEY_LOCKED(ks, vk)
Definition: input.h:104
#define SET_KEY_LOCKED(ks, vk, down)
Definition: input.h:108
PKL W32kGetDefaultKeyLayout(VOID)
Definition: kbdlayout.c:512
static KEYBOARD_INDICATOR_PARAMETERS gIndicators
Definition: keyboard.c:16
KEYBOARD_ATTRIBUTES gKeyboardInfo
Definition: keyboard.c:17
static ULONG gAltNumPadValue
Definition: keyboard.c:31
static DWORD IntGetModBits(PKBDTABLES pKbdTbl, PBYTE pKeyState)
Definition: keyboard.c:310
static enum _ALTNUM_STATE gAltNumPadState
BOOL FASTCALL IntTranslateKbdMessage(LPMSG lpMsg, UINT flags)
Definition: keyboard.c:1412
static NTSTATUS APIENTRY IntKeyboardUpdateLeds(HANDLE hKeyboardDevice, WORD wVk, WORD wScanCode)
Definition: keyboard.c:119
VOID NTAPI UserProcessKeyboardInput(PKEYBOARD_INPUT_DATA pKbdInputData)
Definition: keyboard.c:1327
DWORD APIENTRY NtUserVkKeyScanEx(WCHAR wch, HKL dwhkl, BOOL bUsehKL)
Definition: keyboard.c:1845
INT gLayoutToggleKeyState
Definition: keyboard.c:20
int APIENTRY NtUserToUnicodeEx(UINT wVirtKey, UINT wScanCode, PBYTE pKeyStateUnsafe, LPWSTR pwszBuffUnsafe, INT cchBuff, UINT wFlags, HKL dwhkl)
Definition: keyboard.c:1615
BYTE gafAsyncKeyState[256 *2/8]
Definition: keyboard.c:13
BOOL NTAPI UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected)
Definition: keyboard.c:1246
static WORD IntFixVk(WORD wVk, BOOL bExt)
Definition: keyboard.c:259
static VOID SnapWindow(HWND hWnd)
Definition: keyboard.c:735
static BOOL IntTranslateChar(WORD wVirtKey, PBYTE pKeyState, PBOOL pbDead, PBOOL pbLigature, PWCHAR pwcTranslatedChar, PKBDTABLES pKbdTbl)
Definition: keyboard.c:332
_ALTNUM_STATE
Definition: keyboard.c:25
@ ALTNUM_INACTIVE
Definition: keyboard.c:26
@ ALTNUM_OEM
Definition: keyboard.c:27
@ ALTNUM_ACP
Definition: keyboard.c:28
DWORD gdwLanguageToggleKey
Definition: keyboard.c:19
static int APIENTRY IntToUnicodeEx(UINT wVirtKey, UINT wScanCode, PBYTE pKeyState, LPWSTR pwszBuff, int cchBuff, UINT wFlags, PKBDTABLES pKbdTbl)
Definition: keyboard.c:444
static WCHAR FASTCALL IntVkToChar(WORD wVk, PKBDTABLES pKbdTbl)
Definition: keyboard.c:617
DWORD gdwLayoutToggleKey
Definition: keyboard.c:21
static BOOL IntCheckLanguageToggle(_In_ PUSER_MESSAGE_QUEUE pFocusQueue, _In_ BOOL bIsDown, _In_ WORD wVk, _Inout_ PINT pKeyState)
Definition: keyboard.c:866
DWORD APIENTRY NtUserGetKeyNameText(LONG lParam, LPWSTR lpString, int cchSize)
Definition: keyboard.c:1720
static LRESULT co_CallLowLevelKeyboardHook(WORD wVk, WORD wScanCode, DWORD dwFlags, BOOL bInjected, DWORD dwTime, DWORD dwExtraInfo)
Definition: keyboard.c:699
static PKL FASTCALL IntGetNextKL(_In_ PKL pKL, _In_ BOOL bNext, _In_ BOOL bSameLang)
Definition: keyboard.c:808
static PKEYBOARD_INDICATOR_TRANSLATION gpKeyboardIndicatorTrans
Definition: keyboard.c:15
static UINT IntMapVirtualKeyEx(UINT uCode, UINT Type, PKBDTABLES pKbdTbl)
Definition: keyboard.c:1529
VOID NTAPI UserInitKeyboard(HANDLE hKeyboardDevice)
Definition: keyboard.c:173
static BOOL IntHandleAltNumpad(_In_ WORD wVk, _In_ BOOL bIsDown, _In_ DWORD dwTime)
Handles Alt+Numpad character composition.
Definition: keyboard.c:911
NTSTATUS APIENTRY IntKeyboardGetIndicatorTrans(HANDLE hKeyboardDevice, PKEYBOARD_INDICATOR_TRANSLATION *ppIndicatorTrans)
Definition: keyboard.c:62
static BYTE gafAsyncKeyStateRecentDown[256/8]
Definition: keyboard.c:14
DWORD FASTCALL UserGetKeyboardType(DWORD dwTypeFlag)
Definition: keyboard.c:1820
static VOID NTAPI UpdateAsyncKeyState(WORD wVk, BOOL bIsDown)
Definition: keyboard.c:678
SHORT APIENTRY NtUserGetAsyncKeyState(INT Key)
Definition: keyboard.c:644
INT gLanguageToggleKeyState
Definition: keyboard.c:18
NTSTATUS NTAPI InitKeyboardImpl(VOID)
Definition: keyboard.c:43
BOOL NTAPI ProcessKeyEvent(WORD wVk, WORD wScanCode, DWORD dwFlags, BOOL bInjected, DWORD dwTime, DWORD dwExtraInfo)
Definition: keyboard.c:1020
static WORD FASTCALL IntVkToVsc(WORD wVk, PKBDTABLES pKbdTbl)
Definition: keyboard.c:537
static WORD FASTCALL IntVscToVk(WORD wScanCode, PKBDTABLES pKbdTbl)
Definition: keyboard.c:574
static VOID IntLanguageToggle(_In_ PUSER_MESSAGE_QUEUE pFocusQueue, _In_ BOOL bSameLang, _In_ INT nKeyState)
Definition: keyboard.c:829
static WORD IntSimplifyVk(WORD wVk)
Definition: keyboard.c:231
static WORD IntTranslateNumpadKey(WORD wVk)
Definition: keyboard.c:284
UINT APIENTRY NtUserMapVirtualKeyEx(UINT uCode, UINT uType, DWORD keyboardId, HKL dwhkl)
Definition: keyboard.c:1575
BOOL FASTCALL UserPostMessage(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
Definition: message.c:1395
PVOID FASTCALL UserAssignmentLock(PVOID *ppvObj, PVOID pvNew)
Definition: object.c:839
#define USERTAG_KBDTABLE
Definition: tags.h:247
WINBASEAPI _In_ DWORD _Out_ _In_ WORD wFlags
Definition: wincon_undoc.h:337
ENGAPI VOID APIENTRY EngSetLastError(_In_ ULONG iError)
Definition: error.c:22
#define CLR_INVALID
Definition: wingdi.h:883
#define SRCCOPY
Definition: wingdi.h:333
#define VK_CLEAR
Definition: winuser.h:2236
#define QS_KEY
Definition: winuser.h:885
#define VK_NUMPAD3
Definition: winuser.h:2278
#define VK_SNAPSHOT
Definition: winuser.h:2267
#define VK_TAB
Definition: winuser.h:2235
#define MAKELPARAM(l, h)
Definition: winuser.h:4110
#define WM_KEYUP
Definition: winuser.h:1744
#define LLKHF_EXTENDED
Definition: winuser.h:2687
#define DCX_WINDOW
Definition: winuser.h:2149
#define VK_NUMPAD1
Definition: winuser.h:2276
#define VK_F10
Definition: winuser.h:2300
#define VK_NUMPAD2
Definition: winuser.h:2277
#define VK_CAPITAL
Definition: winuser.h:2242
#define MAPVK_VSC_TO_VK_EX
Definition: winuser.h:2394
#define VK_NUMPAD4
Definition: winuser.h:2279
#define KF_ALTDOWN
Definition: winuser.h:2485
#define VK_SCROLL
Definition: winuser.h:2316
#define KF_EXTENDED
Definition: winuser.h:2482
#define VK_CONTROL
Definition: winuser.h:2239
#define HC_ACTION
Definition: winuser.h:48
#define VK_RSHIFT
Definition: winuser.h:2319
#define VK_UP
Definition: winuser.h:2261
#define VK_OEM_FINISH
Definition: winuser.h:2375
#define VK_LSHIFT
Definition: winuser.h:2318
#define VK_LCONTROL
Definition: winuser.h:2320
#define VK_NUMPAD0
Definition: winuser.h:2275
#define LLKHF_ALTDOWN
Definition: winuser.h:2689
#define VK_NUMPAD6
Definition: winuser.h:2281
#define MAPVK_VSC_TO_VK
Definition: winuser.h:2392
#define VK_NEXT
Definition: winuser.h:2257
#define VK_RCONTROL
Definition: winuser.h:2321
#define KF_UP
Definition: winuser.h:2487
#define KF_MENUMODE
Definition: winuser.h:2484
#define WM_SYSCHAR
Definition: winuser.h:1749
#define WM_SYSDEADCHAR
Definition: winuser.h:1750
#define VK_RMENU
Definition: winuser.h:2323
#define VK_NUMPAD9
Definition: winuser.h:2284
#define VK_OEM_ATTN
Definition: winuser.h:2374
#define VK_OEM_COPY
Definition: winuser.h:2376
#define VK_END
Definition: winuser.h:2258
#define VK_HOME
Definition: winuser.h:2259
#define LLKHF_UP
Definition: winuser.h:2690
#define WM_SYSKEYUP
Definition: winuser.h:1748
#define WH_KEYBOARD_LL
Definition: winuser.h:43
#define LLKHF_INJECTED
Definition: winuser.h:2688
#define WM_CHAR
Definition: winuser.h:1745
#define MAPVK_VK_TO_CHAR
Definition: winuser.h:2393
#define VK_NUMPAD5
Definition: winuser.h:2280
#define VK_LEFT
Definition: winuser.h:2260
#define KEYEVENTF_EXTENDEDKEY
Definition: winuser.h:1112
#define VK_NUMPAD7
Definition: winuser.h:2282
#define VK_RIGHT
Definition: winuser.h:2262
#define VK_DOWN
Definition: winuser.h:2263
#define VK_NUMLOCK
Definition: winuser.h:2315
#define KF_REPEAT
Definition: winuser.h:2486
#define VK_SHIFT
Definition: winuser.h:2238
#define VK_PRIOR
Definition: winuser.h:2256
#define VK_DELETE
Definition: winuser.h:2269
#define MAPVK_VK_TO_VSC
Definition: winuser.h:2391
#define WM_KEYDOWN
Definition: winuser.h:1743
#define VK_NUMPAD8
Definition: winuser.h:2283
#define MAPVK_VK_TO_VSC_EX
Definition: winuser.h:2395
#define VK_DECIMAL
Definition: winuser.h:2289
#define VK_ESCAPE
Definition: winuser.h:2250
#define WM_DEADCHAR
Definition: winuser.h:1746
#define KEYEVENTF_KEYUP
Definition: winuser.h:1113
#define WM_SYSKEYDOWN
Definition: winuser.h:1747
#define VK_INSERT
Definition: winuser.h:2268
#define KF_DLGMODE
Definition: winuser.h:2483
#define VK_LMENU
Definition: winuser.h:2322
#define VK_MENU
Definition: winuser.h:2240
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
char CHAR
Definition: xmlstorage.h:175
unsigned char BYTE
Definition: xxhash.c:193