2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: keyboard.c,v 1.15 2003/11/24 00:22:53 arty Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
24 * FILE: subsys/win32k/ntuser/keyboard.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH Created
30 /* INCLUDES ******************************************************************/
32 #include <ddk/ntddk.h>
33 #include <win32k/win32k.h>
34 #include <internal/safe.h>
35 #include <internal/kbd.h>
36 #include <include/guicheck.h>
37 #include <include/msgqueue.h>
38 #include <include/window.h>
39 #include <include/class.h>
40 #include <include/error.h>
41 #include <include/object.h>
42 #include <include/winsta.h>
47 /* Directory to load key layouts from */
48 #define SYSTEMROOT_DIR L"\\SystemRoot\\System32\\"
50 #define CAPITAL_BIT 0x80000000
51 #define NUMLOCK_BIT 0x40000000
52 #define MOD_BITS_MASK 0x3fffffff
53 #define MOD_KCTRL 0x02
55 #define KS_DOWN_MASK 0xc0
56 #define KS_DOWN_BIT 0x80
57 #define KS_EXT_BIT 0x40
58 #define KS_LOCK_BIT 0x01
60 #define LP_EXT_BIT (1<<24)
61 /* From kbdxx.c -- Key changes with numlock */
64 /* Lock the keyboard state to prevent unusual concurrent access */
65 KSPIN_LOCK QueueStateLock
;
67 BYTE QueueKeyStateTable
[256];
69 /* FUNCTIONS *****************************************************************/
71 /* Initialization -- Right now, just zero the key state and init the lock */
72 NTSTATUS FASTCALL
InitKeyboardImpl(VOID
) {
73 KeInitializeSpinLock(&QueueStateLock
);
74 RtlZeroMemory(&QueueKeyStateTable
,0x100);
75 return STATUS_SUCCESS
;
78 /*** Statics used by TranslateMessage ***/
80 static UINT
DontDistinguishShifts( UINT ret
) {
81 if( ret
== VK_LSHIFT
|| ret
== VK_RSHIFT
) ret
= VK_SHIFT
;
82 if( ret
== VK_LCONTROL
|| ret
== VK_RCONTROL
) ret
= VK_CONTROL
;
83 if( ret
== VK_LMENU
|| ret
== VK_RMENU
) ret
= VK_MENU
;
87 static VOID STDCALL
SetKeyState(DWORD key
, DWORD vk
, DWORD ext
, BOOL down
) {
88 /* Special handling for toggles like numpad and caps lock */
89 if (vk
== VK_CAPITAL
|| vk
== VK_NUMLOCK
)
91 if (down
) QueueKeyStateTable
[key
] ^= 1;
95 QueueKeyStateTable
[key
] |= KS_DOWN_BIT
| (ext
? KS_EXT_BIT
: 0);
97 QueueKeyStateTable
[key
] &= ~KS_DOWN_MASK
;
100 VOID
DumpKeyState( PBYTE KeyState
) {
103 DbgPrint( "KeyState { " );
104 for( i
= 0; i
< 0x100; i
++ ) {
105 if( KeyState
[i
] ) DbgPrint( "%02x(%02x) ", i
, KeyState
[i
] );
110 static BYTE
KeysSet( PKBDTABLES pkKT
, PBYTE KeyState
,
111 int Mod
, int FakeModLeft
, int FakeModRight
) {
115 if( !KeyState
|| !pkKT
) return 0;
117 for( i
= 0; i
< pkKT
->bMaxVSCtoVK
; i
++ ) {
118 Vk
= pkKT
->pusVSCtoVK
[i
] & 0xff;
121 (FakeModLeft
&& Vk
== FakeModLeft
) ||
122 (FakeModRight
&& Vk
== FakeModRight
)) ) {
130 static DWORD
ModBits( PKBDTABLES pkKT
, PBYTE KeyState
) {
135 if( !KeyState
) return 0;
137 /* DumpKeyState( KeyState ); */
139 for( i
= 0; pkKT
->pCharModifiers
->pVkToBit
[i
].Vk
; i
++ ) {
140 int Vk
= pkKT
->pCharModifiers
->pVkToBit
[i
].Vk
;
144 Mask
= KeysSet( pkKT
, KeyState
, Vk
, VK_LSHIFT
, VK_RSHIFT
);
145 if (Mask
& KS_DOWN_MASK
)
146 ModBits
|= pkKT
->pCharModifiers
->pVkToBit
[i
].ModBits
;
149 Mask
= KeysSet( pkKT
, KeyState
, Vk
, VK_LCONTROL
, VK_RCONTROL
);
150 if (Mask
& KS_DOWN_MASK
)
151 ModBits
|= pkKT
->pCharModifiers
->pVkToBit
[i
].ModBits
;
154 Mask
= KeysSet( pkKT
, KeyState
, Vk
, VK_LMENU
, VK_RMENU
);
155 if (Mask
& KS_DOWN_MASK
)
156 ModBits
|= pkKT
->pCharModifiers
->pVkToBit
[i
].ModBits
;
157 if (Mask
& KS_EXT_BIT
)
158 ModBits
|= MOD_KCTRL
;
161 Mask
= KeysSet( pkKT
, KeyState
, Vk
, 0, 0 );
162 if (Mask
& KS_DOWN_BIT
)
163 ModBits
|= pkKT
->pCharModifiers
->pVkToBit
[i
].ModBits
;
168 /* Deal with VK_CAPITAL */
169 if (KeysSet( pkKT
, KeyState
, VK_CAPITAL
, 0, 0 ) & KS_LOCK_BIT
)
171 ModBits
|= CAPITAL_BIT
;
174 /* Deal with VK_NUMLOCK */
175 if (KeysSet( pkKT
, KeyState
, VK_NUMLOCK
, 0, 0 ) & KS_LOCK_BIT
)
177 ModBits
|= NUMLOCK_BIT
;
180 DPRINT( "Current Mod Bits: %x\n", ModBits
);
185 static BOOL
TryToTranslateChar(WORD wVirtKey
,
189 PWCHAR pwcTranslatedChar
,
190 PKBDTABLES keyLayout
)
192 PVK_TO_WCHAR_TABLE vtwTbl
;
193 PVK_TO_WCHARS10 vkPtr
;
194 size_t size_this_entry
;
196 DWORD CapsMod
= 0, CapsState
= 0;
198 CapsState
= ModBits
& ~MOD_BITS_MASK
;
199 ModBits
= ModBits
& MOD_BITS_MASK
;
201 DPRINT ( "TryToTranslate: %04x %x\n", wVirtKey
, ModBits
);
203 if (ModBits
> keyLayout
->pCharModifiers
->wMaxModBits
)
207 shift
= keyLayout
->pCharModifiers
->ModNumber
[ModBits
];
209 for (nMod
= 0; keyLayout
->pVkToWcharTable
[nMod
].nModifications
; nMod
++)
211 if (shift
> keyLayout
->pVkToWcharTable
[nMod
].nModifications
)
215 vtwTbl
= &keyLayout
->pVkToWcharTable
[nMod
];
216 size_this_entry
= vtwTbl
->cbSize
;
217 vkPtr
= (PVK_TO_WCHARS10
)((BYTE
*)vtwTbl
->pVkToWchars
);
218 while(vkPtr
->VirtualKey
)
220 if( wVirtKey
== (vkPtr
->VirtualKey
& 0xff) )
223 shift
| ((CapsState
& CAPITAL_BIT
) ? vkPtr
->Attributes
: 0);
225 *pbDead
= vkPtr
->wch
[CapsMod
] == WCH_DEAD
;
226 *pbLigature
= vkPtr
->wch
[CapsMod
] == WCH_LGTR
;
227 *pwcTranslatedChar
= vkPtr
->wch
[CapsMod
];
229 DPRINT("CapsMod %08x CapsState %08x shift %08x Char %04x\n",
230 CapsMod
, CapsState
, shift
, *pwcTranslatedChar
);
234 vkPtr
= (PVK_TO_WCHARS10
)(((BYTE
*)vkPtr
) + size_this_entry
);
235 if( vkPtr
->VirtualKey
!= 0xff )
237 DPRINT( "Found dead key with no trailer in the table.\n" );
238 DPRINT( "VK: %04x, ADDR: %08x\n", wVirtKey
, (int)vkPtr
);
241 *pwcTranslatedChar
= vkPtr
->wch
[shift
];
245 vkPtr
= (PVK_TO_WCHARS10
)(((BYTE
*)vkPtr
) + size_this_entry
);
253 ToUnicodeInner(UINT wVirtKey
,
261 WCHAR wcTranslatedChar
;
265 if( !pkKT
) return 0;
267 if( TryToTranslateChar( wVirtKey
,
268 ModBits( pkKT
, lpKeyState
),
276 DPRINT("Not handling ligature (yet)\n" );
280 if( cchBuff
> 0 ) pwszBuff
[0] = wcTranslatedChar
;
282 return bDead
? -1 : 1;
296 KeAcquireSpinLock(&QueueStateLock
, &OldIrql
);
298 ret
= ((DWORD
)(QueueKeyStateTable
[key
] & KS_DOWN_BIT
) << 8 ) |
299 (QueueKeyStateTable
[key
] & KS_EXT_BIT
) |
300 (QueueKeyStateTable
[key
] & KS_LOCK_BIT
);
302 KeReleaseSpinLock(&QueueStateLock
, OldIrql
);
306 int STDCALL
ToUnicodeEx( UINT wVirtKey
,
314 int ToUnicodeResult
= 0;
316 KeAcquireSpinLock(&QueueStateLock
, &OldIrql
);
317 ToUnicodeResult
= ToUnicodeInner( wVirtKey
,
324 PsGetWin32Thread()->KeyboardLayout
: 0 );
325 KeReleaseSpinLock(&QueueStateLock
, OldIrql
);
327 return ToUnicodeResult
;
330 int STDCALL
ToUnicode( UINT wVirtKey
,
336 return ToUnicodeEx( wVirtKey
,
346 * Utility to copy and append two unicode strings.
348 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
349 * IN PUNICODE_STRING Second -> Second string to append
350 * IN BOOL Deallocate -> TRUE: Deallocate First string before
356 static NTSTATUS
ReallyAppendUnicodeString(PUNICODE_STRING ResultFirst
,
357 PUNICODE_STRING Second
,
361 ExAllocatePool(PagedPool
,
362 (ResultFirst
->Length
+ Second
->Length
+ sizeof(WCHAR
)));
364 return STATUS_NO_MEMORY
;
366 memcpy( new_string
, ResultFirst
->Buffer
,
367 ResultFirst
->Length
);
368 memcpy( new_string
+ ResultFirst
->Length
/ sizeof(WCHAR
),
371 if( Deallocate
) RtlFreeUnicodeString(ResultFirst
);
372 ResultFirst
->Length
+= Second
->Length
;
373 ResultFirst
->MaximumLength
= ResultFirst
->Length
;
374 new_string
[ResultFirst
->Length
/ sizeof(WCHAR
)] = 0;
375 Status
= RtlCreateUnicodeString(ResultFirst
,new_string
) ?
376 STATUS_SUCCESS
: STATUS_NO_MEMORY
;
377 ExFreePool(new_string
);
382 * Utility function to read a value from the registry more easily.
384 * IN PUNICODE_STRING KeyName -> Name of key to open
385 * IN PUNICODE_STRING ValueName -> Name of value to open
386 * OUT PUNICODE_STRING ReturnedValue -> String contained in registry
391 static NTSTATUS
ReadRegistryValue( PUNICODE_STRING KeyName
,
392 PUNICODE_STRING ValueName
,
393 PUNICODE_STRING ReturnedValue
) {
396 OBJECT_ATTRIBUTES KeyAttributes
;
397 PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo
;
402 InitializeObjectAttributes(&KeyAttributes
, KeyName
, OBJ_CASE_INSENSITIVE
,
404 Status
= ZwOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &KeyAttributes
);
405 if( !NT_SUCCESS(Status
) ) {
409 Status
= ZwQueryValueKey(KeyHandle
, ValueName
, KeyValuePartialInformation
,
414 if( Status
!= STATUS_BUFFER_TOO_SMALL
) {
419 ResLength
+= sizeof( *KeyValuePartialInfo
);
420 KeyValuePartialInfo
=
421 ExAllocatePool(PagedPool
, ResLength
);
424 if( !KeyValuePartialInfo
) {
426 return STATUS_NO_MEMORY
;
429 Status
= ZwQueryValueKey(KeyHandle
, ValueName
, KeyValuePartialInformation
,
430 (PVOID
)KeyValuePartialInfo
,
434 if( !NT_SUCCESS(Status
) ) {
436 ExFreePool(KeyValuePartialInfo
);
440 Temp
.Length
= Temp
.MaximumLength
= KeyValuePartialInfo
->DataLength
;
441 Temp
.Buffer
= (PWCHAR
)KeyValuePartialInfo
->Data
;
443 /* At this point, KeyValuePartialInfo->Data contains the key data */
444 RtlInitUnicodeString(ReturnedValue
,L
"");
445 ReallyAppendUnicodeString(ReturnedValue
,&Temp
,FALSE
);
447 ExFreePool(KeyValuePartialInfo
);
453 typedef PVOID (*KbdLayerDescriptor
)(VOID
);
454 NTSTATUS STDCALL
LdrGetProcedureAddress(PVOID module
,
455 PANSI_STRING import_name
,
459 void InitKbdLayout( PVOID
*pkKeyboardLayout
) {
460 UNICODE_STRING KeyName
;
461 UNICODE_STRING ValueName
;
462 UNICODE_STRING LayoutKeyName
;
463 UNICODE_STRING LayoutValueName
;
464 UNICODE_STRING DefaultLocale
;
465 UNICODE_STRING LayoutFile
;
466 UNICODE_STRING FullLayoutPath
;
467 PWCHAR KeyboardLayoutWSTR
;
468 HMODULE kbModule
= 0;
470 ANSI_STRING kbdProcedureName
;
471 KbdLayerDescriptor layerDescGetFn
;
473 #define XX_STATUS(x) if (!NT_SUCCESS(Status = (x))) continue;
476 RtlInitUnicodeString(&KeyName
,
477 L
"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet"
478 L
"\\Control\\Nls\\Locale");
479 RtlInitUnicodeString(&ValueName
,
482 DPRINT("KeyName = %wZ, ValueName = %wZ\n", &KeyName
, &ValueName
);
484 Status
= ReadRegistryValue(&KeyName
,&ValueName
,&DefaultLocale
);
486 if( !NT_SUCCESS(Status
) ) {
487 DbgPrint( "Could not get default locale (%08x).\n", Status
);
489 DPRINT( "DefaultLocale = %wZ\n", &DefaultLocale
);
491 RtlInitUnicodeString(&LayoutKeyName
,
492 L
"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet"
493 L
"\\Control\\KeyboardLayouts\\");
495 ReallyAppendUnicodeString(&LayoutKeyName
,&DefaultLocale
,FALSE
);
497 RtlFreeUnicodeString(&DefaultLocale
);
498 RtlInitUnicodeString(&LayoutValueName
,L
"Layout File");
500 Status
= ReadRegistryValue(&LayoutKeyName
,&LayoutValueName
,&LayoutFile
);
501 RtlInitUnicodeString(&FullLayoutPath
,SYSTEMROOT_DIR
);
503 if( !NT_SUCCESS(Status
) ) {
504 DbgPrint("Got default locale but not layout file. (%08x)\n",
506 RtlFreeUnicodeString(&LayoutFile
);
508 DPRINT("Read registry and got %wZ\n", &LayoutFile
);
510 RtlFreeUnicodeString(&LayoutKeyName
);
512 ReallyAppendUnicodeString(&FullLayoutPath
,&LayoutFile
,FALSE
);
514 DPRINT("Loading Keyboard DLL %wZ\n", &FullLayoutPath
);
516 RtlFreeUnicodeString(&LayoutFile
);
518 KeyboardLayoutWSTR
= ExAllocatePool(PagedPool
,
519 (FullLayoutPath
.Length
+ 1) *
522 if( !KeyboardLayoutWSTR
) {
523 DbgPrint("Couldn't allocate a string for the keyboard layout name.\n");
524 RtlFreeUnicodeString(&FullLayoutPath
);
527 memcpy(KeyboardLayoutWSTR
,FullLayoutPath
.Buffer
,
528 (FullLayoutPath
.Length
+ 1) * sizeof(WCHAR
));
529 KeyboardLayoutWSTR
[FullLayoutPath
.Length
] = 0;
531 kbModule
= EngLoadImage(KeyboardLayoutWSTR
);
532 DPRINT( "Load Keyboard Layout: %S\n", KeyboardLayoutWSTR
);
535 DbgPrint( "Load Keyboard Layout: No %wZ\n", &FullLayoutPath
);
538 RtlFreeUnicodeString(&FullLayoutPath
);
543 DbgPrint("Trying to load US Keyboard Layout\n");
544 kbModule
= EngLoadImage(L
"\\SystemRoot\\system32\\kbdus.dll");
548 DbgPrint("Failed to load any Keyboard Layout\n");
553 RtlInitAnsiString( &kbdProcedureName
, "KbdLayerDescriptor" );
555 LdrGetProcedureAddress((PVOID
)kbModule
,
558 (PVOID
*)&layerDescGetFn
);
560 if( layerDescGetFn
) {
561 *pkKeyboardLayout
= layerDescGetFn();
565 if( !*pkKeyboardLayout
) {
566 DbgPrint("Failed to load the keyboard layout.\n");
572 PKBDTABLES
W32kGetDefaultKeyLayout() {
573 PKBDTABLES pkKeyboardLayout
= 0;
574 InitKbdLayout( (PVOID
) &pkKeyboardLayout
);
575 return pkKeyboardLayout
;
579 NtUserTranslateMessage(LPMSG lpMsg
,
580 HKL dwhkl
) /* Used to pass the kbd layout */
583 static INT dead_char
= 0;
589 PKBDTABLES keyLayout
;
593 if( !NT_SUCCESS(MmCopyFromCaller(&InMsg
, lpMsg
, sizeof(InMsg
))) ) {
597 keyLayout
= PsGetWin32Thread()->KeyboardLayout
;
601 if (InMsg
.message
!= WM_KEYDOWN
&& InMsg
.message
!= WM_SYSKEYDOWN
)
604 ScanCode
= (InMsg
.lParam
>> 16) & 0xff;
606 KeAcquireSpinLock(&QueueStateLock
, &OldIrql
);
608 UState
= ToUnicodeInner(InMsg
.wParam
, HIWORD(InMsg
.lParam
) & 0xff,
609 QueueKeyStateTable
, wp
, 2, 0,
614 NewMsg
.message
= (InMsg
.message
== WM_KEYDOWN
) ? WM_CHAR
: WM_SYSCHAR
;
619 DPRINT("PREVIOUS DEAD CHAR: %c\n", dead_char
);
621 for( i
= 0; keyLayout
->pDeadKey
[i
].dwBoth
; i
++ )
623 first
= keyLayout
->pDeadKey
[i
].dwBoth
>> 16;
624 second
= keyLayout
->pDeadKey
[i
].dwBoth
;
625 if (first
== dead_char
&& second
== wp
[0])
627 wp
[0] = keyLayout
->pDeadKey
[i
].wchComposed
;
633 DPRINT("FINAL CHAR: %c\n", wp
[0]);
637 NewMsg
.hwnd
= InMsg
.hwnd
;
638 NewMsg
.wParam
= dead_char
;
639 NewMsg
.lParam
= InMsg
.lParam
;
640 UMsg
= MsqCreateMessage(&NewMsg
);
643 MsqPostMessage(PsGetWin32Thread()->MessageQueue
, UMsg
);
646 NewMsg
.hwnd
= InMsg
.hwnd
;
647 NewMsg
.wParam
= wp
[0];
648 NewMsg
.lParam
= InMsg
.lParam
;
649 UMsg
= MsqCreateMessage(&NewMsg
);
650 DPRINT( "CHAR='%c' %04x %08x\n", wp
[0], wp
[0], InMsg
.lParam
);
652 MsqPostMessage(PsGetWin32Thread()->MessageQueue
, UMsg
);
655 else if (UState
== -1)
658 (InMsg
.message
== WM_KEYDOWN
) ? WM_DEADCHAR
: WM_SYSDEADCHAR
;
659 NewMsg
.hwnd
= InMsg
.hwnd
;
660 NewMsg
.wParam
= wp
[0];
661 NewMsg
.lParam
= InMsg
.lParam
;
663 UMsg
= MsqCreateMessage(&NewMsg
);
665 MsqPostMessage(PsGetWin32Thread()->MessageQueue
, UMsg
);
669 KeReleaseSpinLock(&QueueStateLock
, OldIrql
);
674 NtUserSetFocus(HWND hWnd
)
676 return IntSetFocusWindow(hWnd
);
681 NtUserGetKeyboardState(
687 KeAcquireSpinLock(&QueueStateLock
, &OldIrql
);
689 if(!NT_SUCCESS(MmCopyToCaller(lpKeyState
, QueueKeyStateTable
, 256)))
692 KeReleaseSpinLock(&QueueStateLock
, OldIrql
);
698 NtUserSetKeyboardState(
704 KeAcquireSpinLock(&QueueStateLock
, &OldIrql
);
706 if(! NT_SUCCESS(MmCopyFromCaller(QueueKeyStateTable
, lpKeyState
, 256)))
709 KeReleaseSpinLock(&QueueStateLock
, OldIrql
);
714 static UINT
VkToScan( UINT Code
, BOOL ExtCode
, PKBDTABLES pkKT
) {
717 for( i
= 0; i
< pkKT
->bMaxVSCtoVK
; i
++ ) {
718 if( pkKT
->pusVSCtoVK
[i
] == Code
) { return i
; }
724 UINT
ScanToVk( UINT Code
, BOOL ExtKey
, PKBDTABLES pkKT
) {
726 DPRINT("ScanToVk: No layout\n");
733 for( i
= 0; pkKT
->pVSCtoVK_E0
[i
].Vsc
; i
++ ) {
734 if( pkKT
->pVSCtoVK_E0
[i
].Vsc
== Code
)
735 return pkKT
->pVSCtoVK_E0
[i
].Vk
& 0xff;
737 for( i
= 0; pkKT
->pVSCtoVK_E1
[i
].Vsc
; i
++ ) {
738 if( pkKT
->pVSCtoVK_E1
[i
].Vsc
== Code
)
739 return pkKT
->pVSCtoVK_E1
[i
].Vk
& 0xff;
744 if( Code
>= pkKT
->bMaxVSCtoVK
) { return 0; }
745 return pkKT
->pusVSCtoVK
[Code
] & 0xff;
750 * Map a virtual key code, or virtual scan code, to a scan code, key code,
751 * or unshifted unicode character.
755 * 0 -- Code is a virtual key code that is converted into a virtual scan code
756 * that does not distinguish between left and right shift keys.
757 * 1 -- Code is a virtual scan code that is converted into a virtual key code
758 * that does not distinguish between left and right shift keys.
759 * 2 -- Code is a virtual key code that is converted into an unshifted unicode
761 * 3 -- Code is a virtual scan code that is converted into a virtual key code
762 * that distinguishes left and right shift keys.
763 * KeyLayout: Keyboard layout handle (currently, unused)
768 static UINT
IntMapVirtualKeyEx( UINT Code
, UINT Type
, PKBDTABLES keyLayout
) {
773 if( Code
== VK_RSHIFT
) Code
= VK_LSHIFT
;
774 if( Code
== VK_RMENU
) Code
= VK_LMENU
;
775 if( Code
== VK_RCONTROL
) Code
= VK_LCONTROL
;
776 ret
= VkToScan( Code
, FALSE
, keyLayout
);
781 DontDistinguishShifts
782 (IntMapVirtualKeyEx( Code
, 3, keyLayout
) );
788 ret
= VkToScan( Code
, FALSE
, keyLayout
);
789 ToUnicodeInner( Code
, ret
, 0, wp
, 2, 0, keyLayout
);
794 ret
= ScanToVk( Code
, FALSE
, keyLayout
);
803 NtUserMapVirtualKeyEx( UINT Code
, UINT Type
, DWORD keyboardId
, HKL dwhkl
) {
804 PKBDTABLES keyLayout
= PsGetWin32Thread() ?
805 PsGetWin32Thread()->KeyboardLayout
: 0;
807 if( !keyLayout
) return 0;
809 return IntMapVirtualKeyEx( Code
, Type
, keyLayout
);
823 BYTE KeyStateBuf
[0x100];
824 PWCHAR OutPwszBuff
= 0;
828 if( !NT_SUCCESS(MmCopyFromCaller(KeyStateBuf
,
830 sizeof(KeyStateBuf
))) ) {
831 DbgPrint( "Couldn't copy key state from caller.\n" );
834 OutPwszBuff
= ExAllocatePool(NonPagedPool
,sizeof(WCHAR
) * cchBuff
);
836 DbgPrint( "ExAllocatePool(%d) failed\n", sizeof(WCHAR
) * cchBuff
);
839 RtlZeroMemory( OutPwszBuff
, sizeof( WCHAR
) * cchBuff
);
841 ret
= ToUnicodeEx( wVirtKey
,
849 MmCopyToCaller(pwszBuff
,OutPwszBuff
,sizeof(WCHAR
)*cchBuff
);
850 ExFreePool(OutPwszBuff
);
855 static int W32kSimpleToupper( int ch
) {
856 if( ch
>= 'a' && ch
<= 'z' ) ch
= ch
- 'a' + 'A';
862 NtUserGetKeyNameText( LONG lParam
, LPWSTR lpString
, int nSize
) {
867 UINT ScanCode
= (lParam
>> 16) & 0xff;
868 BOOL ExtKey
= lParam
& (1<<24) ? TRUE
: FALSE
;
869 PKBDTABLES keyLayout
=
871 PsGetWin32Thread()->KeyboardLayout
: 0;
873 if( !keyLayout
|| nSize
< 1 ) return 0;
875 if( lParam
& (1<<25) ) {
876 CareVk
= VkCode
= ScanToVk( ScanCode
, ExtKey
, keyLayout
);
877 if( VkCode
== VK_LSHIFT
|| VkCode
== VK_RSHIFT
)
879 if( VkCode
== VK_LCONTROL
|| VkCode
== VK_RCONTROL
)
880 VkCode
= VK_LCONTROL
;
881 if( VkCode
== VK_LMENU
|| VkCode
== VK_RMENU
)
884 VkCode
= ScanToVk( ScanCode
, ExtKey
, keyLayout
);
887 VSC_LPWSTR
*KeyNames
= 0;
889 if( CareVk
!= VkCode
)
890 ScanCode
= VkToScan( VkCode
, ExtKey
, keyLayout
);
893 KeyNames
= keyLayout
->pKeyNamesExt
;
895 KeyNames
= keyLayout
->pKeyNames
;
897 for( i
= 0; KeyNames
[i
].pwsz
; i
++ ) {
898 if( KeyNames
[i
].vsc
== ScanCode
) {
899 UINT StrLen
= wcslen(KeyNames
[i
].pwsz
);
900 UINT StrMax
= StrLen
> (nSize
- 1) ? (nSize
- 1) : StrLen
;
902 if( NT_SUCCESS( MmCopyToCaller( lpString
,
904 StrMax
* sizeof(WCHAR
) ) ) &&
905 NT_SUCCESS( MmCopyToCaller( lpString
+ StrMax
,
907 sizeof( WCHAR
) ) ) ) {
917 UCName
[0] = W32kSimpleToupper(IntMapVirtualKeyEx( VkCode
, 2, keyLayout
));
921 if( !NT_SUCCESS(MmCopyToCaller( lpString
, UCName
, 2 * sizeof(WCHAR
) )) )
929 * Filter this message according to the current key layout, setting wParam
933 VOID FASTCALL
W32kKeyProcessMessage(LPMSG Msg
, PKBDTABLES KeyboardLayout
) {
935 DWORD ScanCode
= 0, ModifierBits
= 0;
938 static WORD NumpadConversion
[][2] =
939 { { VK_DELETE
, VK_DECIMAL
},
940 { VK_INSERT
, VK_NUMPAD0
},
941 { VK_END
, VK_NUMPAD1
},
942 { VK_DOWN
, VK_NUMPAD2
},
943 { VK_NEXT
, VK_NUMPAD3
},
944 { VK_LEFT
, VK_NUMPAD4
},
945 { VK_CLEAR
, VK_NUMPAD5
},
946 { VK_RIGHT
, VK_NUMPAD6
},
947 { VK_HOME
, VK_NUMPAD7
},
948 { VK_UP
, VK_NUMPAD8
},
949 { VK_PRIOR
, VK_NUMPAD9
},
952 if( !KeyboardLayout
|| !Msg
||
953 (Msg
->message
!= WM_KEYDOWN
&& Msg
->message
!= WM_SYSKEYDOWN
&&
954 Msg
->message
!= WM_KEYUP
&& Msg
->message
!= WM_SYSKEYUP
) )
959 KeAcquireSpinLock(&QueueStateLock
, &OldIrql
);
961 /* arty -- handle numpad -- On real windows, the actual key produced
962 * by the messaging layer is different based on the state of numlock. */
963 ModifierBits
= ModBits(KeyboardLayout
,QueueKeyStateTable
);
965 /* Get the raw scan code, so we can look up whether the key is a numpad
967 ScanCode
= (Msg
->lParam
>> 16) & 0xff;
968 Msg
->wParam
= IntMapVirtualKeyEx( ScanCode
, 1, KeyboardLayout
);
969 RawVk
= KeyboardLayout
->pusVSCtoVK
[ScanCode
];
971 if ((ModifierBits
& NUMLOCK_BIT
) && (RawVk
& KNUMP
))
973 /* The key in question is a numpad key. Search for a translation. */
974 for (i
= 0; NumpadConversion
[i
][0]; i
++)
976 if ((RawVk
& 0xff) == NumpadConversion
[i
][0])
978 Msg
->wParam
= NumpadConversion
[i
][1];
984 /* Now that we have the VK, we can set the keymap appropriately
985 * This is a better place for this code, as it's guaranteed to be
986 * run, unlike translate message. */
987 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
)
989 SetKeyState( ScanCode
, Msg
->wParam
, Msg
->lParam
& LP_EXT_BIT
,
990 TRUE
); /* Strike key */
992 else if (Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
994 SetKeyState( ScanCode
, Msg
->wParam
, Msg
->lParam
& LP_EXT_BIT
,
995 FALSE
); /* Release key */
998 KeReleaseSpinLock(&QueueStateLock
, OldIrql
);