a0a59beaa24c997de12ac73bdc2e2eb631332098
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / keyboard.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Keyboard functions
5 * FILE: subsys/win32k/ntuser/keyboard.c
6 * PROGRAMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Rafal Harabien (rafalh@reactos.org)
8 */
9
10 #include <win32k.h>
11 DBG_DEFAULT_CHANNEL(UserKbd);
12
13 BYTE gKeyStateTable[0x100];
14 static PKEYBOARD_INDICATOR_TRANSLATION gpKeyboardIndicatorTrans = NULL;
15
16 /* FUNCTIONS *****************************************************************/
17
18 /*
19 * InitKeyboardImpl
20 *
21 * Initialization -- Right now, just zero the key state
22 */
23 INIT_FUNCTION
24 NTSTATUS
25 NTAPI
26 InitKeyboardImpl(VOID)
27 {
28 RtlZeroMemory(&gKeyStateTable, sizeof(gKeyStateTable));
29 return STATUS_SUCCESS;
30 }
31
32 /*
33 * IntKeyboardGetIndicatorTrans
34 *
35 * Asks the keyboard driver to send a small table that shows which
36 * lights should connect with which scancodes
37 */
38 static
39 NTSTATUS APIENTRY
40 IntKeyboardGetIndicatorTrans(HANDLE hKeyboardDevice,
41 PKEYBOARD_INDICATOR_TRANSLATION *ppIndicatorTrans)
42 {
43 NTSTATUS Status;
44 DWORD dwSize = 0;
45 IO_STATUS_BLOCK Block;
46 PKEYBOARD_INDICATOR_TRANSLATION pRet;
47
48 dwSize = sizeof(KEYBOARD_INDICATOR_TRANSLATION);
49
50 pRet = ExAllocatePoolWithTag(PagedPool,
51 dwSize,
52 USERTAG_KBDTABLE);
53
54 while (pRet)
55 {
56 Status = NtDeviceIoControlFile(hKeyboardDevice,
57 NULL,
58 NULL,
59 NULL,
60 &Block,
61 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION,
62 NULL, 0,
63 pRet, dwSize);
64
65 if (Status != STATUS_BUFFER_TOO_SMALL)
66 break;
67
68 ExFreePoolWithTag(pRet, USERTAG_KBDTABLE);
69
70 dwSize += sizeof(KEYBOARD_INDICATOR_TRANSLATION);
71
72 pRet = ExAllocatePoolWithTag(PagedPool,
73 dwSize,
74 USERTAG_KBDTABLE);
75 }
76
77 if (!pRet)
78 return STATUS_INSUFFICIENT_RESOURCES;
79
80 if (!NT_SUCCESS(Status))
81 {
82 ExFreePoolWithTag(pRet, USERTAG_KBDTABLE);
83 return Status;
84 }
85
86 *ppIndicatorTrans = pRet;
87 return Status;
88 }
89
90 /*
91 * IntKeyboardUpdateLeds
92 *
93 * Sends the keyboard commands to turn on/off the lights
94 */
95 static
96 NTSTATUS APIENTRY
97 IntKeyboardUpdateLeds(HANDLE hKeyboardDevice,
98 WORD wScanCode,
99 BOOL bEnabled,
100 PKEYBOARD_INDICATOR_TRANSLATION pIndicatorTrans)
101 {
102 NTSTATUS Status;
103 UINT i;
104 static KEYBOARD_INDICATOR_PARAMETERS Indicators;
105 IO_STATUS_BLOCK Block;
106
107 if (!pIndicatorTrans)
108 return STATUS_NOT_SUPPORTED;
109
110 for (i = 0; i < pIndicatorTrans->NumberOfIndicatorKeys; i++)
111 {
112 if (pIndicatorTrans->IndicatorList[i].MakeCode == wScanCode)
113 {
114 if (bEnabled)
115 Indicators.LedFlags |= pIndicatorTrans->IndicatorList[i].IndicatorFlags;
116 else
117 Indicators.LedFlags = ~pIndicatorTrans->IndicatorList[i].IndicatorFlags;
118
119 /* Update the lights on the hardware */
120 Status = NtDeviceIoControlFile(hKeyboardDevice,
121 NULL,
122 NULL,
123 NULL,
124 &Block,
125 IOCTL_KEYBOARD_SET_INDICATORS,
126 &Indicators, sizeof(Indicators),
127 NULL, 0);
128
129 return Status;
130 }
131 }
132
133 return STATUS_SUCCESS;
134 }
135
136 /*
137 * IntSimplifyVk
138 *
139 * Changes virtual keys which distinguish between left and right hand, to keys which don't distinguish
140 */
141 static
142 WORD
143 IntSimplifyVk(WORD wVk)
144 {
145 switch (wVk)
146 {
147 case VK_LSHIFT:
148 case VK_RSHIFT:
149 return VK_SHIFT;
150
151 case VK_LCONTROL:
152 case VK_RCONTROL:
153 return VK_CONTROL;
154
155 case VK_LMENU:
156 case VK_RMENU:
157 return VK_MENU;
158
159 default:
160 return wVk;
161 }
162 }
163
164 /*
165 * IntFixVk
166 *
167 * Changes virtual keys which don't not distinguish between left and right hand to proper keys
168 */
169 static
170 WORD
171 IntFixVk(WORD wVk, BOOL bExt)
172 {
173 switch (wVk)
174 {
175 case VK_SHIFT:
176 return bExt ? VK_RSHIFT : VK_LSHIFT;
177
178 case VK_CONTROL:
179 return bExt ? VK_RCONTROL : VK_LCONTROL;
180
181 case VK_MENU:
182 return bExt ? VK_RMENU : VK_LMENU;
183
184 default:
185 return wVk;
186 }
187 }
188
189 /*
190 * IntGetVkOtherSide
191 *
192 * Gets other side of vk: right -> left, left -> right
193 */
194 static
195 WORD
196 IntGetVkOtherSide(WORD wVk)
197 {
198 switch (wVk)
199 {
200 case VK_LSHIFT: return VK_RSHIFT;
201 case VK_RSHIFT: return VK_LSHIFT;
202
203 case VK_LCONTROL: return VK_RCONTROL;
204 case VK_RCONTROL: return VK_LCONTROL;
205
206 case VK_LMENU: return VK_RMENU;
207 case VK_RMENU: return VK_LMENU;
208
209 default: return wVk;
210 }
211 }
212
213 /*
214 * IntTranslateNumpadKey
215 *
216 * Translates numpad keys when numlock is enabled
217 */
218 static
219 WORD
220 IntTranslateNumpadKey(WORD wVk)
221 {
222 switch (wVk)
223 {
224 case VK_INSERT: return VK_NUMPAD0;
225 case VK_END: return VK_NUMPAD1;
226 case VK_DOWN: return VK_NUMPAD2;
227 case VK_NEXT: return VK_NUMPAD3;
228 case VK_LEFT: return VK_NUMPAD4;
229 case VK_CLEAR: return VK_NUMPAD5;
230 case VK_RIGHT: return VK_NUMPAD6;
231 case VK_HOME: return VK_NUMPAD7;
232 case VK_UP: return VK_NUMPAD8;
233 case VK_PRIOR: return VK_NUMPAD9;
234 case VK_DELETE: return VK_DECIMAL;
235 default: return wVk;
236 }
237 }
238
239 /*
240 * IntGetModifiers
241 *
242 * Returns a value that indicates if the key is a modifier key, and
243 * which one.
244 */
245 static
246 UINT FASTCALL
247 IntGetModifiers(PBYTE pKeyState)
248 {
249 UINT fModifiers = 0;
250
251 if (pKeyState[VK_SHIFT] & KS_DOWN_BIT)
252 fModifiers |= MOD_SHIFT;
253
254 if (pKeyState[VK_CONTROL] & KS_DOWN_BIT)
255 fModifiers |= MOD_CONTROL;
256
257 if (pKeyState[VK_MENU] & KS_DOWN_BIT)
258 fModifiers |= MOD_ALT;
259
260 if ((pKeyState[VK_LWIN] | pKeyState[VK_RWIN]) & KS_DOWN_BIT)
261 fModifiers |= MOD_WIN;
262
263 return fModifiers;
264 }
265
266 /*
267 * IntGetShiftBit
268 *
269 * Search the keyboard layout modifiers table for the shift bit
270 */
271 static
272 DWORD FASTCALL
273 IntGetShiftBit(PKBDTABLES pKbdTbl, WORD wVk)
274 {
275 unsigned i;
276
277 for (i = 0; pKbdTbl->pCharModifiers->pVkToBit[i].Vk; i++)
278 if (pKbdTbl->pCharModifiers->pVkToBit[i].Vk == wVk)
279 return pKbdTbl->pCharModifiers->pVkToBit[i].ModBits;
280
281 return 0;
282 }
283
284 /*
285 * IntGetModBits
286 *
287 * Gets layout specific modification bits, for example KBDSHIFT, KBDCTRL, KBDALT
288 */
289 static
290 DWORD
291 IntGetModBits(PKBDTABLES pKbdTbl, PBYTE pKeyState)
292 {
293 DWORD i, dwModBits = 0;
294
295 /* DumpKeyState( KeyState ); */
296
297 for (i = 0; pKbdTbl->pCharModifiers->pVkToBit[i].Vk; i++)
298 if (pKeyState[pKbdTbl->pCharModifiers->pVkToBit[i].Vk] & KS_DOWN_BIT)
299 dwModBits |= pKbdTbl->pCharModifiers->pVkToBit[i].ModBits;
300
301 /* Handle Alt+Gr */
302 if ((pKbdTbl->fLocaleFlags & KLLF_ALTGR) && (pKeyState[VK_RMENU] & KS_DOWN_BIT))
303 dwModBits |= IntGetShiftBit(pKbdTbl, VK_CONTROL); /* Don't use KBDCTRL here */
304
305 TRACE("Current Mod Bits: %lx\n", dwModBits);
306
307 return dwModBits;
308 }
309
310 /*
311 * IntTranslateChar
312 *
313 * Translates virtual key to character
314 */
315 static
316 BOOL
317 IntTranslateChar(WORD wVirtKey,
318 PBYTE pKeyState,
319 PBOOL pbDead,
320 PBOOL pbLigature,
321 PWCHAR pwcTranslatedChar,
322 PKBDTABLES pKbdTbl)
323 {
324 PVK_TO_WCHAR_TABLE pVkToVchTbl;
325 PVK_TO_WCHARS10 pVkToVch;
326 DWORD i, dwModBits, dwVkModBits, dwModNumber = 0;
327 WCHAR wch;
328 BOOL bAltGr;
329 WORD wCaplokAttr;
330
331 dwModBits = pKeyState ? IntGetModBits(pKbdTbl, pKeyState) : 0;
332 bAltGr = pKeyState && (pKbdTbl->fLocaleFlags & KLLF_ALTGR) && (pKeyState[VK_RMENU] & KS_DOWN_BIT);
333 wCaplokAttr = bAltGr ? CAPLOKALTGR : CAPLOK;
334
335 TRACE("TryToTranslate: %04x %x\n", wVirtKey, dwModBits);
336
337 if (dwModBits > pKbdTbl->pCharModifiers->wMaxModBits)
338 {
339 TRACE("dwModBits %x > wMaxModBits %x\n", dwModBits, pKbdTbl->pCharModifiers->wMaxModBits);
340 return FALSE;
341 }
342
343 for (i = 0; pKbdTbl->pVkToWcharTable[i].pVkToWchars; i++)
344 {
345 pVkToVchTbl = &pKbdTbl->pVkToWcharTable[i];
346 pVkToVch = (PVK_TO_WCHARS10)(pVkToVchTbl->pVkToWchars);
347 while (pVkToVch->VirtualKey)
348 {
349 if (wVirtKey == (pVkToVch->VirtualKey & 0xFF))
350 {
351 dwVkModBits = dwModBits;
352
353 /* If CapsLock is enabled for this key and locked, add SHIFT bit */
354 if ((pVkToVch->Attributes & wCaplokAttr) &&
355 pKeyState &&
356 (pKeyState[VK_CAPITAL] & KS_LOCK_BIT))
357 {
358 /* Note: we use special value here instead of getting VK_SHIFT mod bit - it's verified */
359 dwVkModBits ^= KBDSHIFT;
360 }
361
362 /* If ALT without CTRL has ben used, remove ALT flag */
363 if ((dwVkModBits & (KBDALT|KBDCTRL)) == KBDALT)
364 dwVkModBits &= ~KBDALT;
365
366 if (dwVkModBits > pKbdTbl->pCharModifiers->wMaxModBits)
367 break;
368
369 /* Get modification number */
370 dwModNumber = pKbdTbl->pCharModifiers->ModNumber[dwVkModBits];
371 if (dwModNumber >= pVkToVchTbl->nModifications)
372 {
373 TRACE("dwModNumber %u >= nModifications %u\n", dwModNumber, pVkToVchTbl->nModifications);
374 break;
375 }
376
377 /* Read character */
378 wch = pVkToVch->wch[dwModNumber];
379 if (wch == WCH_NONE)
380 break;
381
382 *pbDead = (wch == WCH_DEAD);
383 *pbLigature = (wch == WCH_LGTR);
384 *pwcTranslatedChar = wch;
385
386 TRACE("%d %04x: dwModNumber %08x Char %04x\n",
387 i, wVirtKey, dwModNumber, wch);
388
389 if (*pbDead)
390 {
391 /* After WCH_DEAD, real character is located */
392 pVkToVch = (PVK_TO_WCHARS10)(((BYTE *)pVkToVch) + pVkToVchTbl->cbSize);
393 if (pVkToVch->VirtualKey != 0xFF)
394 {
395 WARN("Found dead key with no trailer in the table.\n");
396 WARN("VK: %04x, ADDR: %p\n", wVirtKey, pVkToVch);
397 break;
398 }
399 *pwcTranslatedChar = pVkToVch->wch[dwModNumber];
400 }
401 return TRUE;
402 }
403 pVkToVch = (PVK_TO_WCHARS10)(((BYTE *)pVkToVch) + pVkToVchTbl->cbSize);
404 }
405 }
406
407 /* If nothing has been found in layout, check if this is ASCII control character.
408 Note: we could add it to layout table, but windows does not have it there */
409 if (wVirtKey >= 'A' && wVirtKey <= 'Z' &&
410 (pKeyState[VK_CONTROL] & KS_DOWN_BIT) &&
411 !(pKeyState[VK_MENU] & KS_DOWN_BIT))
412 {
413 *pwcTranslatedChar = (wVirtKey - 'A') + 1; /* ASCII control character */
414 *pbDead = FALSE;
415 *pbLigature = FALSE;
416 return TRUE;
417 }
418
419 return FALSE;
420 }
421
422 /*
423 * IntToUnicodeEx
424 *
425 * Translates virtual key to characters
426 */
427 static
428 int APIENTRY
429 IntToUnicodeEx(UINT wVirtKey,
430 UINT wScanCode,
431 PBYTE pKeyState,
432 LPWSTR pwszBuff,
433 int cchBuff,
434 UINT wFlags,
435 PKBDTABLES pKbdTbl)
436 {
437 WCHAR wchTranslatedChar;
438 BOOL bDead, bLigature;
439 static WCHAR wchDead = 0;
440 int iRet = 0;
441
442 ASSERT(pKbdTbl);
443
444 if (!IntTranslateChar(wVirtKey,
445 pKeyState,
446 &bDead,
447 &bLigature,
448 &wchTranslatedChar,
449 pKbdTbl))
450 {
451 return 0;
452 }
453
454 if (bLigature)
455 {
456 WARN("Not handling ligature (yet)\n" );
457 return 0;
458 }
459
460 /* If we got dead char in previous call check dead keys in keyboard layout */
461 if (wchDead)
462 {
463 UINT i;
464 WCHAR wchFirst, wchSecond;
465 TRACE("Previous dead char: %lc (%x)\n", wchDead, wchDead);
466
467 for (i = 0; pKbdTbl->pDeadKey[i].dwBoth; i++)
468 {
469 wchFirst = pKbdTbl->pDeadKey[i].dwBoth >> 16;
470 wchSecond = pKbdTbl->pDeadKey[i].dwBoth & 0xFFFF;
471 if (wchFirst == wchDead && wchSecond == wchTranslatedChar)
472 {
473 wchTranslatedChar = pKbdTbl->pDeadKey[i].wchComposed;
474 wchDead = 0;
475 bDead = FALSE;
476 break;
477 }
478 }
479
480 TRACE("Final char: %lc (%x)\n", wchTranslatedChar, wchTranslatedChar);
481 }
482
483 /* dead char has not been not found */
484 if (wchDead)
485 {
486 /* Treat both characters normally */
487 if (cchBuff > iRet)
488 pwszBuff[iRet++] = wchDead;
489 bDead = FALSE;
490 }
491
492 /* add character to the buffer */
493 if (cchBuff > iRet)
494 pwszBuff[iRet++] = wchTranslatedChar;
495
496 /* Save dead character */
497 wchDead = bDead ? wchTranslatedChar : 0;
498
499 return bDead ? -iRet : iRet;
500 }
501
502 /*
503 * IntVkToVsc
504 *
505 * Translates virtual key to scan code
506 */
507 static
508 WORD FASTCALL
509 IntVkToVsc(WORD wVk, PKBDTABLES pKbdTbl)
510 {
511 unsigned i;
512
513 ASSERT(pKbdTbl);
514
515 /* Check standard keys first */
516 for (i = 0; i < pKbdTbl->bMaxVSCtoVK; i++)
517 {
518 if ((pKbdTbl->pusVSCtoVK[i] & 0xFF) == wVk)
519 return i;
520 }
521
522 /* Check extended keys now */
523 for (i = 0; pKbdTbl->pVSCtoVK_E0[i].Vsc; i++)
524 {
525 if ((pKbdTbl->pVSCtoVK_E0[i].Vk & 0xFF) == wVk)
526 return 0xE000 | pKbdTbl->pVSCtoVK_E0[i].Vsc;
527 }
528
529 for (i = 0; pKbdTbl->pVSCtoVK_E1[i].Vsc; i++)
530 {
531 if ((pKbdTbl->pVSCtoVK_E1[i].Vk & 0xFF) == wVk)
532 return 0xE100 | pKbdTbl->pVSCtoVK_E1[i].Vsc;
533 }
534
535 /* Virtual key has not been found */
536 return 0;
537 }
538
539 /*
540 * IntVscToVk
541 *
542 * Translates prefixed scancode to virtual key
543 */
544 static
545 WORD FASTCALL
546 IntVscToVk(WORD wScanCode, PKBDTABLES pKbdTbl)
547 {
548 unsigned i;
549 WORD wVk = 0;
550
551 ASSERT(pKbdTbl);
552
553 if ((wScanCode & 0xFF00) == 0xE000)
554 {
555 for (i = 0; pKbdTbl->pVSCtoVK_E0[i].Vsc; i++)
556 {
557 if (pKbdTbl->pVSCtoVK_E0[i].Vsc == (wScanCode & 0xFF))
558 {
559 wVk = pKbdTbl->pVSCtoVK_E0[i].Vk;
560 }
561 }
562 }
563 else if ((wScanCode & 0xFF00) == 0xE100)
564 {
565 for (i = 0; pKbdTbl->pVSCtoVK_E1[i].Vsc; i++)
566 {
567 if (pKbdTbl->pVSCtoVK_E1[i].Vsc == (wScanCode & 0xFF))
568 {
569 wVk = pKbdTbl->pVSCtoVK_E1[i].Vk;
570 }
571 }
572 }
573 else if (wScanCode < pKbdTbl->bMaxVSCtoVK)
574 {
575 wVk = pKbdTbl->pusVSCtoVK[wScanCode];
576 }
577
578 /* 0xFF nad 0x00 are invalid VKs */
579 return wVk != 0xFF ? wVk : 0;
580 }
581
582 /*
583 * IntVkToChar
584 *
585 * Translates virtual key to character, ignoring shift state
586 */
587 static
588 WCHAR FASTCALL
589 IntVkToChar(WORD wVk, PKBDTABLES pKbdTbl)
590 {
591 WCHAR wch;
592 BOOL bDead, bLigature;
593
594 ASSERT(pKbdTbl);
595
596 if (IntTranslateChar(wVk,
597 NULL,
598 &bDead,
599 &bLigature,
600 &wch,
601 pKbdTbl))
602 {
603 return wch;
604 }
605
606 return 0;
607 }
608
609 #if 0
610 static
611 VOID
612 DumpKeyState(PBYTE pKeyState)
613 {
614 unsigned i;
615
616 DbgPrint("KeyState { ");
617 for (i = 0; i < 0x100; i++)
618 {
619 if (pKeyState[i])
620 DbgPrint("%02x(%02x) ", i, pKeyState[i]);
621 }
622 DbgPrint("};\n");
623 }
624 #endif
625
626 /*
627 * IntGetAsyncKeyState
628 *
629 * Gets key state from global table
630 */
631 static
632 WORD FASTCALL
633 IntGetAsyncKeyState(DWORD dwKey)
634 {
635 WORD dwRet = 0;
636
637 if (dwKey < 0x100)
638 {
639 if (gKeyStateTable[dwKey] & KS_DOWN_BIT)
640 dwRet |= 0xFFFF8000; // If down, windows returns 0xFFFF8000.
641 if (gKeyStateTable[dwKey] & KS_LOCK_BIT)
642 dwRet |= 0x1;
643 }
644 else
645 {
646 EngSetLastError(ERROR_INVALID_PARAMETER);
647 }
648 return dwRet;
649 }
650
651 SHORT
652 APIENTRY
653 NtUserGetAsyncKeyState(INT Key)
654 {
655 DECLARE_RETURN(SHORT);
656
657 TRACE("Enter NtUserGetAsyncKeyState\n");
658 UserEnterExclusive();
659
660 RETURN(IntGetAsyncKeyState(Key));
661
662 CLEANUP:
663 TRACE("Leave NtUserGetAsyncKeyState, ret=%i\n", _ret_);
664 UserLeave();
665 END_CLEANUP;
666 }
667
668 /*
669 * IntKeyboardSendWinKeyMsg
670 *
671 * Sends syscommand to shell, when WIN key is pressed
672 */
673 static
674 VOID NTAPI
675 IntKeyboardSendWinKeyMsg()
676 {
677 PWND pWnd;
678 MSG Msg;
679
680 if (!(pWnd = UserGetWindowObject(InputWindowStation->ShellWindow)))
681 {
682 ERR("Couldn't find window to send Windows key message!\n");
683 return;
684 }
685
686 Msg.hwnd = InputWindowStation->ShellWindow;
687 Msg.message = WM_SYSCOMMAND;
688 Msg.wParam = SC_TASKLIST;
689 Msg.lParam = 0;
690
691 /* The QS_HOTKEY is just a guess */
692 MsqPostMessage(pWnd->head.pti->MessageQueue, &Msg, FALSE, QS_HOTKEY);
693 }
694
695 /*
696 * co_IntKeyboardSendAltKeyMsg
697 *
698 * Sends syscommand enabling window menu
699 */
700 static
701 VOID NTAPI
702 co_IntKeyboardSendAltKeyMsg()
703 {
704 FIXME("co_IntKeyboardSendAltKeyMsg\n");
705 //co_MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0); // This sends everything into a msg loop!
706 }
707
708 /*
709 * UserSendKeyboardInput
710 *
711 * Process keyboard input from input devices and SendInput API
712 */
713 BOOL NTAPI
714 UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected)
715 {
716 WORD wScanCode, wVk, wSimpleVk, wVkOtherSide, wSysKey;
717 PKBL pKbl = NULL;
718 PKBDTABLES pKbdTbl;
719 PUSER_MESSAGE_QUEUE pFocusQueue;
720 struct _ETHREAD *pFocusThread;
721 UINT fModifiers;
722 BYTE PrevKeyState = 0;
723 HWND hWnd;
724 int HotkeyId;
725 struct _ETHREAD *Thread;
726 LARGE_INTEGER LargeTickCount;
727 BOOL bExt = pKbdInput->dwFlags & KEYEVENTF_EXTENDEDKEY;
728 BOOL bKeyUp = pKbdInput->dwFlags & KEYEVENTF_KEYUP;
729
730 /* Find the target thread whose locale is in effect */
731 pFocusQueue = IntGetFocusMessageQueue();
732
733 if (pFocusQueue)
734 {
735 pFocusThread = pFocusQueue->Thread;
736 if (pFocusThread && pFocusThread->Tcb.Win32Thread)
737 pKbl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout;
738 }
739
740 if (!pKbl)
741 pKbl = W32kGetDefaultKeyLayout();
742 if (!pKbl)
743 {
744 ERR("No keyboard layout!\n");
745 return FALSE;
746 }
747
748 pKbdTbl = pKbl->KBTables;
749
750 /* Note: wScan field is always used */
751 wScanCode = pKbdInput->wScan & 0x7F;
752
753 if (pKbdInput->dwFlags & KEYEVENTF_UNICODE)
754 {
755 /* Generate WM_KEYDOWN msg with wParam == VK_PACKET and
756 high order word of lParam == pKbdInput->wScan */
757 wVk = VK_PACKET;
758 }
759 else
760 {
761 if (bExt)
762 wScanCode |= 0xE000;
763
764 if (pKbdInput->dwFlags & KEYEVENTF_SCANCODE)
765 {
766 /* Don't ignore invalid scan codes */
767 wVk = IntVscToVk(wScanCode, pKbdTbl);
768 if (!wVk) /* use 0xFF if vsc is invalid */
769 wVk = 0xFF;
770 }
771 else
772 {
773 wVk = pKbdInput->wVk & 0xFF;
774
775 /* LSHIFT + EXT = RSHIFT */
776 wVk = IntSimplifyVk(wVk);
777 wVk = IntFixVk(wVk, bExt);
778 }
779 }
780
781 if (!(pKbdInput->dwFlags & KEYEVENTF_UNICODE))
782 {
783 /* Get virtual key without shifts (VK_(L|R)* -> VK_*) */
784 wSimpleVk = IntSimplifyVk(wVk);
785 wVkOtherSide = IntGetVkOtherSide(wVk);
786 PrevKeyState = gKeyStateTable[wSimpleVk];
787
788 /* Update global keyboard state. Begin from lock bit */
789 if (!bKeyUp && !(PrevKeyState & KS_DOWN_BIT))
790 gKeyStateTable[wVk] ^= KS_LOCK_BIT;
791
792 /* Update down bit */
793 if (bKeyUp)
794 gKeyStateTable[wVk] &= ~KS_DOWN_BIT;
795 else
796 gKeyStateTable[wVk] |= KS_DOWN_BIT;
797
798 /* Update key without shifts */
799 gKeyStateTable[wSimpleVk] = gKeyStateTable[wVk] | gKeyStateTable[wVkOtherSide];
800
801 if (!bKeyUp)
802 {
803 /* Update keyboard LEDs */
804 if (!gpKeyboardIndicatorTrans)
805 IntKeyboardGetIndicatorTrans(ghKeyboardDevice, &gpKeyboardIndicatorTrans);
806 if (gpKeyboardIndicatorTrans)
807 IntKeyboardUpdateLeds(ghKeyboardDevice,
808 wScanCode,
809 gKeyStateTable[wSimpleVk] & KS_LOCK_BIT,
810 gpKeyboardIndicatorTrans);
811 }
812
813 /* Truncate scan code */
814 wScanCode &= 0x7F;
815
816 /* Support VK_*WIN and VK_*MENU keys */
817 if (bKeyUp)
818 {
819 if (wVk == VK_LWIN || wVk == VK_RWIN)
820 IntKeyboardSendWinKeyMsg();
821 else if(wSimpleVk == VK_MENU && !(gKeyStateTable[VK_CONTROL] & KS_DOWN_BIT))
822 co_IntKeyboardSendAltKeyMsg();
823 }
824
825 /* Check if it is a hotkey */
826 fModifiers = IntGetModifiers(gKeyStateTable);
827 if (GetHotKey(fModifiers, wSimpleVk, &Thread, &hWnd, &HotkeyId))
828 {
829 if (!bKeyUp)
830 {
831 TRACE("Hot key pressed (hWnd %lx, id %d)\n", hWnd, HotkeyId);
832 MsqPostHotKeyMessage(Thread,
833 hWnd,
834 (WPARAM)HotkeyId,
835 MAKELPARAM((WORD)fModifiers, wSimpleVk));
836 }
837
838 return TRUE; /* Don't send any message */
839 }
840 }
841
842 /* If we have a focus queue, post a keyboard message */
843 if (pFocusQueue)
844 {
845 MSG Msg;
846
847 /* If it is F10 or ALT is down and CTRL is up, it's a system key */
848 wSysKey = (pKbdTbl->fLocaleFlags & KLLF_ALTGR) ? VK_LMENU : VK_MENU;
849 if (wVk == VK_F10 ||
850 //uVkNoShift == VK_MENU || // FIXME: If only LALT is pressed WM_SYSKEYUP is generated instead of WM_KEYUP
851 ((gKeyStateTable[wSysKey] & KS_DOWN_BIT) && // FIXME
852 !(gKeyStateTable[VK_CONTROL] & KS_DOWN_BIT)))
853 {
854 if (bKeyUp)
855 Msg.message = WM_SYSKEYUP;
856 else
857 Msg.message = WM_SYSKEYDOWN;
858 }
859 else
860 {
861 if (bKeyUp)
862 Msg.message = WM_KEYUP;
863 else
864 Msg.message = WM_KEYDOWN;
865 }
866 Msg.hwnd = pFocusQueue->FocusWindow;
867 Msg.lParam = MAKELPARAM(1, wScanCode);
868 /* If it is VK_PACKET, high word of wParam is used for wchar */
869 if (!(pKbdInput->dwFlags & KEYEVENTF_UNICODE))
870 {
871 if (bExt)
872 Msg.lParam |= LP_EXT_BIT;
873 if (gKeyStateTable[VK_MENU] & KS_DOWN_BIT)
874 Msg.lParam |= LP_CONTEXT_BIT;
875 if (PrevKeyState & KS_DOWN_BIT)
876 Msg.lParam |= LP_PREV_STATE_BIT;
877 if (bKeyUp)
878 Msg.lParam |= LP_TRANSITION_BIT;
879 }
880
881 Msg.wParam = wVk; // its "simplified" later
882 Msg.pt = gpsi->ptCursor;
883 if (pKbdInput->time)
884 Msg.time = pKbdInput->time;
885 else
886 {
887 KeQueryTickCount(&LargeTickCount);
888 Msg.time = MsqCalculateMessageTime(&LargeTickCount);
889 }
890
891 /* Post a keyboard message */
892 TRACE("Posting keyboard msg %u wParam 0x%x lParam 0x%x\n", Msg.message, Msg.wParam, Msg.lParam);
893 co_MsqPostKeyboardMessage(Msg.message, Msg.wParam, Msg.lParam, bInjected);
894 }
895
896 return TRUE;
897 }
898
899 /*
900 * UserProcessKeyboardInput
901 *
902 * Process raw keyboard input data
903 */
904 VOID NTAPI
905 UserProcessKeyboardInput(
906 PKEYBOARD_INPUT_DATA pKbdInputData)
907 {
908 WORD wScanCode, wVk;
909 PKBL pKbl = NULL;
910 PKBDTABLES pKbdTbl;
911 PUSER_MESSAGE_QUEUE pFocusQueue;
912 struct _ETHREAD *pFocusThread;
913
914 /* Calculate scan code with prefix */
915 wScanCode = pKbdInputData->MakeCode & 0x7F;
916 if (pKbdInputData->Flags & KEY_E0)
917 wScanCode |= 0xE000;
918 if (pKbdInputData->Flags & KEY_E1)
919 wScanCode |= 0xE100;
920
921 /* Find the target thread whose locale is in effect */
922 pFocusQueue = IntGetFocusMessageQueue();
923
924 if (pFocusQueue)
925 {
926 pFocusThread = pFocusQueue->Thread;
927 if (pFocusThread && pFocusThread->Tcb.Win32Thread)
928 pKbl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout;
929 }
930
931 if (!pKbl)
932 pKbl = W32kGetDefaultKeyLayout();
933 if (!pKbl)
934 return;
935
936 pKbdTbl = pKbl->KBTables;
937
938 /* Convert scan code to virtual key.
939 Note: we could call UserSendKeyboardInput using scan code,
940 but it wouldn't interpret E1 key(s) properly */
941 wVk = IntVscToVk(wScanCode, pKbdTbl);
942 TRACE("UserProcessKeyboardInput: %x (break: %u) -> %x\n",
943 wScanCode, (pKbdInputData->Flags & KEY_BREAK) ? 1 : 0, wVk);
944
945 if (wVk)
946 {
947 KEYBDINPUT KbdInput;
948
949 /* Support numlock */
950 if ((wVk & KBDNUMPAD) && (gKeyStateTable[VK_NUMLOCK] & KS_LOCK_BIT))
951 {
952 wVk = IntTranslateNumpadKey(wVk & 0xFF);
953 }
954
955 /* Send keyboard input */
956 KbdInput.wVk = wVk & 0xFF;
957 KbdInput.wScan = wScanCode & 0x7F;
958 KbdInput.dwFlags = 0;
959 if (pKbdInputData->Flags & KEY_BREAK)
960 KbdInput.dwFlags |= KEYEVENTF_KEYUP;
961 if (wVk & KBDEXT)
962 KbdInput.dwFlags |= KEYEVENTF_EXTENDEDKEY;
963 KbdInput.time = 0;
964 KbdInput.dwExtraInfo = pKbdInputData->ExtraInformation;
965 UserSendKeyboardInput(&KbdInput, FALSE);
966
967 /* E1 keys don't have break code */
968 if (pKbdInputData->Flags & KEY_E1)
969 {
970 /* Send key up event */
971 KbdInput.dwFlags |= KEYEVENTF_KEYUP;
972 UserSendKeyboardInput(&KbdInput, FALSE);
973 }
974 }
975 }
976
977 /*
978 * IntTranslateKbdMessage
979 *
980 * Addes WM_(SYS)CHAR messages to message queue if message
981 * describes key which produce character.
982 */
983 BOOL FASTCALL
984 IntTranslateKbdMessage(LPMSG lpMsg,
985 UINT flags)
986 {
987 PTHREADINFO pti;
988 INT cch = 0, i;
989 WCHAR wch[3] = { 0 };
990 MSG NewMsg = { 0 };
991 PKBDTABLES pKbdTbl;
992 PWND pWnd;
993 LARGE_INTEGER LargeTickCount;
994 BOOL bResult = FALSE;
995
996 pWnd = UserGetWindowObject(lpMsg->hwnd);
997 if (!pWnd) // Must have a window!
998 {
999 ERR("No Window for Translate.\n");
1000 return FALSE;
1001 }
1002
1003 pti = pWnd->head.pti;
1004 pKbdTbl = pti->KeyboardLayout->KBTables;
1005 if (!pKbdTbl)
1006 return FALSE;
1007
1008 if (lpMsg->message != WM_KEYDOWN && lpMsg->message != WM_SYSKEYDOWN)
1009 return FALSE;
1010
1011 /* Init pt, hwnd and time msg fields */
1012 NewMsg.pt = gpsi->ptCursor;
1013 NewMsg.hwnd = lpMsg->hwnd;
1014 KeQueryTickCount(&LargeTickCount);
1015 NewMsg.time = MsqCalculateMessageTime(&LargeTickCount);
1016
1017 TRACE("Enter IntTranslateKbdMessage msg %s, vk %x\n",
1018 lpMsg->message == WM_SYSKEYDOWN ? "WM_SYSKEYDOWN" : "WM_KEYDOWN", lpMsg->wParam);
1019
1020 if (lpMsg->wParam == VK_PACKET)
1021 {
1022 NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
1023 NewMsg.wParam = HIWORD(lpMsg->lParam);
1024 NewMsg.lParam = LOWORD(lpMsg->lParam);
1025 MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY);
1026 return TRUE;
1027 }
1028
1029 cch = IntToUnicodeEx(lpMsg->wParam,
1030 HIWORD(lpMsg->lParam) & 0xFF,
1031 pti->MessageQueue->KeyState,
1032 wch,
1033 sizeof(wch) / sizeof(wch[0]),
1034 0,
1035 pKbdTbl);
1036
1037 if (cch)
1038 {
1039 if (cch > 0) /* Normal characters */
1040 NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
1041 else /* Dead character */
1042 {
1043 cch = -cch;
1044 NewMsg.message =
1045 (lpMsg->message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
1046 }
1047 NewMsg.lParam = lpMsg->lParam;
1048
1049 /* Send all characters */
1050 for (i = 0; i < cch; ++i)
1051 {
1052 TRACE("Msg: %x '%lc' (%04x) %08x\n", NewMsg.message, wch[i], wch[i], NewMsg.lParam);
1053 NewMsg.wParam = wch[i];
1054 MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY);
1055 }
1056 bResult = TRUE;
1057 }
1058
1059 TRACE("Leave IntTranslateKbdMessage ret %u, cch %d, msg %x, wch %x\n",
1060 bResult, cch, NewMsg.message, NewMsg.wParam);
1061 return bResult;
1062 }
1063
1064 /*
1065 * Map a virtual key code, or virtual scan code, to a scan code, key code,
1066 * or unshifted unicode character.
1067 *
1068 * Code: See Below
1069 * Type:
1070 * 0 -- Code is a virtual key code that is converted into a virtual scan code
1071 * that does not distinguish between left and right shift keys.
1072 * 1 -- Code is a virtual scan code that is converted into a virtual key code
1073 * that does not distinguish between left and right shift keys.
1074 * 2 -- Code is a virtual key code that is converted into an unshifted unicode
1075 * character.
1076 * 3 -- Code is a virtual scan code that is converted into a virtual key code
1077 * that distinguishes left and right shift keys.
1078 * KeyLayout: Keyboard layout handle
1079 *
1080 * @implemented
1081 */
1082 static UINT
1083 IntMapVirtualKeyEx(UINT uCode, UINT Type, PKBDTABLES pKbdTbl)
1084 {
1085 UINT uRet = 0;
1086
1087 switch (Type)
1088 {
1089 case MAPVK_VK_TO_VSC:
1090 uCode = IntFixVk(uCode, FALSE);
1091 uRet = IntVkToVsc(uCode, pKbdTbl);
1092 if (uRet > 0xFF) // fail for scancodes with prefix (e0, e1)
1093 uRet = 0;
1094 break;
1095
1096 case MAPVK_VSC_TO_VK:
1097 uRet = IntVscToVk(uCode, pKbdTbl) & 0xFF;
1098 uRet = IntSimplifyVk(uRet);
1099 break;
1100
1101 case MAPVK_VK_TO_CHAR:
1102 uRet = (UINT)IntVkToChar(uCode, pKbdTbl);
1103 break;
1104
1105 case MAPVK_VSC_TO_VK_EX:
1106 uRet = IntVscToVk(uCode, pKbdTbl) & 0xFF;
1107 break;
1108
1109 case MAPVK_VK_TO_VSC_EX:
1110 uRet = IntVkToVsc(uCode, pKbdTbl);
1111 break;
1112
1113 default:
1114 EngSetLastError(ERROR_INVALID_PARAMETER);
1115 ERR("Wrong type value: %u\n", Type);
1116 }
1117
1118 return uRet;
1119 }
1120
1121 /*
1122 * NtUserMapVirtualKeyEx
1123 *
1124 * Map a virtual key code, or virtual scan code, to a scan code, key code,
1125 * or unshifted unicode character. See IntMapVirtualKeyEx.
1126 */
1127 UINT
1128 APIENTRY
1129 NtUserMapVirtualKeyEx(UINT uCode, UINT uType, DWORD keyboardId, HKL dwhkl)
1130 {
1131 PKBDTABLES pKbdTbl = NULL;
1132 DECLARE_RETURN(UINT);
1133
1134 TRACE("Enter NtUserMapVirtualKeyEx\n");
1135 UserEnterExclusive();
1136
1137 if (!dwhkl)
1138 {
1139 PTHREADINFO pti;
1140
1141 pti = PsGetCurrentThreadWin32Thread();
1142 if (pti && pti->KeyboardLayout)
1143 pKbdTbl = pti->KeyboardLayout->KBTables;
1144 }
1145 else
1146 {
1147 PKBL pKbl;
1148
1149 pKbl = UserHklToKbl(dwhkl);
1150 if (pKbl)
1151 pKbdTbl = pKbl->KBTables;
1152 }
1153
1154 if (!pKbdTbl)
1155 RETURN(0);
1156
1157 RETURN(IntMapVirtualKeyEx(uCode, uType, pKbdTbl));
1158
1159 CLEANUP:
1160 TRACE("Leave NtUserMapVirtualKeyEx, ret=%i\n", _ret_);
1161 UserLeave();
1162 END_CLEANUP;
1163 }
1164
1165 /*
1166 * NtUserToUnicodeEx
1167 *
1168 * Translates virtual key to characters
1169 */
1170 int
1171 APIENTRY
1172 NtUserToUnicodeEx(
1173 UINT wVirtKey,
1174 UINT wScanCode,
1175 PBYTE pKeyStateUnsafe,
1176 LPWSTR pwszBuffUnsafe,
1177 int cchBuff,
1178 UINT wFlags,
1179 HKL dwhkl)
1180 {
1181 PTHREADINFO pti;
1182 BYTE KeyState[0x100];
1183 PWCHAR pwszBuff = NULL;
1184 int iRet = 0;
1185 PKBL pKbl = NULL;
1186 DECLARE_RETURN(int);
1187
1188 TRACE("Enter NtUserSetKeyboardState\n");
1189 UserEnterShared();
1190
1191 /* Key up? */
1192 if (wScanCode & SC_KEY_UP)
1193 {
1194 RETURN(0);
1195 }
1196
1197 if (!NT_SUCCESS(MmCopyFromCaller(KeyState,
1198 pKeyStateUnsafe,
1199 sizeof(KeyState))))
1200 {
1201 ERR("Couldn't copy key state from caller.\n");
1202 RETURN(0);
1203 }
1204
1205 /* Virtual code is correct? */
1206 if (wVirtKey < 0x100)
1207 {
1208 pwszBuff = ExAllocatePoolWithTag(NonPagedPool, sizeof(WCHAR) * cchBuff, TAG_STRING);
1209 if (!pwszBuff)
1210 {
1211 ERR("ExAllocatePoolWithTag(%d) failed\n", sizeof(WCHAR) * cchBuff);
1212 RETURN(0);
1213 }
1214 RtlZeroMemory(pwszBuff, sizeof(WCHAR) * cchBuff);
1215
1216 if (dwhkl)
1217 pKbl = UserHklToKbl(dwhkl);
1218
1219 if (!pKbl)
1220 {
1221 pti = PsGetCurrentThreadWin32Thread();
1222 pKbl = pti->KeyboardLayout;
1223 }
1224
1225 iRet = IntToUnicodeEx(wVirtKey,
1226 wScanCode,
1227 KeyState,
1228 pwszBuff,
1229 cchBuff,
1230 wFlags,
1231 pKbl ? pKbl->KBTables : NULL);
1232
1233 MmCopyToCaller(pwszBuffUnsafe, pwszBuff, cchBuff * sizeof(WCHAR));
1234 ExFreePoolWithTag(pwszBuff, TAG_STRING);
1235 }
1236
1237 RETURN(iRet);
1238
1239 CLEANUP:
1240 TRACE("Leave NtUserSetKeyboardState, ret=%i\n", _ret_);
1241 UserLeave();
1242 END_CLEANUP;
1243 }
1244
1245 /*
1246 * NtUserGetKeyNameText
1247 *
1248 * Gets key name from keyboard layout
1249 */
1250 DWORD
1251 APIENTRY
1252 NtUserGetKeyNameText(LONG lParam, LPWSTR lpString, int cchSize)
1253 {
1254 PTHREADINFO pti;
1255 DWORD i, cchKeyName, dwRet = 0;
1256 WORD wScanCode = (lParam >> 16) & 0xFF;
1257 BOOL bExtKey = (lParam & LP_EXT_BIT) ? TRUE : FALSE;
1258 PKBDTABLES pKbdTbl;
1259 VSC_LPWSTR *pKeyNames = NULL;
1260 CONST WCHAR *pKeyName = NULL;
1261 WCHAR KeyNameBuf[2];
1262 DECLARE_RETURN(DWORD);
1263
1264 TRACE("Enter NtUserGetKeyNameText\n");
1265 UserEnterShared();
1266
1267 /* Get current keyboard layout */
1268 pti = PsGetCurrentThreadWin32Thread();
1269 pKbdTbl = pti ? pti->KeyboardLayout->KBTables : 0;
1270
1271 if (!pKbdTbl || cchSize < 1)
1272 RETURN(0);
1273
1274 /* "Do not care" flag */
1275 if(lParam & LP_DO_NOT_CARE_BIT)
1276 {
1277 /* Note: we could do vsc -> vk -> vsc conversion, instead of using
1278 hardcoded scan codes, but it's not what Windows does */
1279 if (wScanCode == SCANCODE_RSHIFT && !bExtKey)
1280 wScanCode = SCANCODE_LSHIFT;
1281 else if (wScanCode == SCANCODE_CTRL || wScanCode == SCANCODE_ALT)
1282 bExtKey = FALSE;
1283 }
1284
1285 if (bExtKey)
1286 pKeyNames = pKbdTbl->pKeyNamesExt;
1287 else
1288 pKeyNames = pKbdTbl->pKeyNames;
1289
1290 for (i = 0; pKeyNames[i].pwsz; i++)
1291 {
1292 if (pKeyNames[i].vsc == wScanCode)
1293 {
1294 pKeyName = pKeyNames[i].pwsz;
1295 break;
1296 }
1297 }
1298
1299 if (!pKeyName)
1300 {
1301 WORD wVk = IntVscToVk(wScanCode, pKbdTbl);
1302
1303 if (wVk)
1304 {
1305 KeyNameBuf[0] = IntVkToChar(wVk, pKbdTbl);
1306 KeyNameBuf[1] = 0;
1307 if (KeyNameBuf[0])
1308 pKeyName = KeyNameBuf;
1309 }
1310 }
1311
1312 if (pKeyName)
1313 {
1314 cchKeyName = wcslen(pKeyName);
1315 if (cchKeyName > cchSize - 1)
1316 cchKeyName = cchSize - 1; // don't count '\0'
1317
1318 _SEH2_TRY
1319 {
1320 ProbeForWrite(lpString, (cchKeyName + 1) * sizeof(WCHAR), 1);
1321 RtlCopyMemory(lpString, pKeyName, cchKeyName * sizeof(WCHAR));
1322 lpString[cchKeyName] = UNICODE_NULL;
1323 dwRet = cchKeyName;
1324 }
1325 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1326 {
1327 SetLastNtError(_SEH2_GetExceptionCode());
1328 }
1329 _SEH2_END;
1330 }
1331 else
1332 {
1333 EngSetLastError(ERROR_INVALID_PARAMETER);
1334 }
1335
1336 RETURN(dwRet);
1337
1338 CLEANUP:
1339 TRACE("Leave NtUserGetKeyNameText, ret=%i\n", _ret_);
1340 UserLeave();
1341 END_CLEANUP;
1342 }
1343
1344 /*
1345 * UserGetKeyboardType
1346 *
1347 * Returns some keyboard specific information
1348 */
1349 DWORD FASTCALL
1350 UserGetKeyboardType(
1351 DWORD dwTypeFlag)
1352 {
1353 switch (dwTypeFlag)
1354 {
1355 case 0: /* Keyboard type */
1356 return 4; /* AT-101 */
1357 case 1: /* Keyboard Subtype */
1358 return 0; /* There are no defined subtypes */
1359 case 2: /* Number of F-keys */
1360 return 12; /* We're doing an 101 for now, so return 12 F-keys */
1361 default:
1362 ERR("Unknown type!\n");
1363 return 0; /* Note: we don't have to set last error here */
1364 }
1365 }
1366
1367 /*
1368 * NtUserVkKeyScanEx
1369 *
1370 * Based on IntTranslateChar, instead of processing VirtualKey match,
1371 * look for wChar match.
1372 */
1373 DWORD
1374 APIENTRY
1375 NtUserVkKeyScanEx(
1376 WCHAR wch,
1377 HKL dwhkl,
1378 BOOL bUsehKL)
1379 {
1380 PKBDTABLES pKbdTbl;
1381 PVK_TO_WCHAR_TABLE pVkToWchTbl;
1382 PVK_TO_WCHARS10 pVkToWch;
1383 PKBL pKbl = NULL;
1384 DWORD i, dwModBits = 0, dwModNumber = 0, Ret = (DWORD)-1;
1385
1386 TRACE("NtUserVkKeyScanEx() wch %d, KbdLayout 0x%p\n", wch, dwhkl);
1387 UserEnterShared();
1388
1389 if (bUsehKL)
1390 {
1391 // Use given keyboard layout
1392 if (dwhkl)
1393 pKbl = UserHklToKbl(dwhkl);
1394 }
1395 else
1396 {
1397 // Use thread keyboard layout
1398 pKbl = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->KeyboardLayout;
1399 }
1400
1401 if (!pKbl)
1402 goto Exit;
1403
1404 pKbdTbl = pKbl->KBTables;
1405
1406 // Interate through all VkToWchar tables while pVkToWchars is not NULL
1407 for (i = 0; pKbdTbl->pVkToWcharTable[i].pVkToWchars; i++)
1408 {
1409 pVkToWchTbl = &pKbdTbl->pVkToWcharTable[i];
1410 pVkToWch = (PVK_TO_WCHARS10)(pVkToWchTbl->pVkToWchars);
1411
1412 // Interate through all virtual keys
1413 while (pVkToWch->VirtualKey)
1414 {
1415 for (dwModNumber = 0; dwModNumber < pVkToWchTbl->nModifications; dwModNumber++)
1416 {
1417 if (pVkToWch->wch[dwModNumber] == wch)
1418 {
1419 dwModBits = pKbdTbl->pCharModifiers->ModNumber[dwModNumber];
1420 TRACE("i %d wC %04x: dwModBits %08x dwModNumber %08x MaxModBits %08x\n",
1421 i, wch, dwModBits, dwModNumber, pKbdTbl->pCharModifiers->wMaxModBits);
1422 Ret = (dwModBits << 8) | (pVkToWch->VirtualKey & 0xFF);
1423 goto Exit;
1424 }
1425 }
1426 pVkToWch = (PVK_TO_WCHARS10)(((BYTE *)pVkToWch) + pVkToWchTbl->cbSize);
1427 }
1428 }
1429 Exit:
1430 UserLeave();
1431 return Ret;
1432 }
1433
1434 /*
1435 * UserGetMouseButtonsState
1436 *
1437 * Returns bitfield used in mouse messages
1438 */
1439 WORD FASTCALL
1440 UserGetMouseButtonsState(VOID)
1441 {
1442 WORD ret = 0;
1443
1444 if (gpsi->aiSysMet[SM_SWAPBUTTON])
1445 {
1446 if (gKeyStateTable[VK_RBUTTON] & KS_DOWN_BIT) ret |= MK_LBUTTON;
1447 if (gKeyStateTable[VK_LBUTTON] & KS_DOWN_BIT) ret |= MK_RBUTTON;
1448 }
1449 else
1450 {
1451 if (gKeyStateTable[VK_LBUTTON] & KS_DOWN_BIT) ret |= MK_LBUTTON;
1452 if (gKeyStateTable[VK_RBUTTON] & KS_DOWN_BIT) ret |= MK_RBUTTON;
1453 }
1454 if (gKeyStateTable[VK_MBUTTON] & KS_DOWN_BIT) ret |= MK_MBUTTON;
1455 if (gKeyStateTable[VK_SHIFT] & KS_DOWN_BIT) ret |= MK_SHIFT;
1456 if (gKeyStateTable[VK_CONTROL] & KS_DOWN_BIT) ret |= MK_CONTROL;
1457 if (gKeyStateTable[VK_XBUTTON1] & KS_DOWN_BIT) ret |= MK_XBUTTON1;
1458 if (gKeyStateTable[VK_XBUTTON2] & KS_DOWN_BIT) ret |= MK_XBUTTON2;
1459 return ret;
1460 }
1461
1462 /* EOF */