[WIN32K]
[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 gafAsyncKeyState[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(&gafAsyncKeyState, sizeof(gafAsyncKeyState));
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 (gafAsyncKeyState[dwKey] & KS_DOWN_BIT)
640 dwRet |= 0xFFFF8000; // If down, windows returns 0xFFFF8000.
641 if (gafAsyncKeyState[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 = gafAsyncKeyState[wSimpleVk];
787
788 /* Update global keyboard state. Begin from lock bit */
789 if (!bKeyUp && !(PrevKeyState & KS_DOWN_BIT))
790 gafAsyncKeyState[wVk] ^= KS_LOCK_BIT;
791
792 /* Update down bit */
793 if (bKeyUp)
794 gafAsyncKeyState[wVk] &= ~KS_DOWN_BIT;
795 else
796 gafAsyncKeyState[wVk] |= KS_DOWN_BIT;
797
798 /* Update key without shifts */
799 gafAsyncKeyState[wSimpleVk] = gafAsyncKeyState[wVk] | gafAsyncKeyState[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 gafAsyncKeyState[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 && !(gafAsyncKeyState[VK_CONTROL] & KS_DOWN_BIT))
822 co_IntKeyboardSendAltKeyMsg();
823 }
824
825 /* Check if it is a hotkey */
826 fModifiers = IntGetModifiers(gafAsyncKeyState);
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 ((gafAsyncKeyState[wSysKey] & KS_DOWN_BIT) && // FIXME
852 !(gafAsyncKeyState[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 (gafAsyncKeyState[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) && (gafAsyncKeyState[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 if (pWnd->Unicode)
1054 NewMsg.wParam = wch[i];
1055 else
1056 {
1057 CHAR ch;
1058 if (!NT_SUCCESS(RtlUnicodeToMultiByteN(&ch, sizeof(ch), NULL, &wch[i], sizeof(wch[i]))))
1059 WARN("RtlUnicodeToMultiByteN failed!\n");
1060 NewMsg.wParam = ch;
1061 }
1062 MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY);
1063 }
1064 bResult = TRUE;
1065 }
1066
1067 TRACE("Leave IntTranslateKbdMessage ret %u, cch %d, msg %x, wch %x\n",
1068 bResult, cch, NewMsg.message, NewMsg.wParam);
1069 return bResult;
1070 }
1071
1072 /*
1073 * Map a virtual key code, or virtual scan code, to a scan code, key code,
1074 * or unshifted unicode character.
1075 *
1076 * Code: See Below
1077 * Type:
1078 * 0 -- Code is a virtual key code that is converted into a virtual scan code
1079 * that does not distinguish between left and right shift keys.
1080 * 1 -- Code is a virtual scan code that is converted into a virtual key code
1081 * that does not distinguish between left and right shift keys.
1082 * 2 -- Code is a virtual key code that is converted into an unshifted unicode
1083 * character.
1084 * 3 -- Code is a virtual scan code that is converted into a virtual key code
1085 * that distinguishes left and right shift keys.
1086 * KeyLayout: Keyboard layout handle
1087 *
1088 * @implemented
1089 */
1090 static UINT
1091 IntMapVirtualKeyEx(UINT uCode, UINT Type, PKBDTABLES pKbdTbl)
1092 {
1093 UINT uRet = 0;
1094
1095 switch (Type)
1096 {
1097 case MAPVK_VK_TO_VSC:
1098 uCode = IntFixVk(uCode, FALSE);
1099 uRet = IntVkToVsc(uCode, pKbdTbl);
1100 if (uRet > 0xFF) // fail for scancodes with prefix (e0, e1)
1101 uRet = 0;
1102 break;
1103
1104 case MAPVK_VSC_TO_VK:
1105 uRet = IntVscToVk(uCode, pKbdTbl) & 0xFF;
1106 uRet = IntSimplifyVk(uRet);
1107 break;
1108
1109 case MAPVK_VK_TO_CHAR:
1110 uRet = (UINT)IntVkToChar(uCode, pKbdTbl);
1111 break;
1112
1113 case MAPVK_VSC_TO_VK_EX:
1114 uRet = IntVscToVk(uCode, pKbdTbl) & 0xFF;
1115 break;
1116
1117 case MAPVK_VK_TO_VSC_EX:
1118 uRet = IntVkToVsc(uCode, pKbdTbl);
1119 break;
1120
1121 default:
1122 EngSetLastError(ERROR_INVALID_PARAMETER);
1123 ERR("Wrong type value: %u\n", Type);
1124 }
1125
1126 return uRet;
1127 }
1128
1129 /*
1130 * NtUserMapVirtualKeyEx
1131 *
1132 * Map a virtual key code, or virtual scan code, to a scan code, key code,
1133 * or unshifted unicode character. See IntMapVirtualKeyEx.
1134 */
1135 UINT
1136 APIENTRY
1137 NtUserMapVirtualKeyEx(UINT uCode, UINT uType, DWORD keyboardId, HKL dwhkl)
1138 {
1139 PKBDTABLES pKbdTbl = NULL;
1140 DECLARE_RETURN(UINT);
1141
1142 TRACE("Enter NtUserMapVirtualKeyEx\n");
1143 UserEnterExclusive();
1144
1145 if (!dwhkl)
1146 {
1147 PTHREADINFO pti;
1148
1149 pti = PsGetCurrentThreadWin32Thread();
1150 if (pti && pti->KeyboardLayout)
1151 pKbdTbl = pti->KeyboardLayout->KBTables;
1152 }
1153 else
1154 {
1155 PKBL pKbl;
1156
1157 pKbl = UserHklToKbl(dwhkl);
1158 if (pKbl)
1159 pKbdTbl = pKbl->KBTables;
1160 }
1161
1162 if (!pKbdTbl)
1163 RETURN(0);
1164
1165 RETURN(IntMapVirtualKeyEx(uCode, uType, pKbdTbl));
1166
1167 CLEANUP:
1168 TRACE("Leave NtUserMapVirtualKeyEx, ret=%i\n", _ret_);
1169 UserLeave();
1170 END_CLEANUP;
1171 }
1172
1173 /*
1174 * NtUserToUnicodeEx
1175 *
1176 * Translates virtual key to characters
1177 */
1178 int
1179 APIENTRY
1180 NtUserToUnicodeEx(
1181 UINT wVirtKey,
1182 UINT wScanCode,
1183 PBYTE pKeyStateUnsafe,
1184 LPWSTR pwszBuffUnsafe,
1185 int cchBuff,
1186 UINT wFlags,
1187 HKL dwhkl)
1188 {
1189 PTHREADINFO pti;
1190 BYTE KeyState[0x100];
1191 PWCHAR pwszBuff = NULL;
1192 int iRet = 0;
1193 PKBL pKbl = NULL;
1194 DECLARE_RETURN(int);
1195
1196 TRACE("Enter NtUserSetKeyboardState\n");
1197 UserEnterShared();
1198
1199 /* Key up? */
1200 if (wScanCode & SC_KEY_UP)
1201 {
1202 RETURN(0);
1203 }
1204
1205 if (!NT_SUCCESS(MmCopyFromCaller(KeyState,
1206 pKeyStateUnsafe,
1207 sizeof(KeyState))))
1208 {
1209 ERR("Couldn't copy key state from caller.\n");
1210 RETURN(0);
1211 }
1212
1213 /* Virtual code is correct? */
1214 if (wVirtKey < 0x100)
1215 {
1216 pwszBuff = ExAllocatePoolWithTag(NonPagedPool, sizeof(WCHAR) * cchBuff, TAG_STRING);
1217 if (!pwszBuff)
1218 {
1219 ERR("ExAllocatePoolWithTag(%d) failed\n", sizeof(WCHAR) * cchBuff);
1220 RETURN(0);
1221 }
1222 RtlZeroMemory(pwszBuff, sizeof(WCHAR) * cchBuff);
1223
1224 if (dwhkl)
1225 pKbl = UserHklToKbl(dwhkl);
1226
1227 if (!pKbl)
1228 {
1229 pti = PsGetCurrentThreadWin32Thread();
1230 pKbl = pti->KeyboardLayout;
1231 }
1232
1233 iRet = IntToUnicodeEx(wVirtKey,
1234 wScanCode,
1235 KeyState,
1236 pwszBuff,
1237 cchBuff,
1238 wFlags,
1239 pKbl ? pKbl->KBTables : NULL);
1240
1241 MmCopyToCaller(pwszBuffUnsafe, pwszBuff, cchBuff * sizeof(WCHAR));
1242 ExFreePoolWithTag(pwszBuff, TAG_STRING);
1243 }
1244
1245 RETURN(iRet);
1246
1247 CLEANUP:
1248 TRACE("Leave NtUserSetKeyboardState, ret=%i\n", _ret_);
1249 UserLeave();
1250 END_CLEANUP;
1251 }
1252
1253 /*
1254 * NtUserGetKeyNameText
1255 *
1256 * Gets key name from keyboard layout
1257 */
1258 DWORD
1259 APIENTRY
1260 NtUserGetKeyNameText(LONG lParam, LPWSTR lpString, int cchSize)
1261 {
1262 PTHREADINFO pti;
1263 DWORD i, cchKeyName, dwRet = 0;
1264 WORD wScanCode = (lParam >> 16) & 0xFF;
1265 BOOL bExtKey = (lParam & LP_EXT_BIT) ? TRUE : FALSE;
1266 PKBDTABLES pKbdTbl;
1267 VSC_LPWSTR *pKeyNames = NULL;
1268 CONST WCHAR *pKeyName = NULL;
1269 WCHAR KeyNameBuf[2];
1270 DECLARE_RETURN(DWORD);
1271
1272 TRACE("Enter NtUserGetKeyNameText\n");
1273 UserEnterShared();
1274
1275 /* Get current keyboard layout */
1276 pti = PsGetCurrentThreadWin32Thread();
1277 pKbdTbl = pti ? pti->KeyboardLayout->KBTables : 0;
1278
1279 if (!pKbdTbl || cchSize < 1)
1280 RETURN(0);
1281
1282 /* "Do not care" flag */
1283 if(lParam & LP_DO_NOT_CARE_BIT)
1284 {
1285 /* Note: we could do vsc -> vk -> vsc conversion, instead of using
1286 hardcoded scan codes, but it's not what Windows does */
1287 if (wScanCode == SCANCODE_RSHIFT && !bExtKey)
1288 wScanCode = SCANCODE_LSHIFT;
1289 else if (wScanCode == SCANCODE_CTRL || wScanCode == SCANCODE_ALT)
1290 bExtKey = FALSE;
1291 }
1292
1293 if (bExtKey)
1294 pKeyNames = pKbdTbl->pKeyNamesExt;
1295 else
1296 pKeyNames = pKbdTbl->pKeyNames;
1297
1298 for (i = 0; pKeyNames[i].pwsz; i++)
1299 {
1300 if (pKeyNames[i].vsc == wScanCode)
1301 {
1302 pKeyName = pKeyNames[i].pwsz;
1303 break;
1304 }
1305 }
1306
1307 if (!pKeyName)
1308 {
1309 WORD wVk = IntVscToVk(wScanCode, pKbdTbl);
1310
1311 if (wVk)
1312 {
1313 KeyNameBuf[0] = IntVkToChar(wVk, pKbdTbl);
1314 KeyNameBuf[1] = 0;
1315 if (KeyNameBuf[0])
1316 pKeyName = KeyNameBuf;
1317 }
1318 }
1319
1320 if (pKeyName)
1321 {
1322 cchKeyName = wcslen(pKeyName);
1323 if (cchKeyName > cchSize - 1)
1324 cchKeyName = cchSize - 1; // don't count '\0'
1325
1326 _SEH2_TRY
1327 {
1328 ProbeForWrite(lpString, (cchKeyName + 1) * sizeof(WCHAR), 1);
1329 RtlCopyMemory(lpString, pKeyName, cchKeyName * sizeof(WCHAR));
1330 lpString[cchKeyName] = UNICODE_NULL;
1331 dwRet = cchKeyName;
1332 }
1333 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1334 {
1335 SetLastNtError(_SEH2_GetExceptionCode());
1336 }
1337 _SEH2_END;
1338 }
1339 else
1340 {
1341 EngSetLastError(ERROR_INVALID_PARAMETER);
1342 }
1343
1344 RETURN(dwRet);
1345
1346 CLEANUP:
1347 TRACE("Leave NtUserGetKeyNameText, ret=%i\n", _ret_);
1348 UserLeave();
1349 END_CLEANUP;
1350 }
1351
1352 /*
1353 * UserGetKeyboardType
1354 *
1355 * Returns some keyboard specific information
1356 */
1357 DWORD FASTCALL
1358 UserGetKeyboardType(
1359 DWORD dwTypeFlag)
1360 {
1361 switch (dwTypeFlag)
1362 {
1363 case 0: /* Keyboard type */
1364 return 4; /* AT-101 */
1365 case 1: /* Keyboard Subtype */
1366 return 0; /* There are no defined subtypes */
1367 case 2: /* Number of F-keys */
1368 return 12; /* We're doing an 101 for now, so return 12 F-keys */
1369 default:
1370 ERR("Unknown type!\n");
1371 return 0; /* Note: we don't have to set last error here */
1372 }
1373 }
1374
1375 /*
1376 * NtUserVkKeyScanEx
1377 *
1378 * Based on IntTranslateChar, instead of processing VirtualKey match,
1379 * look for wChar match.
1380 */
1381 DWORD
1382 APIENTRY
1383 NtUserVkKeyScanEx(
1384 WCHAR wch,
1385 HKL dwhkl,
1386 BOOL bUsehKL)
1387 {
1388 PKBDTABLES pKbdTbl;
1389 PVK_TO_WCHAR_TABLE pVkToWchTbl;
1390 PVK_TO_WCHARS10 pVkToWch;
1391 PKBL pKbl = NULL;
1392 DWORD i, dwModBits = 0, dwModNumber = 0, Ret = (DWORD)-1;
1393
1394 TRACE("NtUserVkKeyScanEx() wch %d, KbdLayout 0x%p\n", wch, dwhkl);
1395 UserEnterShared();
1396
1397 if (bUsehKL)
1398 {
1399 // Use given keyboard layout
1400 if (dwhkl)
1401 pKbl = UserHklToKbl(dwhkl);
1402 }
1403 else
1404 {
1405 // Use thread keyboard layout
1406 pKbl = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->KeyboardLayout;
1407 }
1408
1409 if (!pKbl)
1410 goto Exit;
1411
1412 pKbdTbl = pKbl->KBTables;
1413
1414 // Interate through all VkToWchar tables while pVkToWchars is not NULL
1415 for (i = 0; pKbdTbl->pVkToWcharTable[i].pVkToWchars; i++)
1416 {
1417 pVkToWchTbl = &pKbdTbl->pVkToWcharTable[i];
1418 pVkToWch = (PVK_TO_WCHARS10)(pVkToWchTbl->pVkToWchars);
1419
1420 // Interate through all virtual keys
1421 while (pVkToWch->VirtualKey)
1422 {
1423 for (dwModNumber = 0; dwModNumber < pVkToWchTbl->nModifications; dwModNumber++)
1424 {
1425 if (pVkToWch->wch[dwModNumber] == wch)
1426 {
1427 dwModBits = pKbdTbl->pCharModifiers->ModNumber[dwModNumber];
1428 TRACE("i %d wC %04x: dwModBits %08x dwModNumber %08x MaxModBits %08x\n",
1429 i, wch, dwModBits, dwModNumber, pKbdTbl->pCharModifiers->wMaxModBits);
1430 Ret = (dwModBits << 8) | (pVkToWch->VirtualKey & 0xFF);
1431 goto Exit;
1432 }
1433 }
1434 pVkToWch = (PVK_TO_WCHARS10)(((BYTE *)pVkToWch) + pVkToWchTbl->cbSize);
1435 }
1436 }
1437 Exit:
1438 UserLeave();
1439 return Ret;
1440 }
1441
1442 /*
1443 * UserGetMouseButtonsState
1444 *
1445 * Returns bitfield used in mouse messages
1446 */
1447 WORD FASTCALL
1448 UserGetMouseButtonsState(VOID)
1449 {
1450 WORD ret = 0;
1451
1452 if (gpsi->aiSysMet[SM_SWAPBUTTON])
1453 {
1454 if (gafAsyncKeyState[VK_RBUTTON] & KS_DOWN_BIT) ret |= MK_LBUTTON;
1455 if (gafAsyncKeyState[VK_LBUTTON] & KS_DOWN_BIT) ret |= MK_RBUTTON;
1456 }
1457 else
1458 {
1459 if (gafAsyncKeyState[VK_LBUTTON] & KS_DOWN_BIT) ret |= MK_LBUTTON;
1460 if (gafAsyncKeyState[VK_RBUTTON] & KS_DOWN_BIT) ret |= MK_RBUTTON;
1461 }
1462 if (gafAsyncKeyState[VK_MBUTTON] & KS_DOWN_BIT) ret |= MK_MBUTTON;
1463 if (gafAsyncKeyState[VK_SHIFT] & KS_DOWN_BIT) ret |= MK_SHIFT;
1464 if (gafAsyncKeyState[VK_CONTROL] & KS_DOWN_BIT) ret |= MK_CONTROL;
1465 if (gafAsyncKeyState[VK_XBUTTON1] & KS_DOWN_BIT) ret |= MK_XBUTTON1;
1466 if (gafAsyncKeyState[VK_XBUTTON2] & KS_DOWN_BIT) ret |= MK_XBUTTON2;
1467 return ret;
1468 }
1469
1470 /* EOF */